Tribuy is built to be extended, and the Pro add-on uses only these public hooks. Text domain: tribuy-group-buy-for-woocommerce. Namespace: Tribuy. Function, hook and option prefix: tribuy_. Meta prefix: _tribuy_. Constants: TRIBUY_*. Pro uses TribuyPro, tribuy_pro_, _tribuy_pro_ and TRIBUY_PRO_*.
Template overrides
All group buy markup loads through wc_get_template(). Copy any file from the plugin’s templates/ directory into yourtheme/woocommerce/, keeping the same relative path:
templates/single-product/group-buy.php
→ yourtheme/woocommerce/single-product/group-buy.php
| Folder | Templates |
|---|---|
single-product/ | group-buy.php (the campaign box), group-buy-share.php (share links), group-buy-participants.php (recently joined) |
loop/ | group-buy-progress.php (compact progress in the shop and style="compact") |
myaccount/ | group-buys.php (My Account → Group buys) |
emails/ and emails/plain/ | tribuy-customer-joined.php, tribuy-customer-ending-soon.php, tribuy-customer-confirmed.php, tribuy-customer-failed.php, tribuy-campaign-started.php, tribuy-goal-reached.php, tribuy-campaign-ended.php |
Pro’s email templates (tribuy-pro-campaign-update.php, tribuy-pro-supplier-order.php) override the same way. Each template carries a @version; WooCommerce → Status → Group buy flags theme overrides that are out of date.
Every template receives $campaign, the GroupBuyProduct. The email templates also receive $order, $email_heading, $additional_content, $sent_to_admin, $plain_text and $email; the failed email receives $result (refunded, cancelled or refund_pending) and the campaign ended email $participants. The account template receives $rows.
Data model
- Product type:
group_buy, classTribuy\Products\GroupBuyProduct(extendsWC_Product_Simple). Use its getters:get_group_price(),get_goal_qty(),get_max_qty(),get_min_per_customer(),get_max_per_customer(),get_committed_qty(),get_remaining_qty()(-1means no limit),get_qty_to_goal(),get_progress_percent(),get_savings_percent(),get_campaign_status(),get_round(),is_running(),is_scheduled(),is_closed(),is_successful(),is_failed(),is_goal_reached(),get_customer_qty( $user_id, $email ),get_customer_limits( $user_id, $email ),can_participate( $user_id ). - Group price: stored as the WooCommerce sale price, so carts, filters, sorting and the Store API charge it natively.
- Product meta:
_tribuy_goal_qty,_tribuy_max_qty,_tribuy_min_per_customer,_tribuy_max_per_customer,_tribuy_start_date,_tribuy_end_date,_tribuy_status,_tribuy_round,_tribuy_committed_qty(a cache, rebuilt from the participants table and frozen at close),_tribuy_closed_date,_tribuy_ending_soon_sent. - Campaign states:
scheduled→active→successful|failed. A closed campaign can start a new round withCampaign::start_new_round(). - Participants table:
{$wpdb->prefix}tribuy_participants, with the columnsid,product_id,round,order_id,order_item_id(unique),user_id,email,qty,unit_price,status(awaiting,confirmed,refunded,refund_pendingorcancelled),date_createdanddate_updated. Onlyawaitingandconfirmedrows count towards the committed quantity. - Order status:
wc-tribuy-awaiting(“Awaiting group”). It counts as paid, reduces stock, and keeps downloads locked. - Order data: order item meta
_tribuy_round. Order meta_tribuy_joined_email_sent. - Dates: campaign dates are stored as site-local
Y-m-d H:i:sstrings. Convert them withtribuy_local_to_timestamp(), never withstrtotime(), which reads them as UTC. - Scheduling: Action Scheduler, group
tribuy-group-buy-for-woocommerce, with the actionstribuy_start_campaign,tribuy_end_campaign,tribuy_campaign_ending_soon,tribuy_process_orders(batches of 20) and the hourlytribuy_sweep_campaigns. - My Account endpoint:
group-buys.
Helper functions
| Function | Returns |
|---|---|
tribuy_get_campaign( $product ) | The GroupBuyProduct, or false if it isn’t a group buy. |
tribuy_is_campaign( $product ) | Whether a product is a group buy. |
tribuy_get_campaign_statuses(), tribuy_get_campaign_status_label( $status ) | Status labels. |
tribuy_is_ending_soon( $campaign ) | Whether a running campaign is inside the “Ending soon” window. |
tribuy_get_badges( $campaign ), tribuy_get_badges_html( $campaign ) | The campaign’s badges (goal-reached, ending-soon). |
tribuy_get_share_links( $campaign ) | Share links keyed by network, each with label and url. |
tribuy_get_public_name( $first, $last ) | “Jane D.”, for public display. |
tribuy_local_to_timestamp( $date ), tribuy_format_date( $date ) | Date helpers. |
tribuy_get_paid_order_statuses() | Order statuses that make an order join a campaign. |
tribuy_get_template( $name, $args ), tribuy_get_template_html( $name, $args ) | Load a plugin template. |
tribuy_get_admin_url( $args ) | URL of WooCommerce → Group Buys, e.g. array( 'tab' => 'participants', 'product_id' => 123 ). |
Tribuy\Campaign::recalculate( $campaign ) | Rebuild the committed quantity and transition the campaign if needed. |
Tribuy\Campaign::close( $campaign, $outcome = '' ) | Close a campaign now; pass successful or failed to force the outcome. |
Tribuy\Campaign::extend( $campaign, $seconds ) | Move the end date of a running campaign. |
Tribuy\Campaign::start_new_round( $campaign, $start, $end ) | Start a new round of a closed campaign. |
Tribuy\Participants::query( $args ) | Participant rows (product_id, round, status, user_id, email, per_page, page, count). |
Tribuy\Participants::get_committed_qty( $product_id, $round ), get_revenue(), get_recipients() | Campaign figures. |
Tribuy\Frontend\Shortcodes::get_campaign_ids( $atts ) | Campaign IDs for a grid (status, limit, orderby, order). |
Actions
| Action | Arguments | Fires |
|---|---|---|
tribuy_loaded | $plugin | After the plugin instantiates its classes. Boot add-ons here. |
tribuy_installed | — | After an install or upgrade routine. |
tribuy_campaign_started | $campaign | When a campaign starts accepting orders (also at the start of a new round). |
tribuy_goal_reached | $campaign | The first time the committed quantity reaches the goal. |
tribuy_campaign_succeeded / tribuy_campaign_failed | $campaign | When a campaign closes with that outcome. |
tribuy_campaign_closed | $campaign | When a campaign closes, whatever its outcome. |
tribuy_campaign_extended | $campaign, $end_date | When the end date is moved. |
tribuy_campaign_new_round | $campaign, $previous_round | When a closed campaign starts a new round. |
tribuy_campaign_ending_soon | $product_id | Scheduled at the start of the “Ending soon” window. |
tribuy_participant_added | $participant_id, $campaign, $order | When an order line item joins a campaign. |
tribuy_participant_status_changed | $participant_id, $new_status, $old_status | When a participant’s status changes. |
tribuy_order_confirmed | $order_id, $product_id | When an order’s group buy items are confirmed. |
tribuy_order_failed | $order_id, $product_id, $result | When an order’s group buy items are refunded or cancelled. |
tribuy_product_data_panel | $campaign | At the end of the admin Group buy tab. Add your own fields here. |
tribuy_closed_campaign_notice | $campaign | Inside the “This group buy has ended” notice. |
tribuy_campaign_box_after_facts / tribuy_campaign_box_end | $campaign | Inside the campaign box: after the facts, and at the end. |
tribuy_email_campaign_details | $campaign, $order, $plain_text, $email | Before the order details of the joined and successful emails. |
tribuy_participants_table_actions | $campaign, $round | Above a campaign’s participants list. |
tribuy_admin_tab_{tab} | $tab | Render a custom tab on WooCommerce → Group Buys. |
tribuy_campaign_action_{action} | $campaign | Handle a custom campaign action (see Admin\Actions::get_action_url()). |
Filters
| Filter | Arguments | Use |
|---|---|---|
tribuy_can_participate | true, $campaign, $user_id | Return false or a message to stop a customer joining (roles, private campaigns…). |
tribuy_validate_qty | $error, $campaign, $quantity, $limits | Return an error message to reject a quantity, or '' to accept it. |
tribuy_customer_qty_limits | $limits, $campaign, $user_id, $email | The min/max a customer may still order (max of -1 means no limit). |
tribuy_remaining_qty | $remaining, $campaign | Units left (-1 for no limit). |
tribuy_is_purchasable | $purchasable, $campaign | Whether the campaign accepts orders. |
tribuy_cart_item_price | $price, $campaign, $cart_item | Change the price charged in the cart. |
tribuy_should_close_campaign | true, $campaign, $reason | Return false to keep a due campaign open ($reason: ended, cap or goal). |
tribuy_campaign_outcome | $outcome, $campaign | Override the outcome of a closing campaign (not applied to forced outcomes). |
tribuy_refund_amount | $amount, $order, $participants, $campaign | The amount refunded for a failed campaign. |
tribuy_paid_order_statuses | $statuses | Order statuses that make an order join a campaign. |
tribuy_campaign_badges, tribuy_share_links | $list, $campaign | Badges and share links. |
tribuy_campaigns_query_args | $args, $atts | The WP_Query of the campaigns shortcode, block, dashboard and CLI. |
tribuy_account_rows | $rows | Rows of My Account → Group buys. |
tribuy_product_data_errors | $errors, $product | Add validation errors for the Group buy tab. |
tribuy_settings_fields | $settings | Add fields to WooCommerce → Settings → Group buy. |
tribuy_email_classes | $emails | Register or replace emails. |
tribuy_admin_tabs | $tabs | Add tabs to WooCommerce → Group Buys. |
tribuy_campaigns_table_columns, tribuy_campaigns_table_column, tribuy_campaigns_table_row_actions | — | Extend the campaigns table. |
tribuy_participants_table_columns, tribuy_participants_table_column | — | Extend the participants table. |
tribuy_campaign_statuses, tribuy_participant_statuses | $statuses | Status labels. |
tribuy_add_to_cart_url, tribuy_add_to_cart_text, tribuy_single_add_to_cart_text | $value, $campaign | Button URL and text. |
tribuy_campaigns_per_sweep | 50 | Campaigns checked per hourly sweep. |
Example: only let customers with a billing phone join
add_filter( 'tribuy_can_participate', function ( $allowed, $campaign, $user_id ) {
if ( true !== $allowed || ! $user_id ) {
return $allowed;
}
return get_user_meta( $user_id, 'billing_phone', true )
? true
: __( 'Please add a phone number to your account before joining a group buy.', 'my-plugin' );
}, 10, 3 );
Example: notify a supplier when a campaign succeeds
add_action( 'tribuy_campaign_succeeded', function ( $campaign ) {
wp_mail(
'orders@supplier.example',
sprintf( 'Confirmed: %s', $campaign->get_name() ),
sprintf( 'Please prepare %d units.', $campaign->get_committed_qty() )
);
} );
Example: give campaigns one extra day when they are almost there
add_filter( 'tribuy_should_close_campaign', function ( $close, $campaign, $reason ) {
if ( 'ended' === $reason && $campaign->get_progress_percent() >= 90 && ! $campaign->get_meta( '_my_extended' ) ) {
$campaign->update_meta_data( '_my_extended', 1 );
$campaign->save_meta_data();
Tribuy\Campaign::extend( $campaign, DAY_IN_SECONDS );
return false;
}
return $close;
}, 10, 3 );
WP-CLI
wp tribuy list [--status=<status>] [--format=table|csv|json|ids]
wp tribuy recalc [<id>...] [--all]
wp tribuy resolve <id>... [--outcome=successful|failed] [--yes]
wp tribuy extend <id>... [--days=<days>]
Pro hooks
| Hook | Type | Arguments |
|---|---|---|
tribuy_pro_loaded | action | $plugin: Pro features booted (license valid). |
tribuy_pro_tier_unlocked | action | $campaign, $tier: a new price tier was reached. |
tribuy_pro_milestone_reached | action | $campaign, $percent. |
tribuy_pro_order_settled | action | $order, $campaign, $amount, $method (refund, due, coupon or manual). |
tribuy_pro_campaign_relaunched | action | $campaign. |
tribuy_pro_campaign_auto_extended | action | $campaign, $days. |
tribuy_pro_tiers | filter | $tiers, $campaign: the tiers (qty, price), sorted by quantity. |
tribuy_pro_settlement_amount | filter | $amount, $order, $campaign, $final_price. |
tribuy_pro_live_data | filter | $data, $campaign: the live progress payload. |
tribuy_pro_rest_prepare_campaign | filter | $data, $campaign: extend REST campaign objects. |
Helpers: tribuy_pro_get_tiers(), tribuy_pro_get_price_at( $campaign, $qty ), tribuy_pro_get_next_tier(), tribuy_pro_get_history(). Pro product meta: _tribuy_pro_tiers, _tribuy_pro_roles, _tribuy_pro_hide_price, _tribuy_pro_access, _tribuy_pro_password, _tribuy_pro_invite_token, _tribuy_pro_qty_step, _tribuy_pro_min_value, _tribuy_pro_supplier_email, _tribuy_pro_extend_threshold, _tribuy_pro_extend_days, _tribuy_pro_auto_relaunch, _tribuy_pro_relaunch_delay, _tribuy_pro_relaunch_limit, _tribuy_pro_history. Waitlist table: {$wpdb->prefix}tribuy_pro_waitlist. Background work runs on Action Scheduler in the tribuy-group-buy-for-woocommerce-pro group.
REST API (Pro)
Namespace group-buy/v1. Campaign reads are public for published campaigns (private campaigns are hidden from visitors). Participants and actions need the edit_product capability, so authenticate with a cookie + wp_rest nonce or an application password.
| Method & route | Parameters | Returns |
|---|---|---|
GET /wp-json/group-buy/v1/campaigns | status (active default, scheduled, successful, failed, any, or several separated by commas), per_page (1–100, default 10), orderby (end_date, date, title, popularity) | Array of campaigns. |
GET /wp-json/group-buy/v1/campaigns/{id} | — | One campaign. |
GET /wp-json/group-buy/v1/campaigns/{id}/participants | round (default current), per_page (1–500, default 50), page | Participants: id, order_id, user_id, email, qty, unit_price, status, date. Total in the X-WP-Total header. |
POST /wp-json/group-buy/v1/campaigns/{id}/end | outcome (optional: successful or failed) | The closed campaign. |
POST /wp-json/group-buy/v1/campaigns/{id}/extend | days (1–365, default 1) | The campaign. |
POST /wp-json/group-buy/v1/campaigns/{id}/recalculate | — | The campaign. |
A campaign object includes id, name, permalink, status, round, goal, max, committed, progress, remaining, min_per_customer, max_per_customer, start_date, end_date, seconds_remaining, currency, regular_price, group_price, current_price, tiers and next_tier (qty, price, needed, or null).
curl -X POST https://example.com/wp-json/group-buy/v1/campaigns/123/extend \
-u "username:application-password" \
-d days=3