如何在wooccommerce后台实现按发货方式过滤


How to implement a filter by shipping method in woocommerce backend?

我需要在wooccommerce后端实现一个过滤器,我可以使用它来根据所选的运输方法过滤订单。

我可以在自定义字段上创建一个过滤器并更改查询,但问题是wooccommerce将运输方法存储在DB的自定义表中。

关于如何实现这个过滤器,有什么提示吗?

我解决了添加下拉菜单的问题,使用这个钩子:

add_action( 'restrict_manage_posts', 'display_shipping_dropdown' );

然后使用另一个钩子来扩展where子句:

add_filter( 'posts_where', 'admin_shipping_filter', 10, 2 );
function admin_shipping_filter( $where, &$wp_query )
{
    global $pagenow;
    $method = $_GET['shipping_filter'];
    if ( is_admin() && $pagenow=='edit.php' && $wp_query->query_vars['post_type'] == 'shop_order' && !empty($method) ) {
        $where .= $GLOBALS['wpdb']->prepare( 'AND ID
                            IN (
                                SELECT order_id
                                FROM wp_woocommerce_order_items
                                WHERE order_item_type = "shipping"
                                AND order_item_name = "' . $method . '"
                            )' );
    }
    return $where;
}

要完成洛伦佐的答案,这里有一个函数可以用来生成过滤器html:

function display_shipping_dropdown(){
    if (is_admin() && !empty($_GET['post_type']) && $_GET['post_type'] == 'shop_order'){
        $exp_types = array();
        $zones = WC_Shipping_Zones::get_zones();
        foreach($zones as $z) {
            foreach($z['shipping_methods'] as $method) {
                $exp_types[] = $method->title;
            }
        }
        ?>
        <select name="shipping_method">
            <option value=""><?php _e('Filter par expédition', 'woocommerce'); ?></option>
            <?php
            $current_v = isset($_GET['shipping_method']) ? $_GET['shipping_method'] : '';
            foreach ($exp_types as $label) {
                printf
                (
                    '<option value="%s"%s>%s</option>',
                    $label,
                    $label == $current_v? ' selected="selected"':'',
                    $label
                );
            }
            ?>
        </select>
        <?php
    }
}
add_action( 'restrict_manage_posts', 'display_shipping_dropdown' );

在Lorenzo的解决方案中,如果运输方法的标题发生更改,则算法将失败。(在我的例子中是通过插件动态地)。

使用instance_id而不是title将避免这种情况。

add_action( 'restrict_manage_posts', function () {
    if ( is_admin() && ! empty( $_GET['post_type'] ) && $_GET['post_type'] == 'shop_order' ) {
        $exp_types = array();
        $zones     = WC_Shipping_Zones::get_zones();
        foreach ( $zones as $z ) {
            foreach ( $z['shipping_methods'] as $method ) {
                $exp_types[ $method->instance_id ] = $method->title;
            }
        }
        ?>
        <select name="shipping_method">
            <option value=""><?php _e( 'Shipping filter' ); ?></option>
            <?php
            $current_v = isset( $_GET['shipping_method'] ) ? $_GET['shipping_method'] : '';
            foreach ( $exp_types as $key => $label ) {
                printf( '<option value="%s"%s>%s</option>', $key, $key == $current_v ? ' selected="selected"' : '', $label );
            }
            ?>
        </select>
        <?php
    }
} );
add_filter( 'posts_where', function ( $where, &$wp_query ) {
    global $pagenow, $wpdb;
    $method = isset( $_GET['shipping_method'] ) ? $_GET['shipping_method'] : false;
    if ( is_admin() && $pagenow == 'edit.php' && $wp_query->query_vars['post_type'] == 'shop_order' && ! empty( $method ) ) {
        $where .= $wpdb->prepare( "AND ID
IN (
 SELECT order_id
 FROM {$wpdb->prefix}woocommerce_order_itemmeta m
 LEFT JOIN {$wpdb->prefix}woocommerce_order_items i 
  ON i.order_item_id = m.order_item_id
 WHERE meta_key = 'instance_id' and meta_value = '{$method}' )" );
    }
    return $where;
}, 10, 2 );

如果你结合MrSwed和Lorenzo的代码,你会得到这个(如果我错了,请纠正我,但它对我有效):

if ( is_admin()) {
add_filter( 'posts_where', 'admin_shipping_filter', 10, 2 );
function admin_shipping_filter( $where, $wp_query )
{
global $pagenow;
$method = $_GET['shipping_method'];
if ( is_admin() && $pagenow=='edit.php' && $wp_query->query_vars['post_type'] == 'shop_order' && !empty($method) ) {
    $where .= $GLOBALS['wpdb']->prepare( 'AND ID
                        IN (
                            SELECT order_id
                            FROM wp_woocommerce_order_items
                            WHERE order_item_type = "shipping"
                            AND order_item_name = "' . $method . '"
                        )' );
}
return $where;
}
function display_shipping_dropdown(){
if (is_admin() && !empty($_GET['post_type']) && $_GET['post_type'] == 'shop_order'){
    $exp_types = array();
    $zones = WC_Shipping_Zones::get_zones();
    foreach($zones as $z) {
        foreach($z['shipping_methods'] as $method) {
            $exp_types[ $method->instance_id ] = $method->title;
        }
    }
    ?>
    <select name="shipping_method">
        <option value=""><?php _e('Filter Shipping', 'woocommerce'); ?></option>
        <?php
        $current_v = isset($_GET['shipping_method']) ? $_GET['shipping_method'] : '';
        foreach ($exp_types as $label) {
            printf
            (
                '<option value="%s"%s>%s</option>',
                $label,
                $label == $current_v? ' selected="selected"':'',
                $label
            );
        }
        ?>
    </select>
    <?php
    }
}
add_action( 'restrict_manage_posts', 'display_shipping_dropdown' );
}