WooCommerce Filter Orders by Item Count - php

Is it possible to create a custom filter in WooCommerce Orders Admin which will allow filtering by the order item count?
We are looking to filter orders with either one item or more than one item (multiple items).
We have the dropdown on the page via the following action and function, but we're stuck on the filter part and how to query each order to find the item count.
add_action( 'restrict_manage_posts', 'filter_multi_item_orders', 50 );
function filter_multi_item_orders() {
global $typenow;
if ( 'shop_order' != $typenow ) {
return;
}?>
<select name='multi_order_view' id='dropdown_multi_order_view'>
<option <?php
if ( isset( $_GET['multi_order_view'] ) && $_GET['multi_order_view'] ) {
selected( 'all', $_GET['multi_order_view'] );
}
?> value="all"><?php esc_html_e( 'Single and Multi Orders', 'show_multipet_orders' ); ?></option>
<option <?php
if ( isset( $_GET['multi_order_view'] ) && $_GET['multi_order_view'] ) {
selected( 'single', $_GET['multi_order_view'] );
}
?>value="single"><?php esc_html_e( 'Single Orders Only', 'show_multipet_orders' ); ?></option>
<option <?php
if ( isset( $_GET['multi_order_view'] ) && $_GET['multi_order_view'] ) {
selected( 'multi', $_GET['multi_order_view'] );
}
?>value="multi"><?php esc_html_e( 'Multi Orders Only', 'show_multipet_orders' ); ?></option>
</select>
<?php
}
add_filter( 'request', 'filter_multi_item_orders_query', 100 );
function filter_multi_item_orders_query( $vars ) {
global $typenow;
$key = 'post__not_in';
if ( 'shop_order' == $typenow && isset( $_GET['multi_order_view'] ) ) {
if ( 'single' == $_GET['multi_order_view'] ) {
// return orders with $order->get_item_count() == 1
}
elseif ( 'multi' == $_GET['multi_order_view'] ) {
// return orders with $order->get_item_count() > 1
}
}
return $vars;
}
This may not be the best/a possible approach but hope someone can shed some light.
Many thanks

Related

How to filter shop orders by the order price

my shop have 3 products with fixed prices ( 0$ , 18$ and 36$ ).
im trying to make a filter in the admin panel that will give me all the orders by a fixed price.
this is what i have tried so far :
/**
* Add price bulk filter for orders
*/
function add_filter_by_payment_price_orders() {
global $typenow;
if ( 'shop_order' === $typenow ) {
$amount_array = array(0,18,36);
?>
<select name="_shop_order_payment_price" id="dropdown_shop_order_payment_price">
<option value=""><?php esc_html_e( 'All Payment prices', 'text-domain' ); ?></option>
<?php foreach ( $amount_array as $key => $amount ) : ?>
<option value="<?php echo esc_attr( $key ); ?>" <?php echo esc_attr( isset( $_GET['_shop_order_payment_price'] ) ? selected( $key, $_GET['_shop_order_payment_price'], false ) : '' ); ?>>
<?php echo $amount ; ?>
</option>
<?php endforeach; ?>
</select>
<?php
}
}
add_action( 'restrict_manage_posts', 'add_filter_by_payment_price_orders', 99 );
/**
* Process bulk filter order for payment method
*
*/
function add_filter_by_payment_price_orders_query( $vars ) {
global $typenow;
if ( 'shop_order' === $typenow && isset( $_GET['_shop_order_payment_price'] ) ) {
$vars['meta_key'] = 'total';
$vars['meta_value'] = wc_clean( $_GET['_shop_order_payment_price'] );
}
return $vars;
}
add_filter( 'request', 'add_filter_by_payment_price_orders_query', 99 );
/**
* Add price bulk filter for orders
*/
function add_filter_by_payment_price_orders() {
global $typenow;
if ( 'shop_order' === $typenow ) {
$amount_array = array(0,18,36);
?>
<select name="_shop_order_payment_price" id="dropdown_shop_order_payment_price">
<option value=""><?php esc_html_e( 'All Payment prices', 'text-domain' ); ?></option>
<?php foreach ( $amount_array as $key => $amount ) : ?>
<option value="<?php echo esc_attr( $amount); ?>" <?php echo esc_attr( isset( $_GET['_shop_order_payment_price'] ) ? selected( $key, $_GET['_shop_order_payment_price'], false ) : '' ); ?>>
<?php echo $amount ; ?>
</option>
<?php endforeach; ?>
</select>
<?php
}
}
add_action( 'restrict_manage_posts', 'add_filter_by_payment_price_orders', 99 );
/**
* Process bulk filter order for payment method
*
*/
function add_filter_by_payment_price_orders_query( $vars ) {
global $typenow;
if ( 'shop_order' === $typenow && isset( $_GET['_shop_order_payment_price'] ) ) {
$vars['meta_key'] = '_order_total';
$vars['meta_value'] = wc_clean( $_GET['_shop_order_payment_price'] );
}
return $vars;
}
add_filter( 'request', 'add_filter_by_payment_price_orders_query', 99 );

Filter orders by specific meta fields in WooCommerce admin orders list

Can anyone let me know, how can i add / set filter by company name in woo-commerce order page.
and please share functions or show my error so i can solved it.
i tried it but not working. you help is much appreciated.
add_action( 'restrict_manage_posts', 'admin_shop_order_by_product_type_filter' );
function admin_shop_order_by_product_type_filter(){
global $pagenow, $post_type;
if( 'shop_order' === $post_type && 'edit.php' === $pagenow ) {
$domain = 'woocommerce';
$filter_id = 'filter_billing_company';
$current = isset($_GET[$filter_id])? $_GET[$filter_id] : '';
$query_args = ['fields' => '_billing_company', 'orderby' => 'order'];
echo "<pre>";print_r(get_terms($query_args)); echo "</pre>";
echo '<select name="'.$filter_id.'">
<option value="">' . __('Filter by Company', $domain) . '</option>';
foreach ( get_terms($query_args) as $term_name ) {
printf( '<option value="%s"%s>%s</option>', $term_name,
$term_name === $current ? '" selected="selected"' : '', ucfirst($term_name) );
}
echo '</select>';
}
}
Thanks
To filter orders by meta fields on admin orders list, you will use the following (where you will define in the 1st function below the metakey / label pairs that will filter orders):
// Custom function where metakeys / labels pairs are defined
function get_filter_shop_order_meta( $domain = 'woocommerce' ){
// Add below the metakey / label pairs to filter orders
return [
'_billing_company' => __('Billing company', $domain),
'_order_total' => __('Gran total', $domain),
];
}
// Add a dropdown to filter orders by meta
add_action( 'restrict_manage_posts', 'display_admin_shop_order_by_meta_filter' );
function display_admin_shop_order_by_meta_filter(){
global $pagenow, $typenow;
if( 'shop_order' === $typenow && 'edit.php' === $pagenow ) {
$domain = 'woocommerce';
$filter_id = 'filter_shop_order_by_meta';
$current = isset($_GET[$filter_id])? $_GET[$filter_id] : '';
echo '<select name="'.$filter_id.'">
<option value="">' . __('Filter by meta…', $domain) . '</option>';
$options = get_filter_shop_order_meta( $domain );
foreach ( $options as $key => $label ) {
printf( '<option value="%s"%s>%s</option>', $key,
$key === $current ? '" selected="selected"' : '', $label );
}
echo '</select>';
}
}
// Process the filter dropdown for orders by Marketing optin
add_filter( 'request', 'process_admin_shop_order_marketing_by_meta', 99 );
function process_admin_shop_order_marketing_by_meta( $vars ) {
global $pagenow, $typenow;
$filter_id = 'filter_shop_order_by_meta';
if ( $pagenow == 'edit.php' && 'shop_order' === $typenow
&& isset( $_GET[$filter_id] ) && ! empty($_GET[$filter_id]) ) {
$vars['meta_key'] = $_GET[$filter_id];
$vars['orderby'] = 'meta_value';
}
return $vars;
}
// (Optional) Make a custom meta field searchable from the admin order list search field
add_filter( 'woocommerce_shop_order_search_fields', 'shop_order_meta_search_fields', 10, 1 );
function shop_order_meta_search_fields( $meta_keys ){
foreach ( get_filter_shop_order_meta() as $meta_key => $label ) {
$meta_keys[] = $meta_key;
}
return $meta_keys;
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.

Show authors only own courses in dropdown

I am using Buddypress groups and part of the Group set up is to associate it to a Post (it's a custom post type called 'course').
The problem is that when associating a group to a particular post, the dropdown shows Authors all sitewide posts, (i.e. including from other authors). I want it so they can only see, and select from, their own posts - i.e. associate their group to one of their posts.
The code that is behind the current dropdown (which shows all authors' posts) is:
<select name="bp_group_course" id="bp-group-course">
<option value="-1"><?php _e( '--Select--', 'buddypress-learndash' ); ?></option>
<?php
foreach ( $courses as $course ) {
$group_attached = get_post_meta( $course->ID, 'bp_course_group', true );
if ( !empty( $group_attached ) && ( '-1' != $group_attached ) && $course->ID != $group_status ) {
continue;
}
?><option value="<?php echo $course->ID; ?>" <?php echo (( $course->ID == $group_status )) ? 'selected' : ''; ?>><?php echo $course->post_title; ?></option><?php
}
?>
</select>
$courses seems to come from:
if ( ! empty( $course_id ) ) {
$courses = array( get_post( $course_id ) );
} elseif ( ! empty( $group_id ) ){
$courses = learndash_group_enrolled_courses( $group_id );
$courses = array_map( 'intval', $courses );
$courses = ld_course_list( array( 'post__in' => $courses, 'array' => true ) );
} else {
$courses = ld_course_list( array( 'array' => true ) );
}
How can I limit it to just the currently logged in user's posts?
Thanks in advance,

Wordpress save only last custom field

I want to have three dropdown list that allow user select Author, Post and Testimonial. But wordpress only save last dropdown.
This is first dropdown:
//allow authors list on posts
add_action( 'add_meta_boxes', 'author_list_add' );
function author_list_add() {
add_meta_box( 'my-meta-box-id', 'Post Author', 'author_list', 'post', 'normal', 'high' );
}
function author_list( $post ) {
$values = get_post_custom( $post->ID );
$selected = isset( $values['custom_author'] ) ? esc_attr( $values['custom_author'][0] ) : '';
wp_nonce_field( 'my_meta_box_nonce', 'meta_box_nonce ');
?>
<p>
<label for="custom_author">Select author</label>
<br>
<select name="custom_author" id="custom_author">
<option value="0" <?php selected( $selected, '0' ); ?>>No author</option>
<?php
$args = array('post_type' => 'member');
$loop = get_posts($args);
foreach ($loop as $post) : setup_postdata($post);
$name = $post->post_title;
$link = $post->ID;
?>
<option value="<?php echo $link; ?>" <?php selected( $selected, $link ); ?>><?php echo $name; ?></option>
<?php
endforeach;
?>
</select>
</p>
<?php
}
add_action( 'save_post', 'author_list_save' );
function author_list_save( $post_id ) {
// Bail if we're doing an auto save
if( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return;
// if our nonce isn't there, or we can't verify it, bail
if( !isset( $_POST['meta_box_nonce'] ) || !wp_verify_nonce( $_POST['meta_box_nonce'], 'my_meta_box_nonce' ) ) return;
// if our current user can't edit this post, bail
if( !current_user_can( 'edit_post' ) ) return;
// now we can actually save the data
$allowed = array(
'a' => array( // on allow a tags
'href' => array() // and those anchords can only have href attribute
)
);
// Probably a good idea to make sure your data is set
if( isset( $_POST['custom_author'] ) )
update_post_meta( $post_id, 'custom_author', esc_attr( $_POST['custom_author'] ) );
}
The second Part:
//allow select testimonial list on posts
add_action( 'add_meta_boxes', 'testimonial_select_box_add' );
$types = array( 'post', 'page' );
function testimonial_select_box_add() {
add_meta_box( 'testimonial-box', 'Testimonial in bottom row', 'testimonial_select_box', $types, 'normal', 'high' );
}
function testimonial_select_box( $post ) {
$values = get_post_custom( $post->ID );
$selected = isset( $values['testimonial_select'] ) ? esc_attr( $values['testimonial_select'][0] ) : '';
wp_nonce_field( 'testimonial_meta_box_nonce', 'meta_box_nonce' );
?>
<p>
<label for="testimonial_select">Select Testimonial</label>
<br>
<select name="testimonial_select" id="testimonial_select">
<option value="0" <?php selected( $selected, '0' ); ?>>None</option>
<?php
$args = array('post_type' => 'testimonial','posts_per_page' => -1);
$loop = get_posts($args);
foreach ($loop as $post) : setup_postdata($post);
$name = $post->post_title;
$link = $post->ID;
?>
<option value="<?php echo $link; ?>" <?php selected( $selected, $link ); ?>><?php echo $name; ?></option>
<?php
endforeach;
?>
</select>
</p>
<?php
}
add_action( 'save_post', 'testimonial_select_box_save' );
function testimonial_select_box_save( $post_id ) {
// Bail if we're doing an auto save
if( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return;
// if our nonce isn't there, or we can't verify it, bail
if( !isset( $_POST['meta_box_nonce'] ) || !wp_verify_nonce( $_POST['meta_box_nonce'], 'testimonial_meta_box_nonce' ) ) return;
// if our current user can't edit this post, bail
if( !current_user_can( 'edit_post' ) ) return;
// now we can actually save the data
$allowed = array(
'a' => array( // on allow a tags
'href' => array() // and those anchords can only have href attribute
)
);
// Probably a good idea to make sure your data is set
if( isset( $_POST['testimonial_select'] ) )
update_post_meta( $post_id, 'testimonial_select', esc_attr( $_POST['testimonial_select'] ) );
}
And last one:
//allow select Post list on posts
add_action( 'add_meta_boxes', 'post_select_box_add' );
function post_select_box_add() {
add_meta_box( 'post-box', 'Post in bottom row', 'post_select_box',$types, 'normal', 'high' );
}
function post_select_box( $post ) {
$values = get_post_custom( $post->ID );
$selected = isset( $values['post_select'] ) ? esc_attr( $values['post_select'][0] ) : '';
wp_nonce_field( 'post_meta_box_nonce', 'meta_box_nonce' );
?>
<p>
<label for="post_select">Select Post</label>
<br>
<select name="post_select" id="post_select">
<option value="0" <?php selected( $selected, '0' ); ?>>None</option>
<?php
$args = array('post_type' => 'post','posts_per_page' => -1);
$loop = get_posts($args);
foreach ($loop as $post) : setup_postdata($post);
$name = $post->post_title;
$link = $post->ID;
?>
<option value="<?php echo $link; ?>" <?php selected( $selected, $link ); ?>><?php echo $name; ?></option>
<?php
endforeach;
?>
</select>
</p>
<?php
}
add_action( 'save_post', 'post_select_box_save' );
function post_select_box_save( $post_id ) {
// Bail if we're doing an auto save
if( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return;
// if our nonce isn't there, or we can't verify it, bail
if( !isset( $_POST['meta_box_nonce'] ) || !wp_verify_nonce( $_POST['meta_box_nonce'], 'post_meta_box_nonce' ) ) return;
// if our current user can't edit this post, bail
if( !current_user_can( 'edit_post' ) ) return;
// now we can actually save the data
$allowed = array(
'a' => array( // on allow a tags
'href' => array() // and those anchords can only have href attribute
)
);
// Probably a good idea to make sure your data is set
if( isset( $_POST['post_select'] ) )
update_post_meta( $post_id, 'post_select', esc_attr( $_POST['post_select'] ) );
}
as you can see, function and ID names are unique, but only last one saved.
this is what happened when I save :
As per my comment, each of your nonces seems to have the same name (meta_box_nonce), so there may be a clash if all three fields are submitted in the same form. Trying giving them unique names (in both your wp_nonce_field and wp_verify_nonce calls).

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

I need to implement a filter in the woocommerce backend, that I can use to filter the orders by the selected shipping method.
I can create a filter on custom fields and alter the query, but the problem is that woocommerce stores the shipping method in a custom table of the DB.
Any hints on how to achieve this filter?
I solved adding a dropdown menu, using this hook:
add_action( 'restrict_manage_posts', 'display_shipping_dropdown' );
And then used this other hook to extend the where clause:
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;
}
To complete Lorenzo's answer, here is a function you can use to generate the filter 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' );
in Lorenzo's solution, the algorithm will fail if the title of the shipping method is changed. (in my case dynamically by a plugin).
Using instance_id instead of title will avoid this.
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 );
If you combine MrSwed and Lorenzo's code, you get this (please correct me if I'm wrong but it works for me):
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' );
}

Categories