I have three separate woocommerce snippets where each one have one function.
I'm trying to combine them together in one script but can't seems to return more than one value.
function display_woocommerce_order_count2( $atts, $content = null ) {
$args = shortcode_atts( array(
'status' => 'completed',
), $atts );
$statuses = array_map( 'trim', explode( ',', $args['status'] ) );
$order_count = 0;
foreach ( $statuses as $status ) {
// if we didn't get a wc- prefix, add one
if ( 0 !== strpos( $status, 'wc-' ) ) {
$status = 'wc-' . $status;
}
$order_count += wp_count_posts( 'shop_order' )->$status;
}
ob_start();
return '<span style="color:#fff;text-align:center;font-size:12px">Deals:' .
$order_count;
$user->total;
return ob_get_clean();
}
add_shortcode( 'wc_order_count3', 'display_woocommerce_order_count2' );
function get_instock_products_count(){
global $wpdb;
// The SQL query
$result = $wpdb->get_col( "
SELECT COUNT(p.ID)
FROM {$wpdb->prefix}posts as p
INNER JOIN {$wpdb->prefix}postmeta as pm ON p.ID = pm.post_id
WHERE p.post_type LIKE '%product%'
AND p.post_status LIKE 'publish'
AND pm.meta_key LIKE '_stock_status'
AND pm.meta_value LIKE 'instock'
" );
return '<span style="color:#fff;text-align:center;font-size:12px">Proposals
Left: ' . reset($result);
}
add_shortcode('fp7', 'get_instock_products_count');
function new_proposals2(){
global $wpdb;
// 24 hours ago
$is_24h_ago = date("Y-m-d H:i:s", strtotime(date("Y-m-d H:i:s")." -1day"));
// The SQL query
$result = $wpdb->get_col( "
SELECT COUNT(p.ID)
FROM {$wpdb->prefix}posts as p
WHERE p.post_type LIKE '%product%'
AND p.post_status LIKE 'publish'
AND p.post_date > '$is_24h_ago'
" );
return '<span style="color:#fff;text-align:center;font-size:12px">New
Proposals: ' . reset($result);
}
add_shortcode( 'new_proposals', 'new_proposals2' );
i tried combining all scripts and put function after one another and tried to return those 3 values at the end of the 3 functions. But only the first one is returned.
or return value at the end of each function, no luck.
My goal is to have something similar to:
Proposals: Taken(x) | New(x) | Left(x)
To merge that 3 shortcodes in one is very easy and can be done this way:
function order_multi_count( $atts, $content = null ) {
global $wpdb;
$args = shortcode_atts( array(
'status' => 'completed',
), $atts );
## ---- ---- ---- ---- ---- ---- TAKEN ---- ---- ---- ---- ---- ---- ---- ##
$statuses = array_map( 'trim', explode( ',', $args['status'] ) );
$taken = 0;
foreach ( $statuses as $status ) {
// if we didn't get a wc- prefix, add one
if ( 0 !== strpos( $status, 'wc-' ) ) {
$status = 'wc-' . $status;
}
$taken += wp_count_posts( 'shop_order' )->$status;
}
## ---- ---- ---- ---- ---- ---- LEFT ---- ---- ---- ---- ---- ---- ---- ##
// The SQL query
$result = $wpdb->get_col( "
SELECT COUNT(p.ID)
FROM {$wpdb->prefix}posts as p
INNER JOIN {$wpdb->prefix}postmeta as pm ON p.ID = pm.post_id
WHERE p.post_type LIKE '%product%'
AND p.post_status LIKE 'publish'
AND pm.meta_key LIKE '_stock_status'
AND pm.meta_value LIKE 'instock'
" );
$left = reset($result);
## ---- ---- ---- ---- ---- ---- NEW ---- ---- ---- ---- ---- ---- ---- ##
// 24 hours ago
$is_24h_ago = date("Y-m-d H:i:s", strtotime(date("Y-m-d H:i:s")." -1day"));
// The SQL query
$result2 = $wpdb->get_col( "
SELECT COUNT(p.ID)
FROM {$wpdb->prefix}posts as p
WHERE p.post_type LIKE '%product%'
AND p.post_status LIKE 'publish'
AND p.post_date > '$is_24h_ago'
" );
$new = reset($result2);
## ---- ---- ---- ---- ---- RETURNING VALUE ---- ---- ---- ---- ---- ---- ##
$style = 'style="color:#fff;text-align:center;font-size:12px"';
return "<span $style><strong>Proposals:</strong> Taken ($taken) | New ($new) | Left ($left)</span>";
}
add_shortcode( 'order_multi_count', 'order_multi_count' );
This should work
USAGE: [order_multi_count]
or [order_multi_count status="processing"]
While accepted answer is perfectly valid one here is more performant and scalable code.
The issue with your code is that for each and every page load you are fetching & calculating same non-changing data.
This is an overhead which won't affect the site for few thousand visitors but when the products, orders or concurrent traffic goes up above code will start becoming a bottleneck.
In this code I have extensively used Transient API (caching) and instead of updating counts on each page load it will use cached counts. Best part is that it will automatically update the cached counts when any of the data used in each counts changes.
For example, as soon as a product is ordered (or order cancelled) the code will update Taken and Left.
This code is fully tested
Main Shortcode
add_shortcode( 'wp1707_proposal_stats', 'wp1707_proposal_stats_func' );
/**
* Shortcode to display In-Stock, New in last 24hours and Ordered products.
*
* @param array $atts The atts passed via shortcode
*
* @return string Outputs Shortcode HTML
*/
function wp1707_proposal_stats_func( $atts ){
$args = shortcode_atts( array(
'status' => 'completed',
), $atts );
/**
* Taken
*/
$requested_statuses = array_map( 'trim', explode( ',', $args['status'] ) );
$order_count_all_statuses = wp1707_get_count_posts();
$taken = 0;
foreach ( $requested_statuses as $key => $status ) {
// if we didn't get a wc- prefix, add one
if ( 0 !== strpos( $status, 'wc-' ) ) {
$status = 'wc-' . $status;
}
$taken += $order_count_all_statuses->$status;
}
/**
* Left
*/
$left = wp1707_instock_products_count( false );
/**
* New
*/
$new = wp1707_new_products_count();
return sprintf("<span style='proposal-stats'>Proposals:Taken (%d)| Left (%d) | New (%d)</span>", $taken, $left, $new );
}
Utility Functions
add_action('transition_post_status', 'wp1707_update_transients', 10, 3 );
/**
* Updates transients for Orders Count and In-Stock Products Count
*
* @param string $new_status New status passed by WordPress Hook
* @param string $old_status Old status passed by WordPress Hook
* @param WP_Post $post WP Post instance
*/
function wp1707_update_transients( $new_status, $old_status, $post ){
if( 'publish' === $new_status || 'publish' === $old_status ) {
if ( $post->post_type === 'shop_order' ) {
wp1707_get_count_posts( true );
} elseif ( in_array( $post->post_type, array( 'product', 'product_variation' ) ) ) {
wp1707_new_products_count( true );
}
}
}
/**
* Gets Shop Order Counts for each of the Statuses available
*
* @param boolean $update Force update the transient. Pass true to use
* data in transient api. Default false
*
* @return array Array containing Status as keys and order counts as values.
*/
function wp1707_get_count_posts ( $update = false ){
$shop_order_count = get_transient( 'wp1707_shop_order_count' );
if ( !$shop_order_count || !$update) {
$shop_order_count = wp_count_posts( 'shop_order' );
set_transient( 'wp1707_shop_order_count', $shop_order_count, 12 * HOUR_IN_SECONDS );
}
return reset( $shop_order_count );
}
/**
* Counts New Products published in last 24hours
*
* @param boolean $update Force update the transient. Pass true to use
* data in transient api. Default false
*
* @return int Count of new products pubplished in last 24hours
*/
function wp1707_new_products_count( $update = false ){
$new_products_count = get_transient( 'wp1707_new_products_count' );
if ( !$new_products_count || $update === true ) {
/**
* It wasn't there or a product was just published, so regenerate the
* data and save the transient */
global $wpdb;
// 24 hours ago
$is_24h_ago = date("Y-m-d H:i:s", strtotime(date("Y-m-d H:i:s")." -1day"));
// The SQL query
$new_products_count = $wpdb->get_col( "
SELECT COUNT(p.ID)
FROM {$wpdb->posts} as p
WHERE p.post_type LIKE '%product%'
AND p.post_status LIKE 'publish'
AND p.post_date > '$is_24h_ago'
" );
set_transient( 'wp1707_new_products_count', $new_products_count, 24 * HOUR_IN_SECONDS ); // Tweak the time here per your need
}
return reset( $new_products_count );
}
add_action('woocommerce_product_set_stock', 'wp1707_instock_products_count');
add_action('woocommerce_variation_set_stock', 'wp1707_instock_products_count');
/**
* Counts In-Stock Products
*
* @param boolean $update Force update the transient. Pass false to use
* data from transient api. Default true
*
* @return int Count of instock products
*/
function wp1707_instock_products_count( $update = true ){
// Get any existing copy of our transient data
$instock_products_count = get_transient( 'wp1707_instock_products_count' );
if ( !$instock_products_count || $update === true ) {
/**
* It wasn't there or stock was updated for some product, so regenerate
* the data and save the transient */
global $wpdb;
// The SQL query
$instock_products_count = $wpdb->get_col( "
SELECT COUNT(p.ID)
FROM {$wpdb->posts} as p
INNER JOIN {$wpdb->postmeta} as pm ON p.ID = pm.post_id
WHERE p.post_type LIKE '%product%'
AND p.post_status LIKE 'publish'
AND pm.meta_key LIKE '_stock_status'
AND pm.meta_value LIKE 'instock'
" );
set_transient( 'wp1707_instock_products_count', $instock_products_count, 12 * HOUR_IN_SECONDS ); // Tweak the time here per your usual sales traffic
}
return reset( $instock_products_count );
}
Usage
[wp1707_proposal_stats]
or [wp1707_proposal_stats status="processing,on-hold,completed"]
You can style the output by using .proposal-stats
class in your CSS.