Отправка писем WooCommerce через GMail

Если письма с сайта не приходят, можно попробовать отправлять из через почтовый сервер gmail.

Для небольшого количества писем можно бесплатно получить ключи в Google Cloud.

Работает это в связке с плагином WP Mail SMTP, который позволяет настроить отправку почты через разные сервера, в обход стандартной php функции mail() на вашем хостинге. Это увеличивает вероятность доставки почты. Подходит для тех у кого письма с сайта не доходят. Особенно касается mail.ru почты.

Поможет, если не приходят email письма уведомления о заказе в WooCommerce.

Подключаем Google Cloud API

Переходим по ссылке Google Cloud API.

Google Cloud API

Нужно нажать кнопку "+ CREATE CREDENTIALS" и выбрать вариант OAuth client ID

Google Cloud API CREATE CREDENTIALS

Выбираем Application type - Web Application

Google Cloud API Web Application

После этого вам выдадут Client ID и Client Secret. Сохраните их для настройки плагина.

Далее переходим в админку WordPress. Устанавливаем плагин и в настройках выбираем отправку через gmail:

WPMail

Указываем наши ключи от Google Aloud API, нажимаем кнопку "Разрешить плагину отсылать почту используя ваш Google аккаунт":

WPMail Settings

После этого Google предложит авторизоваться и аккаунт будет подключен.

Теперь вся почта с сайта будет отсылаться через ваш почтовый Google сервер

Обратите внимание, что письма будут приходить с вашего gmail ящика

Кнопка сменится на другую и будет указан почтовый ящик, с которго будут приходить письма.

WPMail Settings

Убрать автопараграфы из Категории Woocommerce

Мы можем переопределить функцию для вывода описания Категории товаров Woocommerce.

У меня бывают ситуации, когда мне нужно в описании вставить JavaScript код или добавить шорткоды, при этом стандартные фильтры, которые добавляют параграфы и разрывы строк ломают верстку

Ниже приведена функция, которую вы можете вставить в файл functions.php.

Она уберет вставку автопараграфов, позволит добавлять чистый html и JS код в описании категорий товаров Woocommerce и при этом даст возможность использовать шорткоды.


function woocommerce_taxonomy_archive_description() {
  if ( is_product_taxonomy() && 0 === absint( get_query_var( 'paged' ) ) ) {
    $term = get_queried_object();
 
    if ( $term && !empty( $term->description ) ) {

      add_filter( 'term_description_add_shortcode', 'do_shortcode', 11 );
 
      echo '<div class="term-description">' . apply_filters( 'term_description_add_shortcode', $term->description )  . '</div>';
    }
  }
}

Объединить страницы Корзина и Оформление заказа в WooCommerce

Как известно, чем меньше этапов в оформлении заказа, тем выше конверсия. В некоторых случаях имеет смысл сделать отдельную корзину, но для большинства интернет-магазинов можно смело объединять ее с оформлением заказа.

На выходе должно получиться что-то подобное:

Форма заказа с корзиной Woocommerce

Во-первых, должна быть создана страница "Оформление заказа". Она обычно создается при установке плагина Woocommerce. Если ее нет, создайте.

Блоки с корзиной и формой заказа выводятся с помощью шорткодов. Мы сейчас не будет обсуждать что такое шорткоды. Если в двух словах, то это блоки кода, которые можно вставлять в редактор с помощью ярлыка в квадратных скобках. Вам нужно добавить на страницу оформления заказ следующий код:

Форма заказа с корзиной Woocommerce
[woocommerce_cart]

[woocommerce_checkout]

Далее нужно сообщить WooCommerce, что у нас изменился порядок страниц. Делается это на странице настроек WooCommerce:

Настройки эндпоинтов Woocommerce

Не забудьте поменять с коде ссылки. Вместо /cart сделать /checkout. Чтобы при переходе по ссылке корзины, сразу открывалась страница оформления заказа, можно добавить редирект в файле .htaccess корневой папке с сайтом:

Redirect 301 /cart http://site/checkout

После этого остается дело за малым, настроить оформление этой страницы.

Файлы шаблонов Woocommerce — что означают?

Чтобы шаблоны работали, убедитесь, что в functions.php указано add_theme_support( 'woocommerce' );

Шаблоны вывода категории

Шаблоны вывода страницы товара

Как убрать надпись «включая НДС» в Woocommerce

надпись (включая ХХХ ₽ НДС) в корзине и на странице оформления заказа

Убираем надпись "(включая ХХХ ₽ НДС)" в корзине и на странице оформления заказа с помощью фильтра.

Для этого нужно в файл function.php посемтить следующий код:

add_filter( 'woocommerce_cart_totals_order_total_html', 'delete_nds_tax_from_checkout', 10 );
function delete_nds_tax_from_checkout( $value ) {
  return preg_replace("/<small[^>]+?[^>]+>(.*?)<\/small>/i", '', $value);
}

Это не идеальное решение, потому что мы просто удаляем тег с этой надписью после того как он уже сгенерирован. Но почему-то разработчики Woocommerce не предусмотрели возможность переопределить функцию, выводящую итог или хотя бы отключить через админку вывод налога.

Можно было бы переписать функцию прямо в движке Woocommerce, но это плохая практика, так как если при обновлении версии woocommerce будут изменения в файле wc-cart-functions.php, то наши изменения пропадут и их надо будет вносить снова.

Скрыть метод оплаты для не авторизованных пользователей Woocommerce

Часто бывает необходимо скрыть от пользователей метод оплаты. Как пример: у нас есть интернет-магазин, где пользователи покупают товары без авторизации и создания аккаунтов. Для тестирования эквайринга на сайте (в нашем случае это эквайринг от Сбербанка) нужно скрыть этот метод оплаты от всех, кроме админа, который авторизовался.

То есть нам надо включить метод оплаты только для зарегистрированных пользователей

Нужно добавить следующий код в файл functions.php:

function sberbank_for_logged_user($available_gateways)
{
  global $woocommerce;
 
  if ( !is_user_logged_in() ) { unset($available_gateways['rbspayment']); }
 
  return $available_gateways;
}
add_action('woocommerce_available_payment_gateways', 'sberbank_for_logged_user');

Обратите внимание на $available_gateways['rbspayment'] - где взять название метода?

Все очень просто, можно посмотреть в админке, в ссылке на этот метод, в параметре §ion=rbspayment:

методы оплаты Woocommerce
Наведите мышкой на способ оплаты, чтобы увидеть ссылку

Как сделать мета-теги для категорий Woocommerce с помощью ACF

Для чего это вообще нужно?

Как вы уже наверняка знаете, мета-теги нужны для SEO-продвижения, и если вы пишите свою тему на WordPress или дорабатываете какую-то чужую, то у вас есть два варианта добавить теги. Либо плагином, либо самому подключить поля для мета-тегов на нужные страницы.

Чаще всего я вижу на клиентских сайтах плагины Yast SEO и All in One SEO Pack. На мой взгляд, они добавляют ненужный функционал, часть которого я и так добавляю вставкой заготовленного кода в functions.php. Тем более я хочу также влиять на последний узел в хлебных крошках.

Приведу пример:

Согласитесь, смотрелось бы не очень красиво, если бы я подргужал в хлебные крошки заголовок, как это делают большинство плагинов.

Поэтому я предпочитаю самостоятельно добавить поля для мета-тегов через Advanced Custom Fields. Установка описана здесь - (Установка Advanced Custom Fields).

Для этого нужно:

  1. Добавить группу полей
  2. Добавить вывод полей в шаблоне

Добавить поля ACF для мета тегов на карточки товаров и категории

В админке на вкладке "Группы полей" добавьте следующие поля.

типы полей ACF
На скриншоте пример моих полей. Достаточно при создании указать Ярлык, Имя, Тип.

И выбрать Условия отображения:

Условия показа ACF для Woocommerce
"Категории" находятся в "Формы -> Таксономия"

В итоге поля должны появиться в админке в том числе на страницах Категорий и Товаров.

Вывод полей ACF на странице категории товаров woocommerce

Добавляем вывод полей ACF в шаблон

В Title я использую следующую логику. Сначала для данной страницы проверяется, существует ли тайтл из поля категории. Если его нет, то происходит поиск поля со страницы/записи, если его нет, то подставляется Заголовок страницы.

В шаблон это нужно вставить в файл header.php перед тегом title:

$queried_object = get_queried_object(); 
$taxonomy = $queried_object->taxonomy;
$term_id = $queried_object->term_id;

Внутрь тега title:

if( get_field( 'wc_title', $taxonomy . '_' . $term_id ) ) {
  the_field( 'wc_title', $taxonomy . '_' . $term_id );
} elseif ( get_field('wc_title') ) {
  the_field( 'wc_title' );
} else {
  wp_title( '',true );
}

Для description и keywords такая же логика, только мы не подгружаем туда заголовок. Вообще keywords можно не делать, так как он в ранжировании поисковиками не участвует, но это другая история.

if( get_field( 'wc_description', $taxonomy . '_' . $term_id ) ) {
  the_field( 'wc_description', $taxonomy . '_' . $term_id );
} else {
  the_field( 'wc_description' );
}

Keywords:

if( get_field( 'wc_keywords', $taxonomy . '_' . $term_id ) ) { 
  the_field( 'wc_keywords', $taxonomy . '_' . $term_id);
} else {
  the_field( 'wc_keywords' );
}

Как вывести поле ACF в письмо Woocommerce

О том как добавить произвольные поля можно почитать в разделе Руководство по Advanced Custom Fields.

Сначала приведу пример кода, потом подробно его рассмотрим:

function the_custom_field( $item_id, $item, $order, $plain_text){
  if( $color = get_field( 'color', $item->get_product_id() )) {
    echo $color;
  }
}
add_action('woocommerce_order_item_meta_start', 'the_custom_field', 20, 4);

За вывод списка товаров в письме отвечает шаблон email-order-items.php. Если посмотреть в код, то мы увидим несколько хуков (такие места в коде, куда мы можем вклинить выполнение своих функций).

// allow other plugins to add additional product information here.
do_action( 'woocommerce_order_item_meta_start', $item_id, $item, $order, $plain_text );

// allow other plugins to add additional product information here.
do_action( 'woocommerce_order_item_meta_end', $item_id, $item, $order, $plain_text );

У меня между ними ничего не выводится, поэтому я могу использовать любой. У вас могут выводиться атрибуты товаров, поэтому поэкспериментируйте, чтобы определить в какой именно добавиться вывод кода.

Далее, когда мы знаем какой хук использовать (например, woocommerce_order_item_meta_start) и какие параметры но принимает ($item_id, $item, $order, $plain_text), можем написать функцию вывода атрибута из ACF (тот код, который я привел в самом начале).

Поместить её нужно, как обычно, в файл functions.php вашей темы.

add_action('woocommerce_order_item_meta_start', 'the_custom_field', 20, 4); - эта строка связывает нашу функцию the_custom_field и хук woocommerce_order_item_meta_start.

Параметр "10" отвечает за приоритет. Если несколько функций привязано к хуку, то первым выведется тот, у которого это число меньше.

Параметр "4" отвечает за то, сколько параметров передается нашей функции из хука. Данный хук передает 4 параметра - $item_id, $item, $order, $plain_text. И эти же параметры мы указываем при создании функции function the_custom_field( $item_id, $item, $order, $plain_text)

Теперь посмотрим, что происходит внутри:

if( $color = get_field( 'color', $item->get_product_id() )) {
  echo $color;
}

Тут буквально написано, что мы получаем поле с именем color для товара с id равным $item->get_product_id(). И если такое поле существует, то выводим его содержимое. Можете подробнее прочитать про Описание функции get_field()

Если мы заглянем в файлы шаблонов WooCommerce, то увидим, что этот Хук содержится не только в шаблоне письма, но и в шаблонах оформления заказа, и на странице, которая выводится с подтверждением, после оформления заказа. То есть внеся изменения через хук информация в форме заказа и далее в цепочке заказа обновится автоматически. Это надо помнить и при необходимости поменять шаблоны.

Изменить текст кнопки «Добавить в корзину» на странице товара

Текст выводится функцией $product->single_add_to_cart_text(), которая определена в файле /wp-content/plugins/woocommerce/includes/abstracts/abstract-wc-product.php

  /**
   * Get the add to cart button text for the single page.
   *
   * @return string
   */
  public function single_add_to_cart_text() {
    return apply_filters( 'woocommerce_product_single_add_to_cart_text', __( 'Add to cart', 'woocommerce' ), $this );
  }

Как видно из кода, здесь можно использовать фильтр. Добавим код ниже в файл functions.php:

function my_theme_cart_button_text() {
  return 'Оформить заказ';
}
add_filter( 'woocommerce_product_single_add_to_cart_text', 'my_theme_cart_button_text' );

В фильтр мы передаем новый текст, вместо старого. В принципе, можно сразу передать текст который нужно. Но если сайт использует мультиязычность, то лучше добавить файл с переводами для Вашей темы. Как сделано в примере ниже и реализовано в самом woocommerce.

function my_theme_cart_button_text() {
  return __( 'Add to cart', 'my_theme' );
}
add_filter( 'woocommerce_product_single_add_to_cart_text', 'my_theme_cart_button_text' );

Настройка полей заказа WooCommerce с помощью actions и filters

Все манипуляции с кодом из этой статьи следует проводить в файле functions.php

Поля оплаты и доставки для формы заказа подтягиваются из класса объявленного в файле class-wc-countries.php и функции get_address_fields(). Это позволяет включать и выключать поля на основе локации пользователя. Перед тем как вернуть эти поля, woocommerce прогоняет их через фильтры. Это позволяет редактировать их с помощью тем и плагинов.

Оплата:

$address_fields = apply_filters('woocommerce_billing_fields', $address_fields);

Доставка:

$address_fields = apply_filters('woocommerce_shipping_fields', $address_fields);

Класс checkout добавляет загружаемые поля в массив 'checkout_fields', а также добавляет несколько других полей, таких как 'order_notes'.

$this->checkout_fields['billing']    = $woocommerce->countries->get_address_fields( $this->get_value('billing_country'), 'billing_' );
$this->checkout_fields['shipping']   = $woocommerce->countries->get_address_fields( $this->get_value('shipping_country'), 'shipping_' );
$this->checkout_fields['account']    = array(
    'account_username' => array(
        'type' => 'text',
        'label' => __('Account username', 'woocommerce'),
        'placeholder' => _x('Username', 'placeholder', 'woocommerce')
        ),
    'account_password' => array(
        'type' => 'password',
        'label' => __('Account password', 'woocommerce'),
        'placeholder' => _x('Password', 'placeholder', 'woocommerce'),
        'class' => array('form-row-first')
        ),
    'account_password-2' => array(
        'type' => 'password',
        'label' => __('Account password', 'woocommerce'),
        'placeholder' => _x('Password', 'placeholder', 'woocommerce'),
        'class' => array('form-row-last'),
        'label_class' => array('hidden')
        )
    );
$this->checkout_fields['order']  = array(
    'order_comments' => array(
        'type' => 'textarea',
        'class' => array('notes'),
        'label' => __('Order Notes', 'woocommerce'),
        'placeholder' => _x('Notes about your order, e.g. special notes for delivery.', 'placeholder', 'woocommerce')
        )
    );

Этот массив также проходит через фильтр:

$this->checkout_fields = apply_filters('woocommerce_checkout_fields', $this->checkout_fields);

Это дает полный контроль над полями - надо только знать как получить к ним доступ.

Перезапись ядра полей

Хук внутри фильтра woocommerce_checkout_fields позволяет перезаписывать любые поля. Для примера, давайте изменим плейсхолдер у поля order_comments.

Сейчас он задан через _x('Notes about your order, e.g. special notes for delivery.', 'placeholder', 'woocommerce')

Мы можем изменить его добавив несколько строк в файл functions.php

// Hook in
add_filter( 'woocommerce_checkout_fields' , 'custom_override_checkout_fields' );

// Our hooked in function - $fields is passed via the filter!
function custom_override_checkout_fields( $fields ) {
     $fields['order']['order_comments']['placeholder'] = 'My new placeholder';
     return $fields;
}

Можно переписать и другую часть, например label (название поля)

// Hook in
add_filter( 'woocommerce_checkout_fields' , 'custom_override_checkout_fields' );

// Our hooked in function - $fields is passed via the filter!
function custom_override_checkout_fields( $fields ) {
     $fields['order']['order_comments']['placeholder'] = 'My new placeholder';
     $fields['order']['order_comments']['label'] = 'My new label';
     return $fields;
}

Или удалить поле

// Hook in
add_filter( 'woocommerce_checkout_fields' , 'custom_override_checkout_fields' );

// Our hooked in function - $fields is passed via the filter!
function custom_override_checkout_fields( $fields ) {
     unset($fields['order']['order_comments']);

     return $fields;
}

Вот полный перечень полей, передаваемых woocommerce_checkout_fields

Каждое поле имеет массив свойств:

В некоторых случаях может понадобиться использовать фильтр woocommerce_default_address_fields. Они применяется к стандартным полям:

Для примера, сделаем поле address_1 не обязательным.

// Hook in
add_filter( 'woocommerce_default_address_fields' , 'custom_override_default_address_fields' );

// Our hooked in function - $address_fields is passed via the filter!
function custom_override_default_address_fields( $address_fields ) {
     $address_fields['address_1']['required'] = false;

     return $address_fields;
}

Приоритет

Приоритет помогает определить очередность запуска кода. Он устанавливается внутри каждой функции и полезен при переопределении существующего кода.

Код с большим номером будет запущен после кода с меньшим номером, это значит код с приоритетом 20 будет запущен после кода с приоритетом 10.

Аргумент, задающий приоритет передается в add_action после задания хука и функции, которую вы вешаете на этот хук.

add_action( 'woocommerce_return_to_shop_redirect', 'wc_empty_cart_redirect_url', 10);

Примеры

Редирект кнопки "Вернуться в магазин" из корзины на страницу с распродажей:

/**
 * Changes the redirect URL for the Return To Shop button in the cart.
 */
function wc_empty_cart_redirect_url() {
  return 'http://example.url/category/specials/';
}
add_filter( 'woocommerce_return_to_shop_redirect', 'wc_empty_cart_redirect_url', 10 );

Здесь вы можете увидеть, что приоритет установлен равным 10. Это обычно стандартный приоритет для функций Woocommerce, поэтому его может быть недостаточно, чтобы перезаписать функциональность кнопки.

Вместо этого мы можем изменить приоритет на другое значение больше 10. Не смотря на то, что 11 будет работать, хорошей практикой считается использовать числа кратные 10, то есть 20, 30 и так далее.

/**
 * Changes the redirect URL for the Return To Shop button in the cart.
 */
function wc_empty_cart_redirect_url() {
  return 'http://example.com/category/specials/';
}
add_filter( 'woocommerce_return_to_shop_redirect', 'wc_empty_cart_redirect_url', 20 );

С приоритетами мы можем иметь две функции на одном хуке. Обычно это может создать проблемы, но так как мы установили для одной функции более высокий приоритет чем для другой, наш сайт будет выполнять только соответствующую из них, и мы получим страницу с распродажей, как это предусмотрено в коде ниже:

/**
 * Changes the redirect URL for the Return To Shop button in the cart.
 * BECAUSE THIS FUNCTION HAS THE PRIORITY OF 20, IT WILL RUN AFTER THE FUNCTION BELOW (HIGHER NUMBERS RUN LATER)
 */
function wc_empty_cart_redirect_url() {
  return 'http://example.com/category/specials/';
}
add_filter( 'woocommerce_return_to_shop_redirect', 'wc_empty_cart_redirect_url', 20 );

/**
 * Changes the redirect URL for the Return To Shop button in the cart.
 * EVEN THOUGH THIS FUNCTION WOULD NORMALLY RUN LATER BECAUSE IT'S CODED AFTERWARDS, THE 10 PRIORITY IS LOWER THAN 20 ABOVE
 */
function wc_empty_cart_redirect_url() {
  return 'http://example.com/shop/';
}
add_filter( 'woocommerce_return_to_shop_redirect', 'wc_empty_cart_redirect_url', 10 );

Добавление своих полей доставки и оплаты

Добавление полей похоже на их перезаписывание. Например, добавим новое поле shipping_phone:

// Hook in
add_filter( 'woocommerce_checkout_fields' , 'custom_override_checkout_fields' );

// Our hooked in function - $fields is passed via the filter!
function custom_override_checkout_fields( $fields ) {
     $fields['shipping']['shipping_phone'] = array(
        'label'     => __('Phone', 'woocommerce'),
    'placeholder'   => _x('Phone', 'placeholder', 'woocommerce'),
    'required'  => false,
    'class'     => array('form-row-wide'),
    'clear'     => true
     );

     return $fields;
}

/**
 * Display field value on the order edit page
 */
 
add_action( 'woocommerce_admin_order_data_after_shipping_address', 'my_custom_checkout_field_display_admin_order_meta', 10, 1 );

function my_custom_checkout_field_display_admin_order_meta($order){
    echo '

'.__('Phone From Checkout Form').': ' . get_post_meta( $order->get_id(), '_shipping_phone', true ) . '

'; }
добавление полей в woocommerce

Что мы должны сделать с новым полем? Ничего. Потому что мы определили поле в массиве checkout_fields, поле автоматически обработается и сохранится в post meta. Если нужно добавить проверку, то нужно искать дополнительных хуки в классе checkout.

Добавляем произвольные поля

Подобным образом добавляем произвольные поля. Давайте добавим новое поле после поля "Комментарий к заказу" с помощью хука:

/**
 * Add the field to the checkout
 */
add_action( 'woocommerce_after_order_notes', 'my_custom_checkout_field' );

function my_custom_checkout_field( $checkout ) {

    echo '<div id="my_custom_checkout_field"><h2>' . __('My Field') . '</h2>';

    woocommerce_form_field( 'my_field_name', array(
        'type'          => 'text',
        'class'         => array('my-field-class form-row-wide'),
        'label'         => __('Fill in this field'),
        'placeholder'   => __('Enter something'),
        ), $checkout->get_value( 'my_field_name' ));

    echo '</div>';

}

Это даст нам следующий результат:

Теперь нам нужно добавить валидацию при отправке формы. Для этого примера это поле будет обязательным.

/**
 * Process the checkout
 */
add_action('woocommerce_checkout_process', 'my_custom_checkout_field_process');

function my_custom_checkout_field_process() {
    // Check if set, if its not set add an error.
    if ( ! $_POST['my_field_name'] )
        wc_add_notice( __( 'Please enter something into this new shiny field.' ), 'error' );
}

И при валидации будет выпадать ошибка


Напоследок, сохраним новое поле в поля заказа используя следующий код:

/**
 * Update the order meta with field value
 */
add_action( 'woocommerce_checkout_update_order_meta', 'my_custom_checkout_field_update_order_meta' );

function my_custom_checkout_field_update_order_meta( $order_id ) {
    if ( ! empty( $_POST['my_field_name'] ) ) {
        update_post_meta( $order_id, 'My Field', sanitize_text_field( $_POST['my_field_name'] ) );
    }
}

Если хотите отображать это поле на странице заказа в админке, то это можно сделать следующим кодом:

/**
 * Display field value on the order edit page
 */
add_action( 'woocommerce_admin_order_data_after_billing_address', 'my_custom_checkout_field_display_admin_order_meta', 10, 1 );

function my_custom_checkout_field_display_admin_order_meta($order){
    echo '

'.__('My Field').': ' . get_post_meta( $order->id, 'My Field', true ) . '

'; }

Получится следующий результат:

Добавление произвольного поля к email письмам

/* To use: 
1. Add this snippet to your theme's functions.php file
2. Change the meta key names in the snippet
3. Create a custom field in the order post - e.g. key = "Tracking Code" value = abcdefg
4. When next updating the status, or during any other event which emails the user, they will see this field in their email
*/
add_filter('woocommerce_email_order_meta_keys', 'my_custom_order_meta_keys');

function my_custom_order_meta_keys( $keys ) {
     $keys[] = 'Tracking Code'; // This will look for a custom field called 'Tracking Code' and add it to emails
     return $keys;
}