Sum custom post meta values - php

This should be really straightforward..
I have a custom post type: "shipment" with a custom field "shipment_cost"
I want to sum the total cost of all shipments.
I've managed to get it to output the correct amount with a single post:
$totalcost = 0;
$post_ids = [2583];
foreach( $post_ids as $post_id )
{
$totalcost += (int) get_post_meta( $post_id, 'shipment_cost', true );
}
echo $totalcost;
But when I try to use all shipment CPTs in an array, I get a result of zero.
$shipments = array(
'post_type' => 'shipment'
);
$totalcost = 0;
$post_ids = $shipments;
foreach( $post_ids as $post_id )
{
$totalcost += (int) get_post_meta( $post_id, 'shipment_cost', true );
}
echo $totalcost;
Is my shipments array wrong, or am I just going about this the wrong way in general?
Thanks!

Right now it seems that you are using $shipments as it was an array of post ids? You first need to retrieve all post ids:
$shipments = get_posts(array(
'post_type' => 'shipment',
'post_status' => 'publish'
));
Since the above would return post object you need to modify your loop:
foreach ($shipments as $post) {
$totalcost += (int) get_post_meta($post->ID, 'shipment_cost', true);
}
A better and faster way might be to use a raw database query to get the sum for all meta values:
$totalcost = $wpdb->get_col("SELECT SUM(pm.meta_value) FROM {$wpdb->postmeta} pm
INNER JOIN {$wpdb->posts} p ON p.ID = pm.post_id
WHERE pm.meta_key = 'shipment_cost'
AND p.post_status = 'publish'
AND p.post_type = 'shipment'");

This just saved my life!! Been looking for a solution to total inputs from a Pods Custom Post Type which has a Custom Field that users can enter a number into. I then wrapped the code in a shortcode to display on front end
function jobs_shortcode () {
$jobs = get_posts(array(
'post_type' => 'pledged_job',
'post_status' => 'publish'
));
$total = 0;
$post_ids = $jobs;
foreach ($jobs as $post) {
$total += (int) get_post_meta($post->ID, 'jobs_pledged', true);
}
echo $total;
}
add_shortcode( 'jobs', 'jobs_shortcode' );
THANK YOU!

Related

Improve Performance get_post_meta WordPress

I created a logic inside my WordPress, where for every CPT shop_oder, there is a post_meta called "luck_number". The problem is that on average, each post in this CPT has had more than 1000 sales, and then when I create a while to go through and get the post_meta with get_post_meta, the page takes about 15 minutes to load, specifically inside the While do loop.
I did a test, and when there are few post_meta the speed is ok, but when we get to the thousand place, it gets pretty slow.
What would be the best way, so that even in this scenario of thousands of post_meta per POST, I still have a good performance?
The section where the laugh is like this:
<?php
$loop = new WP_Query( $args );
while ( $loop->have_posts() ) : $loop->the_post();
$numbers = get_post_meta(get_the_ID(),"luck_number",false);
$a = 0;
while($a<count($numbers)):
// DO SOMETHING WITH THE NUMBER
$a++;
endwhile;
endwhile;
wp_reset_query();
While each post has an average of 0 to 500 numbers, everything works fine. Above 1000, it's very slow.
My 'post_per_page' averages 25, but even changing it to a smaller number doesn't change the result much. The infrastructure like the server (a good VPS) or the memory_limit of PHP (currently with 1024M) hasn't interfered much
If you need only one custom_field from CPT, you don't need to use WP_Query
You can just take all fields in the array through $wpdb
Try this code
function get_luck_numbers_from_db( $key = '', $type = 'post', $status = 'publish' ) {
global $wpdb;
if( empty( $key ) )
return;
$r = $wpdb->get_results( $wpdb->prepare( "
SELECT pm.post_id, pm.meta_value FROM {$wpdb->postmeta} pm
LEFT JOIN {$wpdb->posts} p ON p.ID = pm.post_id
WHERE pm.meta_key = '%s'
AND p.post_status = '%s'
AND p.post_type = '%s'
", $key, $status, $type ) );
foreach($r as $value) {
if($value !="") {
$luck_numbers_array[$value->post_id] = $value->meta_value;
}
}
return $luck_numbers_array;
}
$array = get_luck_numbers_from_db('luck_number','shop_oder', 'publish');
print_r($array);

Is there any way to add a pause after so many iterations in a php foreach loop?

I'm trying to update post meta for over 100,000 WooCommerce products (using ACF's update_field function). The code is pretty straightforward, it assigns a priority order based on the menu order of an attribute. Since it's going through so many products, the memory limit gets reached. Is there maybe a way to pause for a few seconds after every 1,000 records so that the memory limit doesn't get exhausted?
$args = array(
'taxonomy' => 'pa_brand',
'hide_empty' => false,
);
$brands = get_terms("pa_brand");
$brand_IDs = array();
foreach ($brands as $brand) {
array_push($brand_IDs, $brand->term_id);
}
$args = array(
'post_type' => 'product',
'posts_per_page' => -1,
);
$products = get_posts($args);
// This is the foreach loop that goes through thousands of products
foreach ($products as $prod) {
$ID = $prod->ID;
$brand = get_the_terms($ID, 'pa_brand');
$brand = $brand[0] ?? false;
if (!$brand) {
continue;
}
$brand_ID = $brand->term_id;
$priority = array_search($brand_ID, $brand_IDs) + 1;
update_field("field_61607fa7967c4", $priority, $ID);
}
I've confirmed the code does work properly. I tried on just 5 products.
For this job, you shouldn't use the get posts function because it grabs all fields from the database and all that you want is the id and the brands.
Try to fetch the database directly:
global $wpdb;
$results = $wpdb->get_results( "SELECT id FROM {$wpdb->prefix}posts WHERE
post_type='product'", OBJECT );
foreach ($results as $prod) {
//...
}
Not really sure about the field for type in the posts table. Maybe you have to look for the correct name.

Wordpress: sum custom meta_values from all posts by a user

Ok, so right now I have a working code, that basically echo the total amount of posts for meta_key _heart_this for a specific user:
<?php $query = new WP_Query( array( 'meta_key' => '_heart_this', 'author' => 1, ) );
echo $query->found_posts; ?>
However, some posts have meta_value of 2, 3 etc..
So I want to sum the total amount of meta_value and echo, because right now the number I get is inaccurate obviously.
I'm almost there, need a bit of guidance.
Thanks in advance.
It should be taken in loop. Use below code
$query = new WP_Query( array( 'meta_key' => '_heart_this', 'author' => 1) );
//Take all values in array
$sum = [];
if( $query->have_posts()){
while( $query->have_posts()): $query->the_post();
{
//Get all posts values one by one
$value = get_post_meta( get_the_ID(), '_heart_this', true );
//Push values in array
array_push($sum, $value);
}
endwhile;
}
//Sum all values of array to get total amount of meta value
$sum_final = array_sum ($sum);
echo $sum_final;
Tested & works

How to count meta_key(s) of a page?

Is it possible to count the amount of the same meta_keys for the same post_id.
I have a page with the post_id 44 and every time a user submits something on this page a new database rule is added with the meta_key "post_rating_0".
There are over 30 rules now for this page and I want to count them.
For other pages the same thing.
Is this possible?
Code so far:
global $post;
$query_args = array(
'post_type' => 'page',
'post_status' => 'publish',
'posts_per_page' => -1,
'meta_key' => 'post_rating_0'
// 'fields' => 'SUM(amount_to_paid)',
);
$sum = 0;
$query = new WP_Query($query_args);
if ( $query->have_posts() ) {
while( $query->have_posts() ) {
$query->the_post();
// do the processing for each post
$sum = $sum + intval(get_post_meta(get_the_id(),'post_rating_0', true ));
}
}
echo $sum ;
This is what I got so far... But what this does is echo the value of "2" what is very logic. It searches for posts with the meta_key "post_rating_0", counts them and that are 2 posts.
What I'm trying to do is count the amount of meta_keys "post_rating_0" are in one page.
This modified code will give you an array with all post_id and the corresponding amount of your specific meta:
$meta_arr = array();
$query = new WP_Query($query_args);
if ( $query->have_posts() ) {
while( $query->have_posts() ) {
$query->the_post();
$post_id = get_the_id();
$meta_arr[$post_id] = intval(get_post_meta($post_id, 'post_rating_0', false));
}
}
print_r($meta_arr);
Did some more research and with some modifications I managed to got it working. This is the final code:
$pagina_id_test = get_the_id();
// retrieve all meta_values with key 'post_rating_0' from database
$reviews_posts = $wpdb->get_results("
SELECT meta_value FROM " . $wpdb->prefix . "postmeta
WHERE meta_key = 'post_rating_0'
AND post_id = $pagina_id_test", ARRAY_A);
// define reviews array
$reviews_count = array();
// iterate through meta_values, count the occurence of each review
foreach ($reviews_posts as $reviews_post) {
if (isset($reviews_count[$reviews_post['meta_value']])) {
$reviews_count[$reviews_post['meta_value']] = $reviews_count[$reviews_post['meta_value']] + 1;
} else {
$reviews_count[$reviews_post['meta_value']] = 1;
}
}
// echo results
$aantal_reviews = 0;
foreach ($reviews_count as $review) {
$aantal_reviews++;
}
echo $aantal_reviews;
global $wpdb;
global $post;
$post_id = $post->ID;
$c = $wpdb->get_row("SELECT COUNT(*) as NBR FROM {$wpdb->postmeta}
WHERE post_id={$post_id} AND meta_key='post_rating_0' AND
(SELECT ID FROM {$wpdb->posts} WHERE ID={$post_id} AND post_type='page') IS NOT NULL");
echo $c->NBR;
Select count of post where post_type is page and meta_key='post_rating_0'

Fastest approach: Count all products (including variations) in WooCommerce

I'm wondering if there exist any faster approaches to count all products in WooCommerce (and their child-variations), than this following code-example:
function total_product_count() {
$product_count = 0;
$args = array(
'post_type' => 'product',
'posts_per_page' => -1
);
/* Initialize WP_Query, and retrieve all product-pages */
$loop = new WP_Query($args);
/* Check if array contains any posts */
if ($loop->have_posts()):
while ($loop->have_posts()):
$loop->the_post();
global $product;
/* Count the children - add count to product_count */
product_count += count($product->get_children());
endwhile;
endif;
return $product_count;
}
On my local XAMPP web-server the function executes in 3 seconds (having 253 products), which is way too long time. The function returns 1269.
$product->get_children() is not always correct in this situation. get_children() return child products as well as grouped products if exist.
I hope the better and fastest way is to use wpdb:: MySQL query method. Try the following code
echo 'Number of main products => '.main_product_count();
echo 'Number of variations => '. variation_product_count();
function main_product_count() {
global $wpdb;
$count = $wpdb->get_var("SELECT COUNT(*) FROM $wpdb->posts WHERE `post_type` LIKE 'product'");
return $count;
}
function variation_product_count() {
global $wpdb;
$count = $wpdb->get_var("SELECT COUNT(*) FROM $wpdb->posts WHERE `post_type` LIKE 'product_variation'");
return $count;
}
as your naming
$loop =new WP_Query($args);
try this code
$loop->post_count;
while ($loop->have_posts()){
global $product;
/* Count the children - add count to product_count */
$loop->post_count += count($product->get_children());
}
WP_Query has a property which gives you the number of posts found matching the current query parameters:
function total_product_count() {
$args = array( 'post_type' => 'product', 'posts_per_page' => -1 );
$products = new WP_Query( $args );
return $products->found_posts;
}

Categories