How to extend Split Order Payment from a separate plugin — add your own settings tab, change field requirements, and hook into every notification moment — without editing a single line of this plugin’s code.
1. Detecting the plugin is active
Check for the base plugin before registering any of your hooks, so your plugin degrades gracefully if it’s ever deactivated:
if ( defined( 'CSWC_SPLIT_ORDER_PAYMENTS_VERSION' ) ) {
// Safe to register the hooks below.
}
2. Adding a settings tab
The Split Settings page (admin.php?page=split-order-payment) builds its tabs entirely from a filter, and renders each tab’s content entirely from an action. The base plugin’s own four tabs register through this exact same mechanism — your tab is a peer, not a bolt-on.
Add a slug to the $tabs array, keyed by a unique slug, with a label and optional icon (a Dashicons class name):
add_filter( 'cswc_split_payment_settings_tabs', function ( $tabs ) {
$tabs['whatsapp'] = array(
'label' => __( 'WhatsApp', 'my-whatsapp-addon' ),
'icon' => 'dashicons-format-chat',
);
return $tabs;
} );
{slug} is whatever key you added above (e.g. whatsapp). Echo your fields here — you’re already inside the page’s <form> and a settings-table-style card, so a plain <table class="form-table"> matches the surrounding UI:
add_action( 'cswc_split_payment_settings_tab_whatsapp', function () { ?>
<table class="form-table">
<tr>
<th><?php esc_html_e( 'WhatsApp API Token', 'my-whatsapp-addon' ); ?></th>
<td>
<input type="text" name="whatsapp_api_token"
value="<?php echo esc_attr( get_option( 'whatsapp_api_token' ) ); ?>" class="regular-text">
</td>
</tr>
</table>
<?php } );
split_order_payment_settings, to WordPress’s own options.php. Register your own field in that same group on admin_init and it saves automatically alongside the base plugin’s fields:
add_action( 'admin_init', function () {
register_setting( 'split_order_payment_settings', 'whatsapp_api_token' );
} );
3. Making the participant phone number required
The phone field on the participant form is optional by default. One filter makes it required everywhere it matters — the field’s own label, the frontend JS validation, and a server-side check when the form is submitted:
add_filter( 'cswc_split_payment_phone_required', '__return_true' );
Return it conditionally if the requirement should only apply once your own feature is actually configured:
add_filter( 'cswc_split_payment_phone_required', function ( $required ) {
return (bool) get_option( 'whatsapp_api_token' );
} );
4. Hooking into notification events
You don’t need a new hook to fire alongside the base plugin’s emails — it already fires a plain do_action() at every lifecycle moment, which is exactly what its own email classes listen to. Hook the same actions to send a WhatsApp message (or anything else) at the same moment:
| Hook | Fires when | Arguments |
|---|---|---|
| cr_split_order_payment_email | A participant is invited to pay their share | $order, $email, $split_payment |
| cswc_split_reminder_email | An unpaid participant is due a reminder | $order, $email_id, $row |
| cswc_split_expiry_email | A split expires and its order is auto-cancelled | $order |
| cr_split_order_complete_email | Every participant has paid | $parent_order, $email |
Example — send a WhatsApp reminder alongside the existing email reminder:
add_action( 'cswc_split_reminder_email', function ( $order, $email_id, $row ) {
if ( empty( $row->access_token ) ) {
return;
}
$pay_url = add_query_arg( array(
'split-order' => $row->order_id,
'split_pay_for' => rawurlencode( $email_id ),
), site_url( '/' ) );
// send_whatsapp_message() is your own integration's function.
send_whatsapp_message( $row->email_id, sprintf(
__( 'Reminder: you still owe %1$s for order #%2$d. Pay here: %3$s', 'my-whatsapp-addon' ),
wc_price( $row->share_amount ), $row->order_id, $pay_url
) );
}, 10, 3 );
$row isn’t guaranteed to carry a phone number by itself — cross-reference it with the participant data described next if you need one.5. Reading participant data
The tracking table — your primary source
Every participant, on every split, has one row in {$wpdb->prefix}cr_split_order_payments. This is the cleanest structured source for a per-participant integration:
| Column | Type | Meaning |
|---|---|---|
| order_id | bigint | The participant’s own sub-order (or the parent order for the organiser’s own share). |
| email_id | varchar | The participant’s email address. |
| amount / share_amount | float | The full order amount and this participant’s share of it. |
| payment_status | tinyint | 0 pending, 1 paid. |
| reminder_sent | tinyint | How many reminders have gone out so far. |
| access_token | varchar | The token used in a guest’s secure pay link. |
| expiry_date | datetime | When this split is due to auto-cancel, if unpaid. |
global $wpdb;
$participants = $wpdb->get_results( $wpdb->prepare(
"SELECT * FROM {$wpdb->prefix}cr_split_order_payments WHERE order_id = %d",
$parent_order_id
) );
Order meta — the raw split configuration
The parent order also carries the split’s original configuration as a single meta value, useful for the organiser’s chosen split mode or the phone numbers entered at split time:
| Meta key | On | Shape |
|---|---|---|
| _split_order_data | Parent order | array( 'participants' => [emails], 'invitee_mobiles' => [phones, same order], 'each_price', 'total_participants', 'split_mode', 'custom_amounts', 'split_participant_msg' ) |
| _split_payment_for | A participant’s sub-order | That participant’s email address (string). |
// Always via the order object — never get_post_meta()/update_post_meta(),
// which silently break under HPOS (High-Performance Order Storage).
$order = wc_get_order( $order_id );
$split = $order->get_meta( '_split_order_data' );
$phones = $split['invitee_mobiles'] ?? array();
6. Best practices
- Never touch order data with
get_post_meta()/update_post_meta(). Always go through$order->get_meta()/update_meta_data()/save()— raw postmeta calls silently fail once HPOS is active. - Don’t edit any file inside the base plugin. Every extension point you need is one of the hooks above; a direct patch won’t survive an update.
- Prefix your own option names (e.g.
whatsapp_) to avoid colliding with the base plugin’s own settings, which live in the samesplit_order_payment_settingsgroup. - Sanitize and escape exactly as you would anywhere else in WordPress —
register_setting()accepts asanitize_callback, and none of this plugin’s hooks sanitize your data for you.
7. Full worked example
A minimal, complete companion plugin putting all of the above together:
<?php
/**
* Plugin Name: Split Payment — WhatsApp Notifications
* Description: Sends WhatsApp reminders for Split Order Payment participants.
* Requires Plugins: woocommerce-split-order-payments
*/
if ( ! defined( 'CSWC_SPLIT_ORDER_PAYMENTS_VERSION' ) ) {
return; // Base plugin isn't active.
}
// 1. Add our own settings tab.
add_filter( 'cswc_split_payment_settings_tabs', function ( $tabs ) {
$tabs['whatsapp'] = array( 'label' => 'WhatsApp', 'icon' => 'dashicons-format-chat' );
return $tabs;
} );
add_action( 'cswc_split_payment_settings_tab_whatsapp', function () { ?>
<table class="form-table"><tr>
<th>WhatsApp API Token</th>
<td><input type="text" name="whatsapp_api_token"
value="<?php echo esc_attr( get_option( 'whatsapp_api_token' ) ); ?>" class="regular-text"></td>
</tr></table>
<?php } );
add_action( 'admin_init', function () {
register_setting( 'split_order_payment_settings', 'whatsapp_api_token' );
} );
// 2. Require a phone number once we're configured.
add_filter( 'cswc_split_payment_phone_required', function ( $required ) {
return (bool) get_option( 'whatsapp_api_token' );
} );
// 3. Send a WhatsApp message alongside every reminder email.
add_action( 'cswc_split_reminder_email', function ( $order, $email_id, $row ) {
if ( ! get_option( 'whatsapp_api_token' ) ) {
return;
}
// ...call your WhatsApp API here, using $row->share_amount, $row->order_id, etc.
}, 10, 3 );
