Программное обновление пользовательских атрибутов WooCommerce
Прежде всего, спасибо за участие в этом впечатляющем сообществе, которое уже тысячу раз помогало мне.
В моей среде Wordpress (тема Enfold, плагин WooCommerce) я создал систему для использования опроса в качестве входных данных для мгновенного создания постов на фронтенде сайта. Ответы из опроса включаются в автоматически генерируемые посты (тип 'product') вместе с пользовательскими атрибутами WooCommerce.
Я написал пользовательские запросы, реагирующие на триггеры в mySQL - вставляющие и обновляющие wp_posts, wp_terms, wp_postmeta, wp_term_relationships.
Все работает отлично, кроме одного: пользовательские атрибуты товаров WooCommerce не отображаются мгновенно в выпадающих/селект фильтрах на сайте. Однако 'ручное' нажатие кнопки Обновить на странице Wordpress решает проблему.
Я ищу способ точно повторить 'ручное' нажатие Обновить в CMS Wordpress. На данный момент сам пост успешно загружается на сайте, но его атрибуты товара WooCommerce не инициализируются.
До сих пор я пробовал множество обходных путей:
- Программное установление статуса поста (черновик) и мгновенное изменение на опубликованный пост (publish);
- Использование встроенного планировщика публикаций Wordpress, устанавливая время публикации;
- Вызов wp_update_post;
- Использование плагина Tao Scheduled Updates (https://nl.wordpress.org/plugins/tao-schedule-update/);
- Использование плагина WordPress PostController (https://github.com/HarriBellThomas/Wordpress_PostController)
Тем не менее, все попытки обновляют только посты в wp_posts, по-видимому, не затрагивая базовые отношения/пользовательские атрибуты товаров.
Моя единственная просьба - программно повторить нажатие на 'Обновить' в среде CMS Wordpress. Это помогло бы мне автоматизировать процесс вместо ручного вмешательства.
Не могли бы вы предложить способ сделать это?
Большое спасибо за ваше время!
ОБНОВЛЕНИЕ:
Привет, Том,
После изучения твоего ответа я все еще не понимаю.
Мои запросы обновляют/вставляют все необходимые таблицы. Они практически повторяют все шаги из упомянутых тобой php-скриптов.
Когда я проверяю товар в CMS, я вижу, что все данные - и особенно атрибуты - загружаются корректно. Когда я вручную нажимаю Обновить в CMS и сравниваю данные в таблицах mySQL до и после обновления, я не вижу значительных различий. Единственное, что я замечаю - это значение _product_attributes в wp_postmeta, которое немного отличается (сериализованная строка).
Однако, когда я экспериментирую с этим значением (очищаю/изменяю его для конкретного поста в wp_postmeta), ничего не меняется в атрибутах - и все по-прежнему работает при фильтрации.
Это приводит меня к вопросам:
- Что именно происходит при ручном нажатии 'Обновить'?
- Существует ли какое-то другое хранилище, кроме таблиц mySQL, где части каким-то образом связаны?
- Можно ли мне 1) принять процедуру 'создания товара', на которую ты ссылаешься, как данность и пропустить ее (так как я запускаю свои запросы), а затем 2) вызвать только точную процедуру, которая выполняется при нажатии Обновить - чтобы она 'связала' все вместе без повторного создания всех записей в базе данных?
- Если да, то где мне найти эту конкретную процедуру?
Твоя помощь очень ценится. Спасибо! Том

Хорошо, у меня была похожая проблема, и я расскажу, как её решить.
Всё работает отлично, за исключением одного: пользовательские атрибуты товаров WooCommerce не отображаются мгновенно в выпадающих списках/фильтрах на сайте. Однако, если вручную нажать "Обновить" в админке WordPress, всё начинает работать.
При отображении атрибутов WooCommerce использует функцию: wc_get_attribute_taxonomies() (http://woocommerce.wp-a2z.org/oik_api/wc_get_attribute_taxonomies/)
Вы заметите, что эта функция получает данные из 'транзиента' (это кешированные данные, см. http://codex.wordpress.org/Transients_API).
Если вы вручную загружаете данные в базу данных, возможно, вы пропустили загрузку транзиента (который, кстати, хранится в таблице wp_options
). Когда вы нажимаете "Обновить" в админке WordPress, запускается функция, которая обновляет транзиент, и поэтому атрибуты начинают отображаться.
Чтобы это исправить, убедитесь, что при ручном обновлении MySQL вы также обновляете транзиент. В моём случае, при ручном добавлении атрибутов товаров в WooCommerce, мне пришлось добавить строку в таблицу wp_options
с options_name
равным _transient_wc_attribute_taxonomies
и моими атрибутами в сериализованном массиве в колонке option_value
(плюс ID с автозагрузкой, установленной в 'yes'). Но есть и другие транзиенты, поэтому всё зависит от того, какая функция вызывает проблему и что именно вы пытаетесь отобразить. Вы можете определить, какой транзиент отсутствует, выполнив поиск в MySQL по %transient%
в таблице wp_options
до нажатия кнопки "Обновить" в админке WordPress и после, а затем сравнить данные.

Обновляете ли вы также термины внутри товара WooCommerce? И wp_term_taxonomy
, и wp_woocommerce_attribute_taxonomies
должны быть обновлены вашими таксономическими терминами, чтобы товар WooCommerce мог отображать выпадающие списки вариаций "Цвет" или "Размер".
При программном создании товара WooCommerce, вариации продукта необходимо вставить и привязать к существующим атрибутам (таксономиям, созданным в WooCommerce).
Обратите внимание на мета-ключ поста "_product_attributes", который хранит данные атрибутов. Вам все равно нужно будет связать термины (атрибуты) с вашим товаром (внутри wp_term_taxonomy
), но, надеюсь, это даст вам направление для дальнейших действий.
Также посмотрите функции create_product
(https://github.com/woothemes/woocommerce/blob/master/includes/api/class-wc-api-products.php#L237) и save_variations
(https://github.com/woothemes/woocommerce/blob/master/includes/api/class-wc-api-products.php#L1692), в которых описано, как выполняется создание товара и его вариаций.

Ещё раз спасибо, Том. Да, забыл упомянуть wp_term_taxonomy. Да, я тоже вставляю/обновляю эту таблицу.
Поскольку набор атрибутов не меняется и в wp_woocommerce_attribute_taxonomies не регистрируется количество, что именно там нужно обновлять?
Спасибо за ссылки. Я изучу их и дам вам знать!
С уважением, Том

Это один из вариантов с PHP кодом:
function change_price_by_type( $product_id, $price, $price_type) {
update_post_meta( $product_id, '_' . $price_type, $price );
}
function change_price_all_types( $product_id, $price ) {
change_price_by_type( $product_id, $price, 'price' );
change_price_by_type( $product_id, $price, 'sale_price' );
change_price_by_type( $product_id, $price, 'regular_price');
}
function change_product_price( $product_id, $price ) {
change_price_all_types( $product_id, $price );
$product = wc_get_product( $product_id ); // Обработка вариативных товаров
if ( $product->is_type( 'variable' ) ) {
// RM: Получаем вариации, включая те, которых нет в наличии
$args = array(
'post_type' => 'product_variation',
'post_status' => array( 'private', 'publish' ),
'numberposts' => -1,
'orderby' => 'menu_order',
'order' => 'asc',
'post_parent' => $product_id // $post->ID
);
$variations = get_posts( $args );
foreach ( $variations as $variation ) {
change_price_all_types( $variation->ID, $price );
}
}
}
$args = array( 'post_type' => 'product', 'posts_per_page' => 3000);
$products = get_posts( $args );
foreach($products as $product) {
change_product_price($product->ID, 9.99);
echo $product->ID;
}
exit;
затем перейдите в phpMyAdmin и выполните следующие SQL запросы (возможно, вам потребуется изменить название таблицы вместо wp_).
UPDATE `wp_postmeta`
SET `meta_value` = ''
WHERE `meta_key` IN ('_sale_price', '_sale_price_dates_from', '_sale_price_dates_to')
AND `post_id` IN
(SELECT `ID`
FROM `wp_posts`
WHERE `post_type` = 'product'
AND `post_status` = 'publish' );
Очистить кеш:
DELETE
FROM `wp_options`
WHERE (`option_name` LIKE '_transient_wc_var_prices_%'
OR `option_name` LIKE '_transient_timeout_wc_var_prices_%')
SQL код взят с: http://www.technoedu.com/forums/topic/wordpress-solved-copy-woocommerce-products-sale-prices-to-regular-prices-and-reset-sale-prices/
