WordPress fundraising progress bar: a shortcode you can build today
· 4 min read
Charities, churches, and non-profit groups running WordPress often need one thing: a simple bar that shows how far a campaign has come. Set a goal, enter the amount raised, show supporters the progress. That is the whole job.
A handful of plugins do this. Most are abandoned, locked behind a paid plan, or carry more features than a small fundraising page needs. Some have had security disclosures. The underlying need is simple enough that building a fresh version takes about five minutes.
The shortcode approach means you place it anywhere: a page, a post, a widget area, a Gutenberg block. One attribute for the goal, one for the amount raised, one for the label. No admin screen, no database table, nothing to configure except the raised figure as donations come in.
What one build gives you
- A [fundraising_bar] shortcode that renders a visual progress bar with goal, raised amount, and an optional label
- Percentage fill calculated from raised divided by goal, capped at 100%
- A goal-reached visual state when raised meets or exceeds the goal
- Currency symbol as a shortcode attribute, defaulting to $
What it does not do
- Connecting to any payment plugin or gateway to update the raised amount automatically
- Storing donation records or donor information
- A live total pulled from GiveWP, Charitable, WooCommerce, or any other plugin
- Multiple campaigns managed from a central admin screen
- Donation form functionality: this plugin displays progress only, it does not accept payments
Thermometer does these. This covers the part most sites use.
The prompt
Loads into the composer so you can edit it first. Nothing is built, and nothing is charged, until you send it.
Build a WordPress plugin called Fundraising Progress Bar. Plugin Name: Fundraising Progress Bar. Description: Shows a visual fundraising progress bar via a shortcode. Single PHP file. No dependencies. Register a shortcode with tag fundraising_bar. Accept these attributes with defaults via shortcode_atts: goal (default empty string), raised (default empty string), label (default empty string), currency (default "$"). Sanitize: goal and raised with floatval, label with sanitize_text_field, currency with sanitize_text_field then mb_substr to 3 characters. If $goal is zero or empty after floatval, return an empty string. Calculate: $pct = min( ( $raised / $goal ) * 100, 100 ); $pct_display = round( $pct ); $raised_fmt = number_format( $raised, 0 ); $goal_fmt = number_format( $goal, 0 ); Build output as a string: - Outer div: class="fundraising-bar-wrap" data-pct="{$pct_display}". Add class fundraising-bar-complete if $pct >= 100. - If label non-empty: <p class="fundraising-bar-label"> containing the label. - <div class="fundraising-bar-track"><div class="fundraising-bar-fill" style="width:{$pct}%" role="progressbar" aria-valuenow="{$pct_display}" aria-valuemin="0" aria-valuemax="100"></div></div> - <p class="fundraising-bar-amounts">{$currency}{$raised_fmt} raised of {$currency}{$goal_fmt} goal</p> Return the string (do not echo). On wp_enqueue_scripts: call wp_register_style( 'fundraising-bar', false ), then wp_enqueue_style( 'fundraising-bar' ), then wp_add_inline_style( 'fundraising-bar', $css ) where $css is: .fundraising-bar-wrap{margin:1.5em 0}.fundraising-bar-label{font-weight:600;margin-bottom:.4em}.fundraising-bar-track{background:#e0e0e0;border-radius:4px;height:1.5em;overflow:hidden}.fundraising-bar-fill{background:#4caf50;height:100%;transition:width .3s ease}.fundraising-bar-complete .fundraising-bar-fill{background:#388e3c}.fundraising-bar-amounts{margin-top:.4em;font-size:.9em;color:#555} No settings page. No admin menu. No database tables. No AJAX. No inline JS.
What the shortcode produces
A horizontal progress bar showing a filled percentage. A label above the bar if you provide one. The amounts below it: raised and goal, formatted with your currency symbol. When the goal is reached the bar changes shade to signal completion.
The shortcode looks like: [fundraising_bar goal="5000" raised="1250" label="Roof Fund"]. Place it anywhere WordPress processes shortcodes: a Shortcode block in the editor, a Text widget in a sidebar, a classic editor page, or a template file via do_shortcode.
The style is minimal. The bar sits inside a rounded track, fills left to right as a percentage, and uses a brief CSS transition so any page reload feels smooth. No external assets, no calls to a CDN.
- goal: the target amount (required)
- raised: the amount collected so far (required)
- label: text shown above the bar (optional)
- currency: symbol prepended to amounts, defaults to $ (optional)
How you update the raised amount
The raised attribute is a static number in the shortcode. To update it, edit the page and change the value. For a campaign receiving a handful of donations a day, this is almost always fine: the person processing donations knows the running total and can update the page when they log in.
There is no live connection to a payment processor in this build. That is also why there is nothing to break when a payment API changes or a gateway plugin updates. The display is separate from the collection.
For campaigns where updates need to happen automatically, you could extend the plugin later by asking Steem to read the total from another plugin or a custom database field and pass it to the shortcode dynamically. That is a follow-up build, not something this one includes.
Changing how the bar looks
Because you own the plugin code, changing the appearance is a follow-up message away. Ask for a vertical thermometer shape, a different colour, a thicker bar, or the percentage displayed inside the fill. The CSS is bundled in the same file, so nothing is locked.
The default colours are a neutral grey track and a green fill that darkens when the goal is reached. These work on most themes without any adjustment. If your theme uses a brand colour that clashes, tell Steem the hex code and ask it to swap the fill.
Typography, spacing, and font size for the amounts are also in the plugin CSS. A follow-up build can turn this into a full block with inspector controls, which lets editors adjust the goal and raised amount from the block sidebar without touching the shortcode.
When a dedicated fundraising plugin makes more sense
If you need to process donations through the same plugin that shows the progress, that is a different shape of tool. GiveWP and Charitable handle donation forms, payment gateways, receipt emails, donor management, and reporting, with a progress display as one of many features. If you are collecting donations on the same site and need a full workflow, one of those is the right answer.
The shortcode built here shows a number you provide. It does not read from GiveWP, Charitable, WooCommerce, or any other plugin's totals. If your donation form already records contributions somewhere, you would need a small bridge to pull that total automatically, which is outside this build.
For a small charity running one campaign at a time and updating the figure weekly, the shortcode is the simpler choice. For an organisation running dozens of concurrent campaigns where totals must update in real time, it is not.
Questions
- How do I update the raised amount as donations come in?
Edit the page or post that contains the shortcode and change the raised attribute to the new total. There is no automatic update in this build: the raised figure is a static number you set manually.
- Can I place this shortcode in a sidebar widget?
Yes. In the block editor, add a Shortcode block to a widget area and paste the shortcode there. In classic widgets, use a Text widget. The shortcode works anywhere WordPress processes shortcodes.
- Can I change the currency symbol?
Yes. Add currency="£" (or any 1-3 character string) as an attribute. The default is $. For example: [fundraising_bar goal="10000" raised="4500" currency="€" label="Building Fund"].
- What happens if the raised amount exceeds the goal?
The bar fills to 100% and the fill colour darkens to show the goal was reached. The amounts below the bar still display the actual raised figure, so supporters can see the campaign exceeded its target.
The prompt
Loads into the composer so you can edit it first. Nothing is built, and nothing is charged, until you send it.
Build a WordPress plugin called Fundraising Progress Bar. Plugin Name: Fundraising Progress Bar. Description: Shows a visual fundraising progress bar via a shortcode. Single PHP file. No dependencies. Register a shortcode with tag fundraising_bar. Accept these attributes with defaults via shortcode_atts: goal (default empty string), raised (default empty string), label (default empty string), currency (default "$"). Sanitize: goal and raised with floatval, label with sanitize_text_field, currency with sanitize_text_field then mb_substr to 3 characters. If $goal is zero or empty after floatval, return an empty string. Calculate: $pct = min( ( $raised / $goal ) * 100, 100 ); $pct_display = round( $pct ); $raised_fmt = number_format( $raised, 0 ); $goal_fmt = number_format( $goal, 0 ); Build output as a string: - Outer div: class="fundraising-bar-wrap" data-pct="{$pct_display}". Add class fundraising-bar-complete if $pct >= 100. - If label non-empty: <p class="fundraising-bar-label"> containing the label. - <div class="fundraising-bar-track"><div class="fundraising-bar-fill" style="width:{$pct}%" role="progressbar" aria-valuenow="{$pct_display}" aria-valuemin="0" aria-valuemax="100"></div></div> - <p class="fundraising-bar-amounts">{$currency}{$raised_fmt} raised of {$currency}{$goal_fmt} goal</p> Return the string (do not echo). On wp_enqueue_scripts: call wp_register_style( 'fundraising-bar', false ), then wp_enqueue_style( 'fundraising-bar' ), then wp_add_inline_style( 'fundraising-bar', $css ) where $css is: .fundraising-bar-wrap{margin:1.5em 0}.fundraising-bar-label{font-weight:600;margin-bottom:.4em}.fundraising-bar-track{background:#e0e0e0;border-radius:4px;height:1.5em;overflow:hidden}.fundraising-bar-fill{background:#4caf50;height:100%;transition:width .3s ease}.fundraising-bar-complete .fundraising-bar-fill{background:#388e3c}.fundraising-bar-amounts{margin-top:.4em;font-size:.9em;color:#555} No settings page. No admin menu. No database tables. No AJAX. No inline JS.
Steem