将 WooCommerce 产品销售价格复制为正常价格并重置销售价格

Copy WooCommerce products Sale prices to regular prices and reset Sale prices

我想用促销价值替换我的 WooCommerce 商店中的所有常规价格,并删除 wp_postmeta table 下的促销价值.

post_id 列对于每种产品的两种价格都是相同的,要复制的列是 _sale_price_price 并删除 _sale_price

我 运行 可以用什么查询来实现?

这是一个自定义函数,可以将促销价复制到正常价格并重置促销 price.Regarding WooCommerce 中的价格有:

  • 有效价格:'_price'
  • 正常价格:'_regular_price'
  • 售价:'_sale_price'

因此您也需要更新正常价格并重置促销价的所有相关数据。还需要刷新价格。
此功能有一个 UI 将出现在商店页面或单个产品页面中 仅供管理员和商店经理使用

If you have more than 1000 products, the process will be auto split in multiple steps (by 1000 products) to avoid errors when there is too many products.

SQL 查询只会 select 有促销价的产品 ID,而不是所有产品。对于 update/Reset 价格,我使用 update_post_meta() 函数而不是查询来刷新每个产品缓存...

看起来像:

  • 开始更新价格(第一步):

  • 继续必要的步骤:

  • 价格更新完成(结束画面):

Important: Before starting this kind of process always make a database backup

这是钩子函数代码:

add_action( 'woocommerce_before_main_content', function(){

    // Only admins and shop manargers
    if( ! current_user_can( 'edit_products' ) ) return;

    global $wpdb;
    $products_count = get_option( 'product_prices_update_count' );

    // Auto enable multistep price updates for more than 1000 products
    $limit = $products_count > 2 ? 2 : false;

    if( $limit != false )
        $offset = get_option( 'product_prices_update_offset' );

    if( empty( $offset ) && $limit != false ) {
        $offset = 0;
        add_option( 'product_prices_update_offset', $offset );
    }

    $control_process = $limit != false ? "LIMIT $offset, $limit" : "";

    if( ! isset( $_POST['prices_updates'] ) ) $control_process = '';

    // 1. First query: Get for all product ids the sale price
    $results = $wpdb->get_results( "
        SELECT  postmeta.post_id, postmeta.meta_value as price
        FROM {$wpdb->prefix}postmeta as postmeta
        INNER JOIN {$wpdb->prefix}posts as posts ON postmeta.post_id = posts.ID
        WHERE posts.post_type LIKE '%product%'
        AND postmeta.meta_key = '_sale_price'
        AND postmeta.meta_value != ''
        ORDER BY posts.ID ASC
        $control_process
    " );

    if( empty( $products_count ) ){
        update_option( 'product_prices_update_count', count($results) );
        $count = count($results);
    } else $count = $products_count;

    $remaining = ! empty( $products_count ) && $limit != false ? $count-($offset+$limit) : count($results);

    $products_updated = 0;

    echo '<div style="border: solid 1px grey; padding: 16px; margin-bottom: 12px;)">
    <form class="cart" method="post" enctype="multipart/form-data">';

    if( isset( $_POST['prices_updates'] ) && ( $remaining > 0 || ! $limit ) ){

        foreach($results as $result){

            $post_id  = $result->post_id;
            $price    = $result->price;

            // 2. Updating Active and Regular prices
            update_post_meta( $post_id, '_price', $price );
            update_post_meta( $post_id, '_regular_price', $price );

            // 3. Reset Sale price
            update_post_meta( $post_id, '_sale_price', '' );
            update_post_meta( $post_id, '_sale_price_dates_from', '');
            update_post_meta( $post_id, '_sale_price_dates_to', '');

            // 4. Refresh product cache
            wc_delete_product_transients($post_id);

            $products_updated++;
           // echo "$post_id ($products_updated), ";
        }
    }

    if( ( ! $limit && ! empty( $products_count ) ) || $remaining <= 0 ){
        echo "<p><strong>Process is now finished.</strong><br>
        <em>You can remove or comment the code, Thanks</em></p>";
        if( isset($_POST['prices_updates'] ) ){
            delete_option( 'product_prices_update_offset' );
            delete_option( 'product_prices_update_count' );
        }
    } else {
        if( isset( $_POST['prices_updates'] ) ){
            update_option( 'product_prices_update_offset', $offset+$limit );
            echo "<p>$products_updated products have been updated.<br>";
            echo "There is still $remaining remaining products to update.</p>";
        } else
            echo "<p>There is $remaining  products to update.</p>";

        $value = empty( $products_count ) ? "Start update" : "Continue update";
        echo '<input type="submit" class="button" name="prices_updates" value="'.$value.'" />';
    }
    echo '</form></div>';

}, 2, 0);

代码进入您的活动子主题(或主题)的 function.php 文件或任何插件文件。

此代码已经过测试并且有效。

这是您要查找的纯 MySQL 查询:

首先你必须使用自连接来更新_price_regular_price字段

UPDATE `wp_postmeta` AS a,
       `wp_postmeta` AS b
SET a.`meta_value` = b.meta_value
WHERE a.post_id = b.post_id
  AND a.meta_key IN ('_price', '_regular_price')
  AND b.meta_key = '_sale_price'
  AND b.meta_value != ''
  AND a.`post_id` IN
    (SELECT `ID`
     FROM `wp_posts`
     WHERE `post_type` = 'product'
       AND `post_status` = 'publish');

现在要重置促销价和日期,您必须将其设置为空白

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' );

如果你想删除这些字段,那么使用带有 WHERE 子句的 DELETE 语句,它会解决你的目的。

您还必须删除存储在 _transient_timeout_wc_var_prices_{{post_id}} 下的 wp_options table 中的 WooCommerce 产品价格缓存和_transient_wc_var_prices_{{post_id}}option_name

DELETE
FROM `wp_options`
WHERE (`option_name` LIKE '_transient_wc_var_prices_%'
    OR `option_name` LIKE '_transient_timeout_wc_var_prices_%')

特别感谢@LoicTheAztec 指出产品价格缓存

以上查询已经过测试并且对我有效。

在 运行 这个查询之前做一个数据库备份

希望对您有所帮助!