Practical, source-verified snippets for common Fundations (FREE, version 2.8.x) customizations. All examples use hooks and filters documented in Hooks & Filters Reference.
Notify admin when a fundraiser is created
get_fund_action_created fires after the wizard creates a post and saves all meta. The second argument is always an empty array.
add_action( 'get_fund_action_created', function( $post_id ) {
wp_mail(
get_option( 'admin_email' ),
'New fundraiser created',
sprintf(
'A new fundraiser was created: %s\n%s',
get_the_title( $post_id ),
get_permalink( $post_id )
)
);
} );
Act on a confirmed payment
Use get_fund_donation_paid for logic that requires a real payment. This fires when a webhook or reconciliation cron confirms the payment, and is the hook the Stats Model listens to.
add_action( 'get_fund_donation_paid', function( $donation_id ) {
$action_id = (int) get_post_meta( $donation_id, '_get_donation_action_id', true );
$amount = (float) get_post_meta( $donation_id, '_get_donation_amount', true );
$email = get_post_meta( $donation_id, '_get_donation_donor_email', true );
// Send a receipt, update a CRM, etc.
} );
For test mode and petition/leads mode, use get_fund_donation_completed instead, or hook both. See the note in Hooks & Filters Reference.
Add custom data before a donation is stored
add_filter( 'get_fund_donation_data_before_create', function( $data, $action_id ) {
if ( isset( $data['amount'] ) && (float) $data['amount'] >= 100 ) {
$data['tier'] = 'gold';
}
return $data;
}, 10, 2 );
Sort child fundraisers by amount raised
get_fund_child_actions_query_args passes the parent post ID as the second argument.
add_filter( 'get_fund_child_actions_query_args', function( $args, $post_id ) {
$args['orderby'] = 'meta_value_num';
$args['meta_key'] = '_get_fund_raised_amount';
$args['order'] = 'DESC';
return $args;
}, 10, 2 );
Enforce a minimum donation amount
add_filter( 'get_fund_donation_min_amount', function( $min, $action_id ) {
return 5.00;
}, 10, 2 );
Enforce a minimum goal amount in the wizard
add_filter( 'get_fund_wizard_validation_errors', function( $errors, $data ) {
if ( isset( $data['goal_amount'] ) && (float) $data['goal_amount'] < 50 ) {
$errors[] = __( 'Minimum goal amount is €50.', 'my-plugin' );
}
return $errors;
}, 10, 2 );
Redirect after the wizard to a custom page
add_filter( 'get_fund_wizard_redirect_url', function( $url, $post_id ) {
return home_url( '/thank-you-for-creating-a-fundraiser/' );
}, 10, 2 );
Append content to the progress bar block
add_filter( 'get_fund_progress_block_output', function( $output, $fund_data, $attributes, $post_id ) {
$output .= sprintf(
'<p class="progress-summary">%s raised of %s (%s%%)</p>',
esc_html( $fund_data['raised_formatted'] ),
esc_html( $fund_data['amount_formatted'] ),
esc_html( round( $fund_data['percentage'] ) )
);
return $output;
}, 10, 4 );
Allow a specific user role to edit any fundraiser
add_filter( 'get_fund_user_can_edit_action', function( $can_edit, $post_id, $user_id ) {
if ( user_can( $user_id, 'manage_fund_campaigns' ) ) {
return true;
}
return $can_edit;
}, 10, 3 );
Prevent a fundraiser from expiring when goal is met
add_filter( 'get_fund_should_expire_action', function( $should, $action_id ) {
$goal = (float) get_post_meta( $action_id, '_get_fund_amount', true );
$raised = (float) get_post_meta( $action_id, '_get_fund_raised_amount', true );
if ( $goal > 0 && $raised >= $goal ) {
return false;
}
return $should;
}, 10, 2 );
Trigger an action when the goal is reached
add_action( 'get_fund_stats_updated', function( $action_id, $row ) {
$goal = (float) get_post_meta( $action_id, '_get_fund_amount', true );
if ( $goal > 0 && isset( $row['total_raised'] ) && (float) $row['total_raised'] >= $goal ) {
// Goal reached — fire your notification
do_action( 'my_plugin_goal_reached', $action_id );
}
}, 10, 2 );
Change the thank-you URL after a donation
add_filter( 'get_fund_thank_you_url', function( $url, $donation_id, $action_id ) {
return add_query_arg(
array( 'fundraiser' => $action_id ),
home_url( '/donation-received/' )
);
}, 10, 3 );
Purge a CDN cache after a donation
add_action( 'get_fund_purge_cache', function( $urls_to_purge, $post_ids_to_purge ) {
foreach ( $urls_to_purge as $url ) {
wp_remote_request( 'https://api.mycdn.com/purge', array(
'method' => 'DELETE',
'body' => array( 'url' => $url ),
) );
}
}, 10, 2 );
Override the donation email recipient
add_filter( 'get_fund_donation_email_recipients', function( $email, $donation_id ) {
// CC a fundraising coordinator on every donation
return $email . ',coordinator@example.com';
}, 10, 2 );
Add a custom expiration email placeholder
add_filter( 'get_fund_expiration_email_placeholders', function( $placeholders, $action_id, $recipient_type ) {
$raised = get_post_meta( $action_id, '_get_fund_raised_amount', true );
$placeholders['{raised_amount}'] = number_format( (float) $raised, 2 );
return $placeholders;
}, 10, 3 );
Guard code that depends on PRO
if ( class_exists( 'Get_Fund_Pro' ) && Get_Fund::is_pro() ) {
// PRO features available
}
Common mistakes to avoid
| Mistake | Correct approach |
|---|---|
Using get_fund_wizard_steps filter | This filter does not exist. The wizard steps are a frontend JS component with no server-side step array. |
Declaring get_fund_action_created callback with two parameters expecting meaningful data in the second | The second argument is always an empty array. Use only $post_id. |
Using get_fund_progress_percentage filter | This filter does not exist. Use get_fund_progress_block_output to modify the rendered HTML, which includes the percentage in the data. |
Treating get_fund_donation_completed as the only paid hook | It also fires in test mode and petition mode. For production payment logic, use get_fund_donation_paid. |
Calling get_fund_child_actions_query_args with a callback that takes only $args | The filter passes $post_id as a second argument. Always declare ( $args, $post_id ). |