Created
August 13, 2026 11:42
-
-
Save goranefbl/a4f64a40bd047fc6e375439b93bc0880 to your computer and use it in GitHub Desktop.
cap referrals per rank
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| /** | |
| * Example: Per-rank yearly cap on referral email invitations | |
| * | |
| * Each VIP rank is allowed to send a different number of referral email | |
| * invitations per calendar year. Once a customer reaches their rank's limit, | |
| * the "invite friends by email" action is rejected with a friendly message | |
| * until January 1, when the counter resets automatically. | |
| * | |
| * Example caps used below: Bronze 3, Silver 5, Gold 10, Platinum 15. | |
| * | |
| * NOTE: This caps the EMAIL invitation action only (the /widget/customer/invite | |
| * REST endpoint). Copying the referral link and the social-share buttons happen | |
| * entirely in the visitor's browser with no server call, so they cannot be | |
| * capped. This is a hard technical limit, not an oversight. | |
| * | |
| * HOW TO FIND YOUR RANK IDS: | |
| * Go to Loyalty Program -> Ranks -> Edit Rank. The modal header shows the | |
| * rank ID, e.g. "Edit Rank (#2)". Adjust the $caps map below to match your | |
| * actual rank IDs. Any rank not listed, or a customer with no rank yet, | |
| * uses WPGL_INVITE_CAP_DEFAULT. | |
| * | |
| * Copy this snippet to your theme's functions.php or a small custom plugin. | |
| * Requires: Loyalty Program plugin with Referrals + Ranks modules active. | |
| */ | |
| if (!defined('ABSPATH')) { | |
| exit; | |
| } | |
| // Fallback cap for customers with no rank (or a rank not listed in the map below). | |
| if (!defined('WPGL_INVITE_CAP_DEFAULT')) { | |
| define('WPGL_INVITE_CAP_DEFAULT', 3); | |
| } | |
| /** | |
| * Per-rank yearly invitation caps. | |
| * | |
| * Each line has the format: RANK_ID => INVITATIONS_PER_YEAR | |
| * | |
| * - Left of "=>" is the RANK ID (the "#2" shown under | |
| * Loyalty Program -> Ranks -> Edit Rank). | |
| * - Right of "=>" is the NUMBER of referral invitations that rank | |
| * may send per calendar year. | |
| * | |
| * Example: "3 => 10" means rank #3 can send 10 invitations per year. | |
| * Edit the IDs and numbers to match this store's VIP ranks. | |
| */ | |
| function wpgl_referral_invite_caps() | |
| { | |
| return array( | |
| // RANK ID => INVITATIONS PER YEAR | |
| 1 => 3, // e.g. Bronze | |
| 2 => 5, // e.g. Silver | |
| 3 => 10, // e.g. Gold | |
| 4 => 15, // e.g. Platinum | |
| ); | |
| } | |
| /** | |
| * Resolve the current user's yearly invite cap from their rank. | |
| * | |
| * @param int $user_id | |
| * @return int | |
| */ | |
| function wpgl_get_user_invite_cap($user_id) | |
| { | |
| $cap = WPGL_INVITE_CAP_DEFAULT; | |
| if (class_exists('WPGL_Ranks_Core')) { | |
| $rank = WPGL_Ranks_Core::get_user_rank($user_id); | |
| if ($rank && !empty($rank->id)) { | |
| $caps = wpgl_referral_invite_caps(); | |
| if (isset($caps[(int) $rank->id])) { | |
| $cap = (int) $caps[(int) $rank->id]; | |
| } | |
| } | |
| } | |
| return (int) $cap; | |
| } | |
| /** | |
| * The user-meta key that stores how many invites the user has sent this year. | |
| * Includes the year so it resets automatically every January 1. | |
| * | |
| * @param int $user_id | |
| * @return string | |
| */ | |
| function wpgl_invite_count_meta_key($user_id) | |
| { | |
| $year = (int) current_time('Y'); | |
| return '_wpgens_referral_invites_sent_' . $year; | |
| } | |
| /** | |
| * Block the invite request BEFORE any email is sent if it would exceed the cap. | |
| * Hooks the loyalty invite REST route: POST {namespace}/widget/customer/invite | |
| */ | |
| add_filter('rest_pre_dispatch', 'wpgl_enforce_referral_invite_cap', 10, 3); | |
| function wpgl_enforce_referral_invite_cap($result, $server, $request) | |
| { | |
| // Only act on the referral invite endpoint. | |
| if (strpos((string) $request->get_route(), '/widget/customer/invite') === false) { | |
| return $result; | |
| } | |
| $user_id = get_current_user_id(); | |
| if (!$user_id) { | |
| return $result; // let the plugin's own auth check handle it | |
| } | |
| // Count how many valid emails this request is trying to send. | |
| $emails = $request->get_param('emails'); | |
| $requested = 0; | |
| if (is_array($emails)) { | |
| foreach ($emails as $email) { | |
| if (is_email($email)) { | |
| $requested++; | |
| } | |
| } | |
| } | |
| if ($requested < 1) { | |
| return $result; // nothing valid to send, let the plugin respond | |
| } | |
| $cap = wpgl_get_user_invite_cap($user_id); | |
| $already_sent = (int) get_user_meta($user_id, wpgl_invite_count_meta_key($user_id), true); | |
| $remaining = max(0, $cap - $already_sent); | |
| if ($requested > $remaining) { | |
| return new WP_Error( | |
| 'wpgl_invite_limit_reached', | |
| sprintf( | |
| /* translators: 1: yearly cap, 2: remaining invites */ | |
| __('You can send up to %1$d referral invitations per year. You have %2$d left this year.', 'wpgens-loyalty'), | |
| $cap, | |
| $remaining | |
| ), | |
| array('status' => 429) | |
| ); | |
| } | |
| return $result; | |
| } | |
| /** | |
| * Increment the counter each time an invite email is actually sent. | |
| * Fires once per email from WPGL_Emails::send_referral_invite(). | |
| */ | |
| add_action('wpgens_loyalty_before_send_email', 'wpgl_count_referral_invite', 10, 2); | |
| function wpgl_count_referral_invite($email_type, $user_id) | |
| { | |
| if ($email_type !== 'referralInvite' || !$user_id) { | |
| return; | |
| } | |
| $key = wpgl_invite_count_meta_key($user_id); | |
| $count = (int) get_user_meta($user_id, $key, true); | |
| update_user_meta($user_id, $key, $count + 1); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment