Woocommerce 产品排序未按预期工作

问题描述 投票:0回答:1

我开发了自定义插件,为我的网站用户提供对产品投赞成票/反对票的功能,并且根据投票权重,该插件会将较高排名产品的价格提高到 10000,将最低排名提高到 1 以及介于两者之间的所有其他产品。此功能按预期工作,但有一个小问题,在更新每个价格后,在商店和仪表板/产品部分中,产品排序顺序行为不正确。假设 1 美元的产品更改为 10000,那么它现在应该转到升序的最后一个位置,但它仍然在同一位置。我做了很多调试,发现了这两条线索 1.手动更新价格排序反映正确且立即。 2. 在插件更新的产品上,当我手动重新生成查找表但我想自动化该过程时,排序顺序会更正。

我已添加这样做,但网站的行为陈旧且相同,需要帮助来解决此问题。这是主要代码

<?php

if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

class WC_Vote_Price {

    private static $instance = null;

    public static function instance() {
        if ( is_null( self::$instance ) ) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    public function __construct() {
        add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
        add_action( 'woocommerce_single_product_summary', array( $this, 'display_vote_buttons' ), 25 );
        add_action( 'wp_ajax_wc_vote_price', array( $this, 'handle_vote' ) );
        add_action( 'wp_ajax_nopriv_wc_vote_price', array( $this, 'handle_vote' ) );
        add_action( 'admin_menu', array( $this, 'add_settings_page' ) );
        add_action( 'admin_post_wc_vote_price_reset', array( $this, 'handle_reset' ) );
        add_filter( 'woocommerce_get_price_html', array( $this, 'custom_woocommerce_get_price_html'), 10, 2 );
        add_action('save_post_product', array($this, 'handle_product_price_update'), 10, 3);
    }

    public function handle_product_price_update($post_id, $post, $update) {
        if ($post->post_type !== 'product') {
            return;
        }

        // Ensure we only run on price updates
        if (isset($_POST['meta_input'])) {
            $meta_input = $_POST['meta_input'];
            if (isset($meta_input['_price'])) {
                try {
                    wc_update_product_lookup_tables();
                    wc_delete_product_transients(); // Clear WooCommerce product cache
                    
                    // Forcefully regenerate lookup tables
                    wc_get_container()->get( \Automattic\WooCommerce\Internal\Product\Lookup\LookupDataStore::class )->regenerate();
                    
                } catch (Exception $e) {
                    error_log('Error updating lookup tables: ' . $e->getMessage());
                }
            }
        }
    }

    public function enqueue_scripts() {
        wp_enqueue_style( 'wc-vote-price-style', plugins_url( '../assets/css/style.css', __FILE__ ) );
        wp_enqueue_script( 'wc-vote-price-script', plugins_url( '../assets/js/script.js', __FILE__ ), array( 'jquery' ), null, true );
        wp_localize_script( 'wc-vote-price-script', 'wc_vote_price_params', array(
            'ajax_url' => admin_url( 'admin-ajax.php' ),
            'nonce'    => wp_create_nonce( 'wc-vote-price-nonce' )
        ) );
    }

    public function display_vote_buttons() {
        global $product;

        $votes = get_post_meta( $product->get_id(), '_wc_vote_price_votes', true ) ?: 0;
        $downvotes = get_post_meta( $product->get_id(), '_wc_vote_price_downvotes', true ) ?: 0;

        $user_ip = $_SERVER['REMOTE_ADDR'];
        $voted_up = get_post_meta( $product->get_id(), '_wc_vote_price_voted_up_' . $user_ip, true );
        $voted_down = get_post_meta( $product->get_id(), '_wc_vote_price_voted_down_' . $user_ip, true );

        $upvote_class = $voted_up ? 'voted' : '';
        $downvote_class = $voted_down ? 'voted' : '';

        echo '<div class="wc-vote-price">';
        echo '<button class="vote-button ' . esc_attr( $upvote_class ) . '" data-vote="up" data-product="' . esc_attr( $product->get_id() ) . '">Vote Up (' . esc_html( $votes ) . ')</button>';
        echo '<button class="vote-button ' . esc_attr( $downvote_class ) . '" data-vote="down" data-product="' . esc_attr( $product->get_id() ) . '">Vote Down (' . esc_html( $downvotes ) . ')</button>';
        echo '</div>';
        echo '<div id="loading-overlay"><div class="loading-message">Your vote is being processed<span class="dots"><span></span><span></span><span></span></span></div></div>';
    }

    public function handle_vote() {
        check_ajax_referer( 'wc-vote-price-nonce', 'nonce' );

        if ( ! isset( $_POST['product_id'], $_POST['vote_type'] ) ) {
            wp_send_json_error( 'Invalid data' );
        }

        $product_id = absint( $_POST['product_id'] );
        $vote_type = sanitize_text_field( $_POST['vote_type'] );

        $user_ip = $_SERVER['REMOTE_ADDR'];
        $voted_up = get_post_meta( $product_id, '_wc_vote_price_voted_up_' . $user_ip, true );
        $voted_down = get_post_meta( $product_id, '_wc_vote_price_voted_down_' . $user_ip, true );

        $votes = get_post_meta( $product_id, '_wc_vote_price_votes', true ) ?: 0;
        $downvotes = get_post_meta( $product_id, '_wc_vote_price_downvotes', true ) ?: 0;

        if ( $vote_type === 'up' ) {
            if ( $voted_up ) {
                $votes--;
                delete_post_meta( $product_id, '_wc_vote_price_voted_up_' . $user_ip );
            } else {
                if ( $voted_down ) {
                    $downvotes--;
                    delete_post_meta( $product_id, '_wc_vote_price_voted_down_' . $user_ip );
                }
                $votes++;
                update_post_meta( $product_id, '_wc_vote_price_voted_up_' . $user_ip, true );
            }
        } elseif ( $vote_type === 'down' ) {
            if ( $voted_down ) {
                $downvotes--;
                delete_post_meta( $product_id, '_wc_vote_price_voted_down_' . $user_ip );
            } else {
                if ( $voted_up ) {
                    $votes--;
                    delete_post_meta( $product_id, '_wc_vote_price_voted_up_' . $user_ip );
                }
                $downvotes++;
                update_post_meta( $product_id, '_wc_vote_price_voted_down_' . $user_ip, true );
            }
        }

        update_post_meta( $product_id, '_wc_vote_price_votes', $votes );
        update_post_meta( $product_id, '_wc_vote_price_downvotes', $downvotes );

        // Trigger price adjustment
        $this->adjust_product_prices();
        wc_delete_product_transients();

        wp_send_json_success( array( 'votes' => $votes, 'downvotes' => $downvotes ) );
    }

    private function adjust_product_prices() {
        global $wpdb;

        // Fetch all products and their votes
        $products = $wpdb->get_results("
            SELECT p.ID, COALESCE(v.meta_value, 0) AS votes
            FROM {$wpdb->posts} p
            LEFT JOIN {$wpdb->postmeta} v ON p.ID = v.post_id AND v.meta_key = '_wc_vote_price_votes'
            WHERE p.post_type = 'product' AND p.post_status = 'publish'
            ORDER BY votes DESC, p.ID ASC
        ");

        $max_price = 10000;
        $min_price = 1;
        $price_range = $max_price - $min_price;
        $num_products = count($products);

        if ($num_products == 0) {
            return; // No products to adjust
        }

        $rank = 0;
        foreach ($products as $product) {
            $sale_price = $max_price - ($rank * $price_range / ($num_products - 1));
            $sale_price = round($sale_price);
            $regular_price = $sale_price + 1;

            // Update sale price and regular price
            $wpdb->update(
                $wpdb->postmeta,
                array( 'meta_value' => $sale_price ),
                array( 'post_id' => $product->ID, 'meta_key' => '_sale_price' ),
                array( '%d' ),
                array( '%d', '%s' )
            );
            $wpdb->update(
                $wpdb->postmeta,
                array( 'meta_value' => $regular_price ),
                array( 'post_id' => $product->ID, 'meta_key' => '_regular_price' ),
                array( '%d' ),
                array( '%d', '%s' )
            );

            update_post_meta($product->ID, '_price', $sale_price);
            update_post_meta($product->ID, '_wc_vote_price_adjusted_price', $sale_price);
            $rank++;

            // Logging the price update
            error_log("Updating product ID {$product->ID} to sale price {$sale_price} and regular price {$regular_price}");
        }

        wc_delete_product_transients();

        // Clear sorting transients
      $transients = array(
         'wc_products_onsale',
            'wc_layered_nav_counts',
           'wc_products_will_display',
           'wc_hidden_term_ids'
      );

      foreach ( $transients as $transient ) {
         delete_transient( $transient );
     }

      // Ensure the class exists before regenerating lookup tables
    if (class_exists('Automattic\WooCommerce\Internal\Product\Lookup\LookupDataStore')) {
        try {
            wc_get_container()->get( \Automattic\WooCommerce\Internal\Product\Lookup\LookupDataStore::class )->regenerate();
        } catch (Exception $e) {
            error_log('Error regenerating lookup tables: ' . $e->getMessage());
        }
    } else {
        error_log('LookupDataStore class does not exist.');
    }
}

    public function custom_woocommerce_get_price_html($price, $product) {
        $adjusted_price = get_post_meta($product->get_id(), '_wc_vote_price_adjusted_price', true);
        if ($adjusted_price) {
            $price = wc_price($adjusted_price);
        }
        return $price;
    }

    public function add_settings_page() {
        add_menu_page(
            'WC Vote Price Settings',
            'Vote Price',
            'manage_options',
            'wc-vote-price',
            array( $this, 'settings_page_content' ),
            'dashicons-thumbs-up',
            56
        );
    }

    public function settings_page_content() {
        ?>
        <div class="wrap">
            <h1>Vote Price Settings</h1>
            <form action="admin-post.php" method="post">
                <input type="hidden" name="action" value="wc_vote_price_reset">
                <button type="submit" class="button button-primary">Reset All Votes</button>
            </form>
        </div>
        <?php
    }

    public function handle_reset() {
        if ( ! current_user_can( 'manage_options' ) ) {
            return;
        }

        global $wpdb;

        $wpdb->query("
            DELETE FROM {$wpdb->postmeta}
            WHERE meta_key IN ('_wc_vote_price_votes', '_wc_vote_price_downvotes')
        ");

        $wpdb->query("
            DELETE FROM {$wpdb->postmeta}
            WHERE meta_key LIKE '_wc_vote_price_voted_%'
        ");

        // Reset prices
        $this->adjust_product_prices();

        // Redirect back to the settings page
        wp_redirect( admin_url( 'admin.php?page=wc-vote-price&reset=true' ) );
        exit;
    }
}

WC_Vote_Price::instance();

?>

我已停用所有插件,使用主题二十二十四。

wordpress woocommerce plugins hook-woocommerce
1个回答
0
投票

在尝试重新生成查找表和清除瞬态时,您似乎走在正确的轨道上,但可能有一些地方可能需要调整或更改,以确保产品排序正确更新。

您可以使用

woocommerce_update_product
操作而不是
save_post_product
。此操作专门用于管理产品数据的更改。

add_action('woocommerce_update_product', array($this,'handle_product_price_update'), 10, 1);

这可确保您的代码在产品数据更新(包括价格变化)时运行。

既然您注意到手动更新可以正常工作,请确保您的

adjust_product_prices
方法可以正确处理数据库更新。如果操作不正确,立即更新数据库可能会导致差异。确保所有相关元键
(_price, _sale_price, and _regular_price)
均已正确更新。

由于您已禁用其他插件并使用默认主题,请确保不存在可能影响排序的剩余自定义或覆盖。自定义主题或代码可能会影响 WooCommerce 的排序方式。

© www.soinside.com 2019 - 2024. All rights reserved.