25 декабря 2019

Показать все товары на одной странице - CS-CART

1. Инициализируем хук для модуля "my_changes"
1.1 Создаем новый файл:
app/addons/my_changes/init.php

1.2. Вставляем инициализацию хука:
<?php

if (!defined('BOOTSTRAP')) { die('Access denied'); }

fn_register_hooks(
 'get_products_pre'
);

2. Создаём функцию которая будет выполнятся в хуке 'get_products_pre' .
2.1 Создаём новый файл :
app/addons/my_changes/func.php



2.2. Вставляем нашу функцию

<?php

function fn_my_changes_get_products_pre(&$params, &$items_per_page, $lang_code)
{
   if($params['all_products'] == 'Y' && $params['dispatch'] == 'categories.view') {
     unset($params['items_per_page']);
     $items_per_page = 0;
    }
    return true;
}


3. Включаем модуль "Мои изменения" .


Теперь , когда Вы будете на странице категории, Вы можете добавить в URL параметр "all_products=Y" . Например:
http://wwww-w-www/?all_products=Y
или
http://index.php?dispatch=categories.view&category_id=281&all_products=Y

Страницы без параметра, будут открываться как обычно.

Переход на последнюю страницу в нумерации страниц (пагинации) Cs-cart

/desgign/themes/YOUR_THEME/templates/common/pagination.tpl


{if $pg != $pagination.current_page}
<a data-ca-scroll=".cm-pagination-container" href="{"`$c_url`&page=`$pagination.total_pages``$extra_url`"|fn_url}" data-ca-page="{$pagination.total_pages}"
 class="cm-history ty-pagination__item {$ajax_class}" data-ca-target-id="{$pagination.total_pages}">Last</a>
{/if}


**
/design/themes/YOUR_THEME/templates/common/pagination.tpl

**

Кнопка "Загрузить ещё" в каталоге в CS-Cart

В CS-Cart по умолчанию пагинация в каталоге товаров сделана через Ajax, но при реализации через выбор страниц в пагинации. Иногда требуется либо добавить или поменять стандартную пагинацию на кнопку «Загрузить ещё», чтобы в конец страницы подгружались ещё товары.
Сделать такое не трудно, достаточно внести изменения в тему сайта. Это можно делать либо в самой теме, либо через свой плагин или в стандартным плагином «Мои изменения».
1. В файле \views\categories\view.tpl нужно добавить свою кнопку

{hook name="categories:view"}
<div id="category_products_{$block.block_id}" class="gul-main-catalog">

<h1 class="gul-categ-head">{$category_data.category}</h1>
{if $category_data.description || $runtime.customization_mode.live_editor}
    <div class="ty-wysiwyg-content ty-mb-s" {live_edit name="category:description:{$category_data.category_id}"}>{$category_data.description nofilter}</div>
{/if}

{if $products}
{assign var="layouts" value=""|fn_get_products_views:false:0}
{if $category_data.product_columns}
    {assign var="product_columns" value=$category_data.product_columns}
{else}
    {assign var="product_columns" value=$settings.Appearance.columns_in_products_list}
{/if}

{if $layouts.$selected_layout.template}
    {include file="`$layouts.$selected_layout.template`" columns=$product_columns}
{/if}

{elseif !$subcategories || $show_no_products_block}
<p class="ty-no-items cm-pagination-container">{__("text_no_products")}</p>
{else}
<div class="cm-pagination-container"></div>
{/if}
<!--category_products_{$block.block_id}--></div>
###################################################################################
# Добавляем сюда свою кнопку, которая будет отвечать за загрузку нового контента
    {assign var="pagination" value=$search|fn_generate_pagination} 
    {if $pagination.total_pages>1} # если у нас больше одной страницы в категории
       {if $smarty.request.dispatch=="products.search"} # если страница поиска
         <div class="gul-load-more serchpagin" data-curcateg='{$smarty.server.REQUEST_URI}' data-curpagunpage="{$pagination.current_page}" data-allpaginpage="{$pagination.total_pages}">Загрузить еще</div>
       {elseif $smarty.request.dispatch=="categories.view"} # если страница каталога
            <div class="gul-load-more catpagin" data-curcateg='{"categories.view&category_id={$category_data.category_id}"|fn_url}' data-curpagunpage="{$pagination.current_page}" data-allpaginpage="{$pagination.total_pages}">Загрузить еще</div>
       {/if}>
    {/if}
###################################################################################
{capture name="mainbox_title"}<span {live_edit name="category:category:{$category_data.category_id}"}>{$category_data.category}</span>{/capture}
{/hook}

2. В файле \blocks\list_templates\grid_list.tpl нужно убрать вызов стандартной пагинации и добавить необходимые теги, чтобы наша загрузка работала


{if $products}

    {script src="js/tygh/exceptions.js"}
    

    {if !$no_pagination}
  #####################################################################################
  # заменяем тут подключение стандартной пагинации на блок контента
        <div class="ty-pagination-container cm-pagination-container" id="pagination_contents">
  #####################################################################################
    {/if}

    {if !$show_empty}
        {split data=$products size=$columns|default:"2" assign="splitted_products"}
    {else}
        {split data=$products size=$columns|default:"2" assign="splitted_products" skip_complete=true}
    {/if}

    {math equation="100 / x" x=$columns|default:"2" assign="cell_width"}
    {if $item_number == "Y"}
        {assign var="cur_number" value=1}
    {/if}

    {* FIXME: Don't move this file *}
    {script src="js/tygh/product_image_gallery.js"}

    {if $settings.Appearance.enable_quick_view == 'Y'}
        {$quick_nav_ids = $products|fn_fields_from_multi_level:"product_id":"product_id"}
    {/if}
    <div class="grid-list">
        {strip}
            {foreach from=$splitted_products item="sproducts" name="sprod"}
                {foreach from=$sproducts item="product" name="sproducts"}
                    <div class="ty-column{$columns}">
                        {if $product}
                            {assign var="obj_id" value=$product.product_id}
                            {assign var="obj_id_prefix" value="`$obj_prefix``$product.product_id`"}
                            {include file="common/product_data.tpl" product=$product}

                            <div class="ty-grid-list__item ty-quick-view-button__wrapper">
                                {assign var="form_open" value="form_open_`$obj_id`"}
                                {$smarty.capture.$form_open nofilter}
                                {hook name="products:product_multicolumns_list"}
                                        <div class="ty-grid-list__image">
                                            {include file="views/products/components/product_icon.tpl" product=$product show_gallery=true}

                                            {assign var="discount_label" value="discount_label_`$obj_prefix``$obj_id`"}
                                            {$smarty.capture.$discount_label nofilter}
                                        </div>

                                        <div class="ty-grid-list__item-name">
                                            {if $item_number == "Y"}
                                                <span class="item-number">{$cur_number}. </span>
                                                {math equation="num + 1" num=$cur_number assign="cur_number"}
                                            {/if}

                                            {assign var="name" value="name_$obj_id"}
                                            {$smarty.capture.$name nofilter}
                                        </div>

                                        <div class="ty-grid-list__price {if $product.price == 0}ty-grid-list__no-price{/if}">
                                            {assign var="old_price" value="old_price_`$obj_id`"}
                                            {if $smarty.capture.$old_price|trim}{$smarty.capture.$old_price nofilter}{/if}

                                            {assign var="price" value="price_`$obj_id`"}
                                            {$smarty.capture.$price nofilter}

                                            {assign var="clean_price" value="clean_price_`$obj_id`"}
                                            {$smarty.capture.$clean_price nofilter}

                                            {assign var="list_discount" value="list_discount_`$obj_id`"}
                                            {$smarty.capture.$list_discount nofilter}
                                        </div>

                                        <div class="ty-grid-list__control">
                                            {if $settings.Appearance.enable_quick_view == 'Y'}
                                                {include file="views/products/components/quick_view_link.tpl" quick_nav_ids=$quick_nav_ids}
                                            {/if}

                                            {if $show_add_to_cart}
                                                <div class="button-container">
                                                    {assign var="add_to_cart" value="add_to_cart_`$obj_id`"}
                                                    {$smarty.capture.$add_to_cart nofilter}
                                                </div>
                                            {/if}
                                        </div>
                                {/hook}
                                {assign var="form_close" value="form_close_`$obj_id`"}
                                {$smarty.capture.$form_close nofilter}
                            </div>
                        {/if}
                    </div>
                {/foreach}
                {if $show_empty && $smarty.foreach.sprod.last}
                    {assign var="iteration" value=$smarty.foreach.sproducts.iteration}
                    {capture name="iteration"}{$iteration}{/capture}
                    {hook name="products:products_multicolumns_extra"}
                    {/hook}
                    {assign var="iteration" value=$smarty.capture.iteration}
                    {if $iteration % $columns != 0}
                        {math assign="empty_count" equation="c - it%c" it=$iteration c=$columns}
                        {section loop=$empty_count name="empty_rows"}
                            <div class="ty-column{$columns}">
                                <div class="ty-product-empty">
                                    <span class="ty-product-empty__text">{__("empty")}</span>
                                </div>
                            </div>
                        {/section}
                    {/if}
                {/if}
            {/foreach}
        {/strip}
    </div>

    {if !$no_pagination}
  ################################# 
  # так-же заменяем стандартную пагинацию на закрытие тега 
        <!--pagination_contents--></div>
  #################################
    {/if}

{/if}

{capture name="mainbox_title"}{$title}{/capture}

3. В скриптах своего модуля или в скриптах своей темы \common\scripts.tpl нужно добавить обработчик загрузки нового контента для нашей кнопки

$('body').on('click','.gul-load-more',function(){ // объявляем событие на клик по нашей кнопке
 var but=$(this); // заносим в переменную нашу кнопку
    if (but.hasClass('catpagin')) { // если страница каталога
     $.ceAjax('request', $(this).data('curcateg') + 'page-' + ($(this).data('curpagunpage') + 1) + '/', {
         result_ids: 'pagination_contents',
            caching: true,
            append: true,
            callback: function (data) {
             but.next().next().next('.ty-sort-container').remove(); // убираем блок с сортировкой
                but.next('.ty-pagination__bottom').remove(); // убираем блок с пагинацией
                but.remove();

                if (but.data('curpagunpage') + 1 >= but.data('allpaginpage')) { // если страница, которую мы загружаем последняя, удаляем кнопку "загрузить ещё"
                 $('.gul-load-more').remove();
                }
             }
          });
      } else if (but.hasClass('serchpagin')) { // если страница поиска
       var request=$(this).data('curcateg');
        request=request.replace("page="+$(this).data('curpagunpage'), "page="+($(this).data('curpagunpage') + 1));
        $.ceAjax('request', request, {
         result_ids: 'pagination_contents',
            caching: true,
            append: true,
            callback: function (data) {
             but.next().next().next('.ty-sort-container').remove(); // убираем блок с сортировкой
                but.next('.ty-pagination__bottom').remove(); // убираем блок с пагинацией
                but.remove();

                if (but.data('curpagunpage') + 1 >= but.data('allpaginpage')) { // если страница, которую мы загружаем последняя, удаляем кнопку "загрузить ещё"
                 $('.gul-load-more').remove();
                }
             }
          });
       }
});

25 ноября 2019

Title, description, keywords и h1 для категорий товаров Woocommerce

Для вывода мета-полей на странице редактирования категорий товаров используем хук product_cat_edit_form_fields.

Редактируем файл functions.php

/* Мета-поля для категорий товаров */
add_action("product_cat_edit_form_fields", 'NAME_meta_product_cat');
function NAME_meta_product_cat($term){?>
<tr class="form-field">
<th scope="row" valign="top"><label>Заголовок (title)</label></th>
<td><input type="text" name="NAME[title]" value="<?php echo esc_attr( get_term_meta( $term->term_id, 'title', 1 ) ) ?>"><br /><p class="description">Не более 60 знаков, включая пробелы</p>
</td>
</tr>
<tr class="form-field">
<th scope="row" valign="top"><label>Краткое описание (description)</label></th>
<td><input type="text" name="NAME[description]" value="<?php echo esc_attr( get_term_meta( $term->term_id, 'description', 1 ) ) ?>"><br /><p class="description">Краткое описание (description)</p>
</td>
</tr>
<tr class="form-field">
<th scope="row" valign="top"><label>Заголовок h1</label></th>
<td><input type="text" name="NAME[h1]" value="<?php echo esc_attr( get_term_meta( $term->term_id, 'h1', 1 ) ) ?>"><br /><p class="description">Заголовок страницы</p>
</td>
</tr>
<tr class="form-field">
<th scope="row" valign="top"><label>Ключевые слова</label></th>
<td><input type="text" name="NAME[keywords]" value="<?php echo esc_attr( get_term_meta( $term->term_id, 'keywords', 1 ) ) ?>"><br /><p class="description">Ключевые слова (keywords)</p>
</td>
</tr>
<?php}


На странице редактирования категорий товаров появится четыре новых поля:


Теперь сохраняем данные в БД используя еще одну функцию

/* Сохранение данных в БД */
add_action('edited_product_cat', 'NAME_save_meta_product_cat');  
add_action('create_product_cat', 'mayak_save_meta_product_cat');
function NAME_save_meta_product_cat($term_id){
 if (!isset($_POST['NAME']))
  return;
 $NAME = array_map('trim', $_POST['NAME']);
 foreach($NAME as $key => $value){
  if(empty($value)){
   delete_term_meta($term_id, $key);
   continue;
  }
  update_term_meta($term_id, $key, $value);
 }
 return $term_id;
}

WordPress вывести имя и ID термина таксономии текущей страницы или дочерней

$taxonomy_name = get_queried_object()->name; // Get the name of the taxonomy
$term_id = get_queried_object_id(); // Get the id of the taxonomy

01 ноября 2019

Редирект со страницы без заданых параметров в корень

301-редирект со страницы без заданного параметра в корень .htaccess


http://www.site.ru/?abc

RewriteCond %{QUERY_STRING} ^abc$ [NC]
RewriteRule ^$ /? [R=301,L]



http://www.site.ru/?page=2

RewriteCond %{QUERY_STRING} ^page=2$ [NC]
RewriteRule ^$ /? [R=301,L]


28 октября 2019

Хуки, которые необходимо вставить в functions.php после установки сайта


1. Склонение дат на сайте



function true_russian_date_forms($the_date = '') {
 if ( substr_count($the_date , '---') > 0 ) {
  return str_replace('---', '', $the_date);
 }
 // массив замен для русской локализации движка и для английской
 $replacements = array(
  "Январь" => "января", // "Jan" => "января"
  "Февраль" => "февраля", // "Feb" => "февраля"
  "Март" => "марта", // "Mar" => "марта"
  "Апрель" => "апреля", // "Apr" => "апреля"
  "Май" => "мая", // "May" => "мая"
  "Июнь" => "июня", // "Jun" => "июня"
  "Июль" => "июля", // "Jul" => "июля"
  "Август" => "августа", // "Aug" => "августа"
  "Сентябрь" => "сентября", // "Sep" => "сентября"
  "Октябрь" => "октября", // "Oct" => "октября"
  "Ноябрь" => "ноября", // "Nov" => "ноября"
  "Декабрь" => "декабря" // "Dec" => "декабря"
 );
 return strtr($the_date, $replacements);
}
 
// если хотите, вы можете приминить только некоторые из фильтров
add_filter('the_time', 'true_russian_date_forms');
add_filter('get_the_time', 'true_russian_date_forms');
add_filter('the_date', 'true_russian_date_forms');
add_filter('get_the_date', 'true_russian_date_forms');
add_filter('the_modified_time', 'true_russian_date_forms');
add_filter('get_the_modified_date', 'true_russian_date_forms');
add_filter('get_post_time', 'true_russian_date_forms');
add_filter('get_comment_date', 'true_russian_date_forms');

2. Сообщения об ошибках при попытке авторизации пользователя на сайте



function true_change_default_login_errors(){
 return '<strong>ОШИБКА</strong>: Вы ошиблись при вводе логина или пароля.';
}
 
add_filter( 'login_errors', 'true_change_default_login_errors' );

3. Защита от вредоносных URL-запросов



if (strpos($_SERVER['REQUEST_URI'], "eval(") || strpos($_SERVER['REQUEST_URI'], "CONCAT") || strpos($_SERVER['REQUEST_URI'], "UNION+SELECT") || strpos($_SERVER['REQUEST_URI'], "base64")) {
 @header("HTTP/1.1 400 Bad Request");
 @header("Status: 400 Bad Request");
 @header("Connection: Close");
 @exit;
}

4. Защита от автоматического спама



function true_stop_spam( $commentdata ) {
 $fake = trim($_POST['comment']); // обычное поле комментирования мы скроем через CSS
 if(!empty($fake)) // заполнение его роботами будет приводить к ошибке, комментарий отправляться не будет
  wp_die('Спамный коммент!'); 
 $_POST['comment'] = trim($_POST['true_comment']); // затем мы присвоим ему значение поля комментария, которое для людей
 return $commentdata;
}
 
add_filter('pre_comment_on_post', 'true_stop_spam');

5. Скрываем имена пользователей из HTML-кода комментариев



function true_remove_css_class( $classes ) {
 foreach( $classes as $key => $class ) {
  if(strstr($class, "comment-author-")) {
   unset( $classes[$key] );
  }
 }
 return $classes;
}
add_filter('comment_class', 'true_remove_css_class');

6. Запрет пингбэков и трэкбэков на самого себя



function true_disable_self_ping( &$links ) {
 foreach ( $links as $l => $link )
  if ( 0 === strpos( $link, get_option( 'home' ) ) )
    unset($links[$l]);
}
 
add_action( 'pre_ping', 'true_disable_self_ping' );

7. Скрываем версию WordPress

 
function true_remove_wp_version_wp_head_feed() {
 return '';
}
 
add_filter('the_generator', 'true_remove_wp_version_wp_head_feed');

Как определить текущий язык страницы wordpress

<?php echo $lang=get_bloginfo("language"); ?>

27 октября 2019

Добавить контент в описание товара WooCommerce

Кастомный вывод краткого описания


add_filter( 'woocommerce_short_description', 'single_product_short_descriptions', 10, 1 ); function single_product_short_descriptions( $post_excerpt ){ global $product; if ( is_single( $product->id ) ) $post_excerpt = '
' . __( "Article only available in the store.", "woocommerce" ) . '
' . $post_excerpt; return $post_excerpt; }

Принудительно указывать описание продукта, если оно пустое (если вы хотите, чтобы этот пользовательский текст отображался):


add_filter( 'woocommerce_product_tabs', 'force_description_product_tabs' ); function force_description_product_tabs( $tabs ) { $tabs['description'] = array( 'title' => __( 'Description', 'woocommerce' ), 'priority' => 10, 'callback' => 'woocommerce_product_description_tab', ); return $tabs; }


function.php

25 октября 2019

Перевод строк в Wordpress

WPML

позволяет переводить тексты внутри темы и плагинов.




_e()

Переводит указанный текст, используя файл перевода и выводит его на экран.
Работает на основе: translate()

Использование

<?php _e( $text, $domain ) ?>
$text(строка) (обязательный)
Текст, который нужно перевести.
По умолчанию: нет
$domain(строка)
ID перевода. Область определения перевода, обозначается названием, которое затем станет идентификатором в PHP.
По умолчанию: default

Примеры

#1. Пример использования функции в базовой теме WordPress:

<?php _e( 'Comment: ' ); ?>
Если используется русский файл локализации, то вернет: "Комментарий:".
Используется русский файл значит: в wp-config.php константа WPLANG определена как ru_RU (define('WPLANG', 'ru_RU');), а значит для такого перевода (без указания параметра $domain) будет использоваться файл ru_RU.mo из каталога wp-content\languages.

#2 Пример перевода с доменом

Допустим мы переводим плагин и у нас есть файл перевода .mo и мы его подключили с помощью load_plugin_textdomain(), где в параметре $domain указали myplugin. Тогда для перевода строки "my super plugin" функцию нужно будет вызвать так:
<?php _e( 'my super plugin', 'myplugin' ); ?>
<?php _e( 'текст любой', 'название_темы' ); ?>

WordPress - Атрибуты миниатюры

title и alt из заголовка записи

Мы можем сделать, чтобы у миниатюры записи (когда мы внутри записи) title и alt прописывались из заголовка записи динамически. Для этого, добавляем следующий сниппет в functions.php
function titles_gallery($attr){
 if ( is_single() ) {  
  $title = get_the_title();
  $attr['title'] = trim(strip_tags( $title ));
  $attr['alt'] = trim(strip_tags( $title )); 
 }  
 return $attr;  
}
add_filter('wp_get_attachment_image_attributes','titles_gallery',10,2);
При использовании функции логотип темы (custom_logo) изображение логотипа принимает свойства миниатюры и в него могут подставится те же alt и title, это неправильно! Нужно изменить вывод логотипа:
<div id="logo"><a href="<?php echo get_site_url(); ?>">
 <?php $custom_logo_id = get_theme_mod( 'custom_logo' );
 $image = wp_get_attachment_image_src( $custom_logo_id , 'full' ); ?>
 <img src="<?php echo $image[0]; ?>" alt="site-logo" title="site-logo">
</a></div>

Микроразметка миниатюры

Добавление миниатюре атрибута itemprop=»image»
if ( !is_admin() ) {
 add_filter( 'wp_get_attachment_image_attributes', 'alter_att_attributes_wpse');
 function alter_att_attributes_wpse($attr) {
  $attr['itemprop'] = 'image';
  return $attr;
 }
}

Размеры миниатюры

add_filter( 'wp_get_attachment_image_attributes', 'alter_att_attributes_wpse');

function alter_att_attributes_wpse($attr) {
 $attr['srcset'] = ' '; // !Отключение вывода вариаций изображения
 return $attr;
}

Можно делать комбинацию атрибутов title и alt + itemprop и т.д. в одной функции

title и alt товара woocommerce

Добавить динамический alt и title в виде заголовка товара изображениям товаров в категории — используем следующую функцию:
add_filter('wp_get_attachment_image_attributes', 'change_attachement_image_attributes', 20, 2);

function change_attachement_image_attributes( $attr, $attachment ){
    // Get post parent
    $parent = get_post_field( 'post_parent', $attachment);

    // Get post type to check if it's product
    $type = get_post_field( 'post_type', $parent);
    if( $type != 'product' ){ return $attr; }

    /// Get title
    $title = get_post_field( 'post_title', $parent);

    $attr['alt'] = $title;
    $attr['title'] = $title;

    return $attr;
}
Эта функция добавляет атрибуты и в шаблоне карточки товара