To sum custom field values across WordPress posts, use a WP_Query with posts_per_page: -1, loop through results calling get_post_meta() or get_field(), and accumulate into a variable. Display via shortcode. No plugin required — but ACF Extended and Toolset add UI-based calculation fields.
Why You Might Need to Sum Custom Field Values
WordPress custom fields are incredibly flexible for storing numeric data — inventory quantities, scores, prices, hours logged, ratings, donations received. But once you’re storing numbers, the next natural requirement is aggregation: what’s the total inventory across all products in a category? What’s the average rating across all reviews? What’s the sum of hours logged this month?
I encounter this need on nearly every data-centric WordPress project. A real estate site wants a total of all property listing prices in a search result. A fitness tracker built on WordPress needs to sum exercise durations across a user’s posts. A charity site needs a running total of pledges stored as a custom field on donor profiles.
WordPress core doesn’t provide a built-in aggregation widget or block — but it gives you all the building blocks: WP_Query, get_post_meta(), and the shortcode API. The question is whether you need a plugin with a UI, or whether a lean PHP function is the better approach.
Using Advanced Custom Fields (ACF) with PHP to Sum Values
If your site uses ACF (the gold standard for custom fields on WordPress), you can sum field values across posts with a few lines of PHP. The approach uses WP_Query to fetch all relevant posts, then calls get_field() on each to collect the numeric value.
/**
* Shortcode: [wpdev_field_sum post_type="product" field="price"]
* Sums a numeric ACF field across all posts of a given type.
*/
function wpdev_field_sum_shortcode( $atts ) {
$atts = shortcode_atts( array(
'post_type' => 'post',
'field' => '',
'format' => 'number', // 'number' or 'currency'
), $atts, 'wpdev_field_sum' );
if ( empty( $atts['field'] ) ) {
return '<em>Please specify a field name.</em>';
}
$query = new WP_Query( array(
'post_type' => sanitize_key( $atts['post_type'] ),
'post_status' => 'publish',
'posts_per_page' => -1,
'fields' => 'ids', // Only retrieve IDs for performance.
'no_found_rows' => true,
) );
$total = 0;
if ( $query->have_posts() ) {
foreach ( $query->posts as $post_id ) {
$value = get_field( sanitize_key( $atts['field'] ), $post_id );
$total += floatval( $value );
}
}
if ( $atts['format'] === 'currency' ) {
return '$' . number_format( $total, 2 );
}
return number_format( $total, 0 );
}
add_shortcode( 'wpdev_field_sum', 'wpdev_field_sum_shortcode' );
Use it as [wpdev_field_sum post_type="donation" field="amount" format="currency"] on any page or widget. Note the 'fields' => 'ids' argument — this tells WP_Query to only load post IDs, not full post objects, which dramatically reduces memory usage when summing across hundreds of posts.
The Best Plugins for Summing Custom Fields
ACF Extended (ACFE): The most powerful free addition to ACF. It adds a “Calculated” field type that evaluates a formula based on other ACF fields within the same post. This is perfect for per-post calculations (e.g., total price = quantity × unit cost) but doesn’t aggregate across posts natively.
Toolset / Toolset Views: Toolset lets you build queries and display aggregated custom field data without PHP. Its “Views” feature can output sums and averages in visual templates. It’s a full platform though — best suited for sites already in the Toolset ecosystem.
WP Meta and Taxonomies: A leaner plugin that extends the post meta API with query UI. It allows filtering posts by meta value ranges and has basic aggregation output. Good for simpler use cases where a full framework feels like overkill.
My recommendation: if you’re already using ACF, start with the custom PHP shortcode above. It’s faster, has no dependencies, and you understand exactly what it does. Only reach for a plugin if your client needs to configure aggregations without developer involvement.
Building a Custom PHP Solution (No Plugin)
For sites that need more control over the query or the output — filtering by taxonomy, date range, or user — a custom PHP function is the cleanest solution. You can extend the shortcode example above with additional attributes to support any query parameter WP_Query accepts.
For extremely large datasets (thousands of posts), bypass WP_Query entirely and use a direct $wpdb query. The wp_postmeta table is optimized for key/value lookups, and a raw SQL SUM() query will be orders of magnitude faster than looping through post objects in PHP.
/**
* Fast database-level sum using wpdb.
* Use when dealing with thousands of posts.
*/
function wpdev_db_sum_meta( $post_type, $meta_key ) {
global $wpdb;
$result = $wpdb->get_var( $wpdb->prepare(
"SELECT SUM( CAST( pm.meta_value AS DECIMAL(10,2) ) )
FROM {$wpdb->postmeta} pm
INNER JOIN {$wpdb->posts} p ON p.ID = pm.post_id
WHERE pm.meta_key = %s
AND p.post_type = %s
AND p.post_status = 'publish'",
$meta_key,
$post_type
) );
return floatval( $result );
}
Displaying Sums in Posts, Pages, and Shortcodes
Once you have your sum function, integrating it into your site is straightforward. The shortcode approach (shown in the code examples) is the most flexible — it works in the block editor, classic editor, widgets, and even menu items. Register it with add_shortcode() and it’s available site-wide.
For theme templates, call your sum function directly in the PHP file. For Gutenberg, wrap the function in a server-side rendered block using register_block_type() with a render_callback. This gives editors a live-preview block that always shows the current total without page refresh.
Performance Considerations for Large Datasets
Summing custom fields across hundreds of posts on every page load is expensive. The first optimization is to use a transient to cache the result — wrap your query in get_transient() and set_transient() with a reasonable expiry (60 minutes for most dashboards). Invalidate the transient using a save_post action hook so the total refreshes when data changes.
For real-time totals that update frequently, consider a denormalization strategy: maintain a single option value (update_option('wpdev_total_donations', $new_total)) that you update incrementally on each new post save, rather than recalculating from scratch each time. This turns an O(n) database scan into a single get_option() call.
For small datasets, use a WP_Query loop with get_field() and a shortcode. For large datasets, use a direct $wpdb SUM() query and cache the result in a transient. Most WordPress sites need no plugin for this — a dozen lines of PHP gets the job done.
Frequently Asked Questions
Use WP_Query with ‘posts_per_page’ => -1 and ‘fields’ => ‘ids’ to get all relevant post IDs, then loop through calling get_post_meta() or get_field() on each, accumulating into a $total variable. Wrap this in a shortcode function for easy placement on any page. For large datasets, use a direct SQL SUM() query via $wpdb.
Run a WP_Query for the relevant posts with ‘posts_per_page’ => -1 and ‘fields’ => ‘ids’ to keep it light, then loop the IDs calling get_post_meta($id, ‘your_field’, true) (or get_field() with ACF) and add each value into a running total. Wrap it in a shortcode so you can drop the total anywhere. For anything beyond a few hundred posts, switch to a direct $wpdb SUM() query instead of looping.
ACF itself doesn’t have a native cross-post aggregation feature, but the free ACF Extended plugin adds a Calculated field type for per-post arithmetic. For cross-post totals, you need a PHP function using WP_Query and get_field(), or a direct database query. ACF Pro’s relationship and repeater fields can also be aggregated with the right PHP logic.
For a repeater, use have_rows() / the_row() and get_sub_field() to loop each row and accumulate the sub-field you want. To total a repeater sub-field across many posts, nest that loop inside a WP_Query over the post IDs. Repeaters store each sub-value as its own meta row, so for large datasets a targeted $wpdb query against the postmeta table (matching the repeater’s meta key pattern) is far faster than nested PHP loops.
Register a shortcode that runs your aggregation query and returns the formatted total. Place the shortcode on your desired page or template. For a server-side Gutenberg block, use register_block_type() with a PHP render_callback that executes the same logic. Both approaches give you a live total that updates as underlying post data changes.
For a single total, custom code wins — a dozen lines of PHP with WP_Query and a shortcode does the job with no plugin overhead, and you control performance and caching. Reach for a plugin (calculated-fields or ACF add-ons) when non-developers need to configure totals through an admin UI, or when you need many calculated fields managed visually. Code for control and speed; plugin for convenience.
Skip the per-post PHP loop and run a single direct query: $wpdb->get_var() with a SUM() over the postmeta table filtered by your meta key (join to posts for status/type if needed). Then cache the result in a transient so you’re not recomputing on every page load — refresh it on a schedule or when the data changes. A loop over thousands of posts can take seconds; the SUM() query plus a cached transient is effectively instant.
Advanced Custom Fields Pro is still the market leader in 2026, offering the broadest field type library, Gutenberg block builder, and the most complete developer documentation. Meta Box is an excellent, more affordable alternative. For heavy relational data needs, Pods Framework deserves serious consideration. For most projects, ACF Pro is the pragmatic default choice.
Related Resources
Custom WordPress Development
Data-driven WordPress applications with complex custom field architecture.
Custom WordPress DevelopmentCustom PHP Development
PHP solutions for aggregating and reporting on complex datasets.
Custom PHP DevelopmentWordPress Login Redirects
Role-based login redirects using the login_redirect filter.
WordPress Login Redirects