I want to change discounts (sale price) for products in certain category, but no matter what i try the code:
How to make it change the same products and keep the same price among WPML/WCML translations? thank you for any advice
///automatic randomized discounts
// Define a custom 1-minute interval
function custom_1_minute_interval($schedules) {
$schedules['1minute'] = array(
'interval' => 60, // 1 minute in seconds
'display' => __('Every 1 Minute'),
);
return $schedules;
}
add_filter('cron_schedules', 'custom_1_minute_interval');
// Schedule the event to run the custom function every 1 minute
add_action('init', 'schedule_custom_function');
function schedule_custom_function() {
if (!wp_next_scheduled('every_1_minute_custom_function')) {
wp_schedule_event(time(), '1minute', 'every_1_minute_custom_function');
}
}
add_action('every_1_minute_custom_function', 'custom_function_to_manage_discounts');
function custom_function_to_manage_discounts() {
// Define the log file
$log_file = WP_CONTENT_DIR . '/promo.log';
// Open the log file for writing (creates a new file if it doesn't exist)
$log_handle = fopen($log_file, 'a');
// Check if the log file was successfully opened
if ($log_handle) {
// Log a timestamp indicating the start of the custom function
fwrite($log_handle, date('[d-M-Y H:i:s]') . " Custom function started." . PHP_EOL);
// Get all products in category ID 29 for the original language version
$category_id = 29;
$args = array(
'post_type' => 'product',
'posts_per_page' => -1,
'tax_query' => array(
array(
'taxonomy' => 'product_cat',
'field' => 'id',
'terms' => $category_id,
'include_children' => true,
),
),
);
$products = get_posts($args);
if ($products) {
// Log the product IDs retrieved from the category
$product_ids_list = array();
foreach ($products as $product) {
$product_ids_list[] = $product->ID;
}
fwrite($log_handle, date('[d-M-Y H:i:s]') . " Product IDs Retrieved from Category ID {$category_id}: " . implode(', ', $product_ids_list) . PHP_EOL);
// Calculate the number of products to apply discounts to (25% of total)
$discount_count = ceil(0.25 * count($products));
// Shuffle the products array randomly
shuffle($products);
// Iterate through products to clear discounts for all
foreach ($products as $product) {
// Get the product object
$product_obj = wc_get_product($product->ID);
// Clear discount price (sale price)
$product_obj->set_sale_price('');
$product_obj->set_date_on_sale_from('');
$product_obj->set_date_on_sale_to('');
// Log the action in the log file
fwrite($log_handle, date('[d-M-Y H:i:s]') . " Cleared discount for Product ID: {$product->ID}" . PHP_EOL);
// Save the product to trigger WooCommerce cache refresh
$product_obj->save();
}
// Apply discounts to a random 25% of products
for ($i = 0; $i < $discount_count; $i++) {
$product = $products[$i];
// Get the regular price
$regular_price = get_post_meta($product->ID, '_regular_price', true);
// Calculate the new discount price (90% of the regular price)
$new_discount_price = $regular_price * 0.9;
// Get the product object
$product_obj = wc_get_product($product->ID);
// Set the new discount price (sale price)
$product_obj->set_sale_price($new_discount_price);
$product_obj->set_date_on_sale_from(time());
// Calculate the new price as a separate variable
$new_price = $regular_price * 0.9;
// Log the action in the log file with the new price
fwrite($log_handle, date('[d-M-Y H:i:s]') . " Applied discount for Product ID: {$product->ID}, New Price: {$new_price}" . PHP_EOL);
// Save the product to trigger WooCommerce cache refresh
$product_obj->save();
}
}
// Log a timestamp indicating the completion of the custom function
fwrite($log_handle, date('[d-M-Y H:i:s]') . " Custom function completed." . PHP_EOL);
// Close the log file
fclose($log_handle);
}
}
Update: Code which works on my staging but not production:
// Define a custom 1-minute interval
function custom_1_minute_interval($schedules) {
$schedules['1minute'] = array(
'interval' => 60, // 1 minute in seconds
'display' => __('Every 1 Minute'),
);
return $schedules;
}
add_filter('cron_schedules', 'custom_1_minute_interval');
// Schedule the event to run the custom function every 1 minute
add_action('init', 'schedule_custom_function');
function schedule_custom_function() {
if (!wp_next_scheduled('every_1_minute_custom_function')) {
wp_schedule_event(time(), '1minute', 'every_1_minute_custom_function');
}
}
add_action('every_1_minute_custom_function', 'custom_function_to_manage_discounts');
function custom_function_to_manage_discounts() {
// Define the log file
$log_file = WP_CONTENT_DIR . '/promo.log';
// Open the log file for writing (creates a new file if it doesn't exist)
$log_handle = fopen($log_file, 'a');
// Check if the log file was successfully opened
if ($log_handle) {
// Log a timestamp indicating the start of the custom function
fwrite($log_handle, date('[d-M-Y H:i:s]') . " Custom function started." . PHP_EOL);
// Get all products in category ID 29 for the original language version
$category_id = array(2465); // <== Changed variable as an array
$posts_ids = get_posts( array(
'post_type' => 'product',
'post_status' => 'publish', // <== Added (published products only)
'posts_per_page' => -1,
'fields' => 'ids', // <== Get an array of product IDs
'orderby' => 'rand', // <== Random order (replace shuffle)
'tax_query' => array(
array(
'taxonomy' => 'product_cat',
'field' => 'term_id', // <== Mistake corrected (not 'id')
'terms' => $category_id,
'include_children' => true,
),
),
) );
if ( count($posts_ids) > 0 ) {
fwrite($log_handle, date('[d-M-Y H:i:s]') . " Product IDs Retrieved from Category ID {$category_id}: " . implode(', ', $posts_ids) . PHP_EOL);
// Calculate the number of products to apply discounts to (25% of total)
$discount_count = ceil(0.25 * count($posts_ids));
// Loop through product Ids
foreach ($posts_ids as $post_id) {
$product = wc_get_product($post_id); // Get the product object
// Reset sale price from discounted products only
if ( $product->get_sale_price() > 0 ) {
$reg_price = $product->get_regular_price(); // get regular price
$product->set_price($reg_price); // Set back the regular price
// Clear sale price
$product->set_sale_price('');
$product->set_date_on_sale_from('');
$product->set_date_on_sale_to('');
$product->save(); // Save the product to trigger WooCommerce cache refresh
do_action( 'wpml_sync_custom_field', $post_id, '_price' ); // refresh price for translations
do_action( 'wpml_sync_custom_field', $post_id, '_sale_price' ); // refresh sale price for translations
do_action( 'wpml_sync_custom_field', $post_id, '_sale_price_dates_from' ); // refresh field for translations
do_action( 'wpml_sync_custom_field', $post_id, '_sale_price_dates_to' ); // refresh field for translations
// Log the action in the log file
fwrite($log_handle, date('[d-M-Y H:i:s]') . " Cleared discount for Product ID: {$post_id}" . PHP_EOL);
}
}
// Apply discounts to a random 25% of products
for ($i = 0; $i < $discount_count; $i++) {
$post_id = $posts_ids[$i];
$product = wc_get_product($posts_ids[$i]); // Get the product object
$reg_price = $product->get_regular_price(); // get regular price
$sale_price = $reg_price * 0.9; // Calculate 10% discount
// Set the new discount price (sale price)
$product->set_price($sale_price);
$product->set_sale_price($sale_price);
$product->set_date_on_sale_from(time());
$product->save(); // Save the product to trigger WooCommerce cache refresh
do_action( 'wpml_sync_custom_field', $post_id, '_price' ); // refresh price for translations
do_action( 'wpml_sync_custom_field', $post_id, '_sale_price' ); // refresh sale price for translations
do_action( 'wpml_sync_custom_field', $post_id, '_sale_price_dates_from' ); // refresh field for translations
do_action( 'wpml_sync_custom_field', $post_id, '_sale_price_dates_to' ); // refresh field for translations
// Log the action in the log file with the new price
fwrite($log_handle, date('[d-M-Y H:i:s]') . " Applied discount for Product ID: {$post_id}, New Price: {$sale_price}" . PHP_EOL);
}
}
// Log a timestamp indicating the completion of the custom function
fwrite($log_handle, date('[d-M-Y H:i:s]') . " Custom function completed." . PHP_EOL);
fclose($log_handle); // Close the log file
}
}
Update 2 Issue narrowed down to be casued by different product default language version vs page default language version. My failed attempt to fix it below
// Define a custom 1-minute interval
function custom_1_minute_interval($schedules) {
$schedules['1minute'] = array(
'interval' => 60, // 1 minute in seconds
'display' => __('Every 1 Minute'),
);
return $schedules;
}
add_filter('cron_schedules', 'custom_1_minute_interval');
// Schedule the event to run the custom function every 1 minute
add_action('init', 'schedule_custom_function');
function schedule_custom_function() {
if (!wp_next_scheduled('every_1_minute_custom_function')) {
wp_schedule_event(time(), '1minute', 'every_1_minute_custom_function');
}
}
add_action('every_1_minute_custom_function', 'custom_function_to_manage_discounts');
function custom_function_to_manage_discounts() {
// Define the log file
$log_file = WP_CONTENT_DIR . '/promo.log';
// Open the log file for writing (creates a new file if it doesn't exist)
$log_handle = fopen($log_file, 'a');
// Check if the log file was successfully opened
if ($log_handle) {
// Log a timestamp indicating the start of the custom function
fwrite($log_handle, date('[d-M-Y H:i:s]') . " Custom function started." . PHP_EOL);
// Get all products in category ID 29 for the original language version (Polish)
$category_id = 2465; // Set the correct category ID for Polish products
$original_language = apply_filters('wpml_current_language', 'pl'); // Set the original language to Polish
// Switch to the original language
do_action('wpml_switch_language', $original_language);
$posts_ids = get_posts( array(
'post_type' => 'product',
'post_status' => 'publish', // Published products only
'posts_per_page' => -1,
'fields' => 'ids', // Get an array of product IDs
'orderby' => 'rand', // Random order
'tax_query' => array(
array(
'taxonomy' => 'product_cat',
'field' => 'term_id', // Use "term_id" as per your comment
'terms' => $category_id,
'include_children' => true,
),
),
) );
// Switch back to the site's default language
do_action('wpml_switch_language', ICL_LANGUAGE_CODE);
if ( count($posts_ids) > 0 ) {
fwrite($log_handle, date('[d-M-Y H:i:s]') . " Product IDs Retrieved from Category ID {$category_id}: " . implode(', ', $posts_ids) . PHP_EOL);
// Calculate the number of products to apply discounts to (25% of total)
$discount_count = ceil(0.25 * count($posts_ids));
// Loop through product Ids
foreach ($posts_ids as $post_id) {
$product = wc_get_product($post_id); // Get the product object
// Reset sale price from discounted products only
if ( $product->get_sale_price() > 0 ) {
$reg_price = $product->get_regular_price(); // Get regular price
$product->set_price($reg_price); // Set back the regular price
// Clear sale price
$product->set_sale_price('');
$product->set_date_on_sale_from('');
$product->set_date_on_sale_to('');
$product->save(); // Save the product to trigger WooCommerce cache refresh
do_action( 'wpml_sync_custom_field', $post_id, '_price' ); // Refresh price for translations
do_action( 'wpml_sync_custom_field', $post_id, '_sale_price' ); // Refresh sale price for translations
do_action( 'wpml_sync_custom_field', $post_id, '_sale_price_dates_from' ); // Refresh field for translations
do_action( 'wpml_sync_custom_field', $post_id, '_sale_price_dates_to' ); // Refresh field for translations
// Log the action in the log file
fwrite($log_handle, date('[d-M-Y H:i:s]') . " Cleared discount for Product ID: {$post_id}" . PHP_EOL);
}
}
// Apply discounts to a random 25% of products
for ($i = 0; $i < $discount_count; $i++) {
$post_id = $posts_ids[$i];
$product = wc_get_product($posts_ids[$i]); // Get the product object
$reg_price = $product->get_regular_price(); // Get regular price
$sale_price = $reg_price * 0.9; // Calculate 10% discount
// Set the new discount price (sale price)
$product->set_price($sale_price);
$product->set_sale_price($sale_price);
$product->set_date_on_sale_from(time());
$product->save(); // Save the product to trigger WooCommerce cache refresh
do_action( 'wpml_sync_custom_field', $post_id, '_price' ); // Refresh price for translations
do_action( 'wpml_sync_custom_field', $post_id, '_sale_price' ); // Refresh sale price for translations
do_action( 'wpml_sync_custom_field', $post_id, '_sale_price_dates_from' ); // Refresh field for translations
do_action( 'wpml_sync_custom_field', $post_id, '_sale_price_dates_to' ); // Refresh field for translations
// Log the action in the log file with the new price
fwrite($log_handle, date('[d-M-Y H:i:s]') . " Applied discount for Product ID: {$post_id}, New Price: {$sale_price}" . PHP_EOL);
}
}
// Log a timestamp indicating the completion of the custom function
fwrite($log_handle, date('[d-M-Y H:i:s]') . " Custom function completed." . PHP_EOL);
fclose($log_handle); // Close the log file
}
}
Another failed attempt
// Define a custom 1-minute interval
function custom_1_minute_interval($schedules) {
$schedules['1minute'] = array(
'interval' => 60, // 1 minute in seconds
'display' => __('Every 1 Minute'),
);
return $schedules;
}
add_filter('cron_schedules', 'custom_1_minute_interval');
// Schedule the event to run the custom function every 1 minute
add_action('init', 'schedule_custom_function');
function schedule_custom_function() {
if (!wp_next_scheduled('every_1_minute_custom_function')) {
wp_schedule_event(time(), '1minute', 'every_1_minute_custom_function');
}
}
add_action('every_1_minute_custom_function', 'custom_function_to_manage_discounts');
function custom_function_to_manage_discounts() {
// Define the log file
$log_file = WP_CONTENT_DIR . '/promo.log';
// Open the log file for writing (creates a new file if it doesn't exist)
$log_handle = fopen($log_file, 'a');
// Check if the log file was successfully opened
if ($log_handle) {
// Log a timestamp indicating the start of the custom function
fwrite($log_handle, date('[d-M-Y H:i:s]') . " Custom function started." . PHP_EOL);
// Get all products in category ID 2465 in the Polish language version
$category_id = 2465; // Category ID
$language_code = 'pl'; // Language code for Polish
$posts_ids = get_posts( array(
'post_type' => 'product',
'post_status' => 'publish',
'posts_per_page' => -1,
'fields' => 'ids',
'orderby' => 'rand',
'tax_query' => array(
array(
'taxonomy' => 'product_cat',
'field' => 'term_id',
'terms' => $category_id,
'include_children' => true,
),
),
'lang' => $language_code, // Specify the language code
) );
if ( count($posts_ids) > 0 ) {
fwrite($log_handle, date('[d-M-Y H:i:s]') . " Product IDs Retrieved from Category ID {$category_id} (Polish version): " . implode(', ', $posts_ids) . PHP_EOL);
// Loop through product Ids
foreach ($posts_ids as $post_id) {
// Get the default language of the site
$default_site_language = apply_filters('wpml_default_language', NULL);
// Get the product's default language
$product_default_language = apply_filters('wpml_element_language_code', NULL, array(
'element_id' => $post_id,
'element_type' => 'post_product'
));
// Check if the product's default language is different from the site's default language
if ($product_default_language !== $default_site_language) {
// The product's default language is different, so you can get its language ID
$product_language_id = apply_filters('wpml_get_language_id', NULL, array(
'code' => $product_default_language
));
// Log the product's language ID
fwrite($log_handle, date('[d-M-Y H:i:s]') . " Product Language ID (Product ID: {$post_id}): $product_language_id" . PHP_EOL);
} else {
// Log that the product is in the site's default language
fwrite($log_handle, date('[d-M-Y H:i:s]') . " Product (ID: {$post_id}) is in the site's default language." . PHP_EOL);
}
$product = wc_get_product($post_id); // Get the product object
// Reset sale price from discounted products only
if ( $product->get_sale_price() > 0 ) {
$reg_price = $product->get_regular_price(); // get regular price
$product->set_price($reg_price); // Set back the regular price
// Clear sale price
$product->set_sale_price('');
$product->set_date_on_sale_from('');
$product->set_date_on_sale_to('');
$product->save(); // Save the product to trigger WooCommerce cache refresh
do_action( 'wpml_sync_custom_field', $post_id, '_price' ); // refresh price for translations
do_action( 'wpml_sync_custom_field', $post_id, '_sale_price' ); // refresh sale price for translations
do_action( 'wpml_sync_custom_field', $post_id, '_sale_price_dates_from' ); // refresh field for translations
do_action( 'wpml_sync_custom_field', $post_id, '_sale_price_dates_to' ); // refresh field for translations
// Log the action in the log file
fwrite($log_handle, date('[d-M-Y H:i:s]') . " Cleared discount for Product ID: {$post_id}" . PHP_EOL);
}
}
// Calculate the number of products to apply discounts to (25% of total)
$discount_count = ceil(0.25 * count($posts_ids));
// Shuffle the products array randomly
shuffle($posts_ids);
// Apply discounts to a random 25% of products
for ($i = 0; $i < $discount_count; $i++) {
$post_id = $posts_ids[$i];
$product = wc_get_product($posts_ids[$i]); // Get the product object
$reg_price = $product->get_regular_price(); // get regular price
$sale_price = $reg_price * 0.9; // Calculate 10% discount
// Set the new discount price (sale price)
$product->set_price($sale_price);
$product->set_sale_price($sale_price);
$product->set_date_on_sale_from(time());
$product->save(); // Save the product to trigger WooCommerce cache refresh
do_action( 'wpml_sync_custom_field', $post_id, '_price' ); // refresh price for translations
do_action( 'wpml_sync_custom_field', $post_id, '_sale_price' ); // refresh sale price for translations
do_action( 'wpml_sync_custom_field', $post_id, '_sale_price_dates_from' ); // refresh field for translations
do_action( 'wpml_sync_custom_field', $post_id, '_sale_price_dates_to' ); // refresh field for translations
// Log the action in the log file with the new price
fwrite($log_handle, date('[d-M-Y H:i:s]') . " Applied discount for Product ID: {$post_id}, New Price: {$sale_price}" . PHP_EOL);
}
}
// Log a timestamp indicating the completion of the custom function
fwrite($log_handle, date('[d-M-Y H:i:s]') . " Custom function completed." . PHP_EOL);
fclose($log_handle); // Close the log file
}
}
There are some few mistakes in your code.
I have first started searching in WPML website and I came across multiple support thread related product (or post) syncing translations:
The action hook to be used is wpml_sync_all_custom_fields
to refresh/sync all the metadata from the translations of a post (or a product).
Then searching more, I found wpml_sync_custom_field
hook that allows to "Sync custom field value across all translations of a given post".
Here is the revisited code version of your main function, that should update/refresh the product translations too (untested):
add_action('every_1_minute_custom_function', 'custom_function_to_manage_discounts');
function custom_function_to_manage_discounts() {
// Define the log file
$log_file = WP_CONTENT_DIR . '/promo.log';
// Open the log file for writing (creates a new file if it doesn't exist)
$log_handle = fopen($log_file, 'a');
// Check if the log file was successfully opened
if ($log_handle) {
// Log a timestamp indicating the start of the custom function
fwrite($log_handle, date('[d-M-Y H:i:s]') . " Custom function started." . PHP_EOL);
// Get all products in category ID 29 for the original language version
$category_id = array(29); // <== Changed variable as an array
$posts_ids = get_posts( array(
'post_type' => 'product',
'post_status' => 'publish', // <== Added (published products only)
'posts_per_page' => -1,
'fields' => 'ids', // <== Get an array of product IDs
'orderby' => 'rand', // <== Random order (replace shuffle)
'tax_query' => array(
array(
'taxonomy' => 'product_cat',
'field' => 'term_id', // <== Mistake corrected (not 'id')
'terms' => $category_id,
'include_children' => true,
),
),
) );
if ( count($posts_ids) > 0 ) {
fwrite($log_handle, date('[d-M-Y H:i:s]') . " Product IDs Retrieved from Category ID {$category_id}: " . implode(', ', $posts_ids) . PHP_EOL);
// Calculate the number of products to apply discounts to (25% of total)
$discount_count = ceil(0.25 * count($posts_ids));
// Loop through product Ids
foreach ($posts_ids as $post_id) {
$product = wc_get_product($post_id); // Get the product object
// Reset sale price from discounted products only
if ( $product->get_sale_price() > 0 ) {
$reg_price = $product->get_regular_price(); // get regular price
$product->set_price($reg_price); // Set back the regular price
// Clear sale price
$product->set_sale_price('');
$product->set_date_on_sale_from('');
$product->set_date_on_sale_to('');
$product->save(); // Save the product to trigger WooCommerce cache refresh
do_action( 'wpml_sync_custom_field', $post_id, '_price' ); // refresh price for translations
do_action( 'wpml_sync_custom_field', $post_id, '_sale_price' ); // refresh sale price for translations
do_action( 'wpml_sync_custom_field', $post_id, '_sale_price_dates_from' ); // refresh field for translations
do_action( 'wpml_sync_custom_field', $post_id, '_sale_price_dates_to' ); // refresh field for translations
// Log the action in the log file
fwrite($log_handle, date('[d-M-Y H:i:s]') . " Cleared discount for Product ID: {$post_id}" . PHP_EOL);
}
}
// Apply discounts to a random 25% of products
for ($i = 0; $i < $discount_count; $i++) {
$post_id = $posts_ids[$i];
$product = wc_get_product($posts_ids[$i]); // Get the product object
$reg_price = $product->get_regular_price(); // get regular price
$sale_price = $reg_price * 0.9; // Calculate 10% discount
// Set the new discount price (sale price)
$product->set_price($sale_price);
$product->set_sale_price($sale_price);
$product->set_date_on_sale_from(time());
$product->save(); // Save the product to trigger WooCommerce cache refresh
do_action( 'wpml_sync_custom_field', $post_id, '_price' ); // refresh price for translations
do_action( 'wpml_sync_custom_field', $post_id, '_sale_price' ); // refresh sale price for translations
do_action( 'wpml_sync_custom_field', $post_id, '_sale_price_dates_from' ); // refresh field for translations
do_action( 'wpml_sync_custom_field', $post_id, '_sale_price_dates_to' ); // refresh field for translations
// Log the action in the log file with the new price
fwrite($log_handle, date('[d-M-Y H:i:s]') . " Applied discount for Product ID: {$post_id}, New Price: {$sale_price}" . PHP_EOL);
}
}
// Log a timestamp indicating the completion of the custom function
fwrite($log_handle, date('[d-M-Y H:i:s]') . " Custom function completed." . PHP_EOL);
fclose($log_handle); // Close the log file
}
}
Code goes in functions.php file of your child theme (or in a plugin). It may work.
Addition - WPML: Get the post IDs of the translations from a post ID
Using the code from "get all other languages for a post", you can get the translated product ids from the parent Id. I have embedded the code in a separate reusable function:
function get_wpml_translated_post_ids( $post_id ) {
$type = apply_filters( 'wpml_element_type', get_post_type( $post_id ) );
$trid = apply_filters( 'wpml_element_trid', false, $post_id, $type );
$product_ids = [];
$translations = apply_filters( 'wpml_get_element_translations', array(), $trid, $type );
foreach ( $translations as $lang => $data ) {
$product_ids[] = $data->element_id;
}
return $product_ids;
}
Code goes in functions.php file of your child theme (or in a plugin).