|
<?php |
|
/** |
|
* Must-Use Plugin: AffiliateWP Desired Coupon Code Field with Auto-Association |
|
* |
|
* Description: Complete solution that adds a "Desired Coupon Code" field to AffiliateWP |
|
* registration forms and automatically creates/associates WooCommerce coupons. |
|
* |
|
* Features: |
|
* - Custom field on registration form |
|
* - Input validation and sanitization |
|
* - Automatic WooCommerce coupon creation on approval |
|
* - Affiliate-coupon association for tracking |
|
* - Admin management interface |
|
* |
|
* @author Wbcom Designs |
|
* @version 2.0.0 |
|
*/ |
|
|
|
// Exit if accessed directly |
|
if ( ! defined( 'ABSPATH' ) ) { |
|
exit; |
|
} |
|
|
|
/** |
|
* ======================= |
|
* PART 1: FIELD FUNCTIONALITY |
|
* ======================= |
|
*/ |
|
|
|
/** |
|
* Sanitize the desired coupon code |
|
* |
|
* Rules: |
|
* - Allows only letters (A-Z), numbers (0-9), underscores (_), and hyphens (-) |
|
* - Converts to uppercase for consistency |
|
* |
|
* @param string $raw Raw input string |
|
* @return string Sanitized coupon code |
|
*/ |
|
function wb_affwp_sanitize_desired_coupon_code( $raw ) { |
|
$code = is_string( $raw ) ? $raw : ''; |
|
$code = wp_unslash( $code ); |
|
// Remove any characters that aren't alphanumeric, underscore, or hyphen |
|
$code = preg_replace( '/[^A-Z0-9_\-]/i', '', $code ); |
|
// Convert to uppercase for consistency |
|
$code = strtoupper( $code ); |
|
return $code; |
|
} |
|
|
|
/** |
|
* Add the Desired Coupon Code field to the frontend registration form |
|
* Using the hook that works with both shortcode and block-based forms |
|
*/ |
|
add_action( 'affwp_register_fields_before_submit', function() { |
|
// Get the submitted value (if form was submitted with errors) |
|
$value = isset( $_POST['desired_coupon_code'] ) |
|
? esc_attr( wb_affwp_sanitize_desired_coupon_code( $_POST['desired_coupon_code'] ) ) |
|
: ''; |
|
?> |
|
<p class="affwp-field affwp-field-text affwp-field-desired-coupon-code"> |
|
<label for="desired_coupon_code" class="affwp-field-label"> |
|
<?php esc_html_e( 'Desired Coupon Code', 'wbcom-affwp' ); ?> |
|
<span class="affwp-field-sublabel"><?php esc_html_e( '(optional)', 'wbcom-affwp' ); ?></span> |
|
</label> |
|
<input type="text" |
|
name="desired_coupon_code" |
|
id="desired_coupon_code" |
|
class="affwp-field-input" |
|
value="<?php echo $value; ?>" |
|
placeholder="<?php esc_attr_e( 'e.g., SAVE10', 'wbcom-affwp' ); ?>" |
|
/> |
|
<span class="affwp-field-description"> |
|
<?php esc_html_e( 'Request a custom coupon code for your referrals (3-20 characters, letters, numbers, hyphens and underscores only).', 'wbcom-affwp' ); ?> |
|
</span> |
|
</p> |
|
<?php |
|
}, 10 ); |
|
|
|
/** |
|
* Validate the Desired Coupon Code on form submission |
|
*/ |
|
add_action( 'affwp_process_register_form', function( $data ) { |
|
// Skip if field is empty (it's optional) |
|
if ( empty( $_POST['desired_coupon_code'] ) ) { |
|
return; |
|
} |
|
|
|
// Check if AffiliateWP is available |
|
if ( ! function_exists( 'affiliate_wp' ) ) { |
|
return; |
|
} |
|
|
|
// Sanitize the input |
|
$code = wb_affwp_sanitize_desired_coupon_code( $_POST['desired_coupon_code'] ); |
|
|
|
// Validate length (3-20 characters) |
|
if ( strlen( $code ) < 3 || strlen( $code ) > 20 ) { |
|
affiliate_wp()->register->add_error( |
|
'desired_coupon_code_length', |
|
__( 'Desired Coupon Code must be between 3 and 20 characters.', 'wbcom-affwp' ) |
|
); |
|
return; |
|
} |
|
|
|
// Check for duplicate WooCommerce coupons (if WooCommerce is active) |
|
if ( function_exists( 'wc_get_coupon_id_by_code' ) ) { |
|
$coupon_id = wc_get_coupon_id_by_code( $code ); |
|
if ( $coupon_id ) { |
|
affiliate_wp()->register->add_error( |
|
'desired_coupon_code_taken', |
|
__( 'Sorry, that coupon code is already in use. Please choose another.', 'wbcom-affwp' ) |
|
); |
|
return; |
|
} |
|
} |
|
}, 10 ); |
|
|
|
/** |
|
* Save the Desired Coupon Code after successful registration |
|
*/ |
|
add_action( 'affwp_post_insert_affiliate', function( $affiliate_id, $args ) { |
|
// Skip if no code was submitted |
|
if ( empty( $_POST['desired_coupon_code'] ) ) { |
|
return; |
|
} |
|
|
|
// Sanitize and save the code |
|
$code = wb_affwp_sanitize_desired_coupon_code( $_POST['desired_coupon_code'] ); |
|
if ( $code && function_exists( 'affwp_update_affiliate_meta' ) ) { |
|
affwp_update_affiliate_meta( (int) $affiliate_id, 'desired_coupon_code', $code ); |
|
} |
|
}, 10, 2 ); |
|
|
|
/** |
|
* Display the field in WordPress admin (Edit Affiliate screen) |
|
*/ |
|
add_action( 'affwp_edit_affiliate_end', function( $affiliate ) { |
|
// Ensure we have a valid affiliate object |
|
if ( ! $affiliate || empty( $affiliate->affiliate_id ) ) { |
|
return; |
|
} |
|
|
|
// Retrieve the saved coupon code |
|
$code = function_exists( 'affwp_get_affiliate_meta' ) |
|
? affwp_get_affiliate_meta( (int) $affiliate->affiliate_id, 'desired_coupon_code', true ) |
|
: ''; |
|
?> |
|
<tr class="form-row"> |
|
<th scope="row"> |
|
<label for="desired_coupon_code"> |
|
<?php esc_html_e( 'Desired Coupon Code', 'wbcom-affwp' ); ?> |
|
</label> |
|
</th> |
|
<td> |
|
<input type="text" |
|
name="desired_coupon_code" |
|
id="desired_coupon_code" |
|
value="<?php echo esc_attr( $code ); ?>" |
|
class="regular-text" /> |
|
<p class="description"> |
|
<?php esc_html_e( 'Affiliate\'s requested coupon code. This can be used for reference or automated coupon creation.', 'wbcom-affwp' ); ?> |
|
</p> |
|
</td> |
|
</tr> |
|
<?php |
|
}, 15 ); // Priority 15 to appear before the associated coupon field |
|
|
|
/** |
|
* Save the field from WordPress admin |
|
*/ |
|
add_action( 'affwp_update_affiliate', function( $data ) { |
|
// Ensure we have an affiliate ID |
|
if ( ! isset( $data['affiliate_id'] ) ) { |
|
return; |
|
} |
|
|
|
$affiliate_id = (int) $data['affiliate_id']; |
|
|
|
// Get and sanitize the submitted code |
|
$code = isset( $_POST['desired_coupon_code'] ) |
|
? wb_affwp_sanitize_desired_coupon_code( $_POST['desired_coupon_code'] ) |
|
: ''; |
|
|
|
// Update the affiliate meta |
|
if ( function_exists( 'affwp_update_affiliate_meta' ) ) { |
|
affwp_update_affiliate_meta( $affiliate_id, 'desired_coupon_code', $code ); |
|
} |
|
} ); |
|
|
|
/** |
|
* ======================= |
|
* PART 2: AUTO-ASSOCIATION |
|
* ======================= |
|
*/ |
|
|
|
/** |
|
* Automatically create and associate WooCommerce coupon when affiliate is approved |
|
*/ |
|
add_action( 'affwp_set_affiliate_status', function( $affiliate_id, $status, $old_status ) { |
|
|
|
// Only proceed when affiliate is being activated/approved |
|
if ( 'active' !== $status ) { |
|
return; |
|
} |
|
|
|
// Don't create duplicate if already active |
|
if ( 'active' === $old_status ) { |
|
return; |
|
} |
|
|
|
// Check if WooCommerce and AffiliateWP are active |
|
if ( ! function_exists( 'WC' ) || ! function_exists( 'affwp_get_affiliate_meta' ) ) { |
|
return; |
|
} |
|
|
|
// Get the desired coupon code |
|
$desired_code = affwp_get_affiliate_meta( $affiliate_id, 'desired_coupon_code', true ); |
|
|
|
// Skip if no desired code |
|
if ( empty( $desired_code ) ) { |
|
return; |
|
} |
|
|
|
// Check if coupon already exists |
|
$existing_coupon_id = wc_get_coupon_id_by_code( $desired_code ); |
|
|
|
if ( $existing_coupon_id ) { |
|
// Coupon already exists, just associate it with affiliate |
|
update_post_meta( $existing_coupon_id, 'affwp_discount_affiliate', $affiliate_id ); |
|
|
|
// Also store the coupon ID in affiliate meta for reference |
|
affwp_update_affiliate_meta( $affiliate_id, 'wc_coupon_id', $existing_coupon_id ); |
|
|
|
return; |
|
} |
|
|
|
// Get affiliate details |
|
$affiliate = affwp_get_affiliate( $affiliate_id ); |
|
$user = get_userdata( $affiliate->user_id ); |
|
|
|
// Prepare coupon settings (customize these as needed) |
|
$coupon_settings = apply_filters( 'affwp_auto_coupon_settings', [ |
|
'discount_type' => 'percent', // or 'fixed_cart', 'fixed_product' |
|
'coupon_amount' => '10', // 10% discount - customize as needed |
|
'individual_use' => 'no', |
|
'product_ids' => '', |
|
'excluded_product_ids' => '', |
|
'usage_limit' => '', |
|
'usage_limit_per_user' => '', |
|
'limit_usage_to_x_items' => '', |
|
'free_shipping' => 'no', |
|
'product_categories' => [], |
|
'excluded_product_categories' => [], |
|
'exclude_sale_items' => 'no', |
|
'minimum_amount' => '', |
|
'maximum_amount' => '', |
|
'email_restrictions' => [], |
|
'description' => sprintf( 'Affiliate coupon for %s (ID: %d)', $user->display_name, $affiliate_id ), |
|
], $affiliate_id, $desired_code ); |
|
|
|
// Create the coupon post |
|
$coupon_data = [ |
|
'post_title' => $desired_code, |
|
'post_content' => $coupon_settings['description'], |
|
'post_status' => 'publish', |
|
'post_author' => 1, |
|
'post_type' => 'shop_coupon', |
|
'post_excerpt' => $coupon_settings['description'], |
|
]; |
|
|
|
$new_coupon_id = wp_insert_post( $coupon_data ); |
|
|
|
if ( is_wp_error( $new_coupon_id ) ) { |
|
error_log( sprintf( 'Failed to create coupon for affiliate %d: %s', $affiliate_id, $new_coupon_id->get_error_message() ) ); |
|
return; |
|
} |
|
|
|
// Set coupon meta data |
|
foreach ( $coupon_settings as $key => $value ) { |
|
if ( 'description' !== $key ) { |
|
update_post_meta( $new_coupon_id, $key, $value ); |
|
} |
|
} |
|
|
|
// Associate coupon with affiliate for tracking |
|
update_post_meta( $new_coupon_id, 'affwp_discount_affiliate', $affiliate_id ); |
|
|
|
// Store the coupon ID in affiliate meta for easy reference |
|
affwp_update_affiliate_meta( $affiliate_id, 'wc_coupon_id', $new_coupon_id ); |
|
|
|
/** |
|
* Action hook after coupon is created and associated |
|
*/ |
|
do_action( 'affwp_after_auto_coupon_created', $new_coupon_id, $affiliate_id, $desired_code ); |
|
|
|
}, 10, 3 ); |
|
|
|
/** |
|
* Display associated coupon in affiliate admin area |
|
*/ |
|
add_action( 'affwp_edit_affiliate_end', function( $affiliate ) { |
|
|
|
if ( ! function_exists( 'WC' ) ) { |
|
return; |
|
} |
|
|
|
$coupon_id = affwp_get_affiliate_meta( $affiliate->affiliate_id, 'wc_coupon_id', true ); |
|
|
|
if ( ! $coupon_id ) { |
|
return; |
|
} |
|
|
|
$coupon = get_post( $coupon_id ); |
|
|
|
if ( ! $coupon || 'shop_coupon' !== $coupon->post_type ) { |
|
return; |
|
} |
|
|
|
$edit_link = get_edit_post_link( $coupon_id ); |
|
$coupon_amount = get_post_meta( $coupon_id, 'coupon_amount', true ); |
|
$discount_type = get_post_meta( $coupon_id, 'discount_type', true ); |
|
|
|
?> |
|
<tr class="form-row"> |
|
<th scope="row"> |
|
<label><?php esc_html_e( 'Associated WooCommerce Coupon', 'wbcom-affwp' ); ?></label> |
|
</th> |
|
<td> |
|
<strong><?php echo esc_html( $coupon->post_title ); ?></strong> |
|
<?php if ( $edit_link ) : ?> |
|
<a href="<?php echo esc_url( $edit_link ); ?>" target="_blank" style="margin-left: 10px;"> |
|
<?php esc_html_e( 'Edit Coupon', 'wbcom-affwp' ); ?> |
|
</a> |
|
<?php endif; ?> |
|
<p class="description"> |
|
<?php |
|
printf( |
|
esc_html__( 'Discount: %s%s', 'wbcom-affwp' ), |
|
esc_html( $coupon_amount ), |
|
'percent' === $discount_type ? '%' : ' ' . get_woocommerce_currency_symbol() |
|
); |
|
?> |
|
</p> |
|
</td> |
|
</tr> |
|
<?php |
|
}, 20 ); |
|
|
|
/** |
|
* Track referrals when the associated coupon is used |
|
* This ensures that when a customer uses an affiliate's coupon, |
|
* the sale is tracked as a referral for that affiliate |
|
*/ |
|
add_action( 'woocommerce_checkout_order_processed', function( $order_id ) { |
|
|
|
if ( ! function_exists( 'affwp_get_affiliate' ) ) { |
|
return; |
|
} |
|
|
|
$order = wc_get_order( $order_id ); |
|
|
|
if ( ! $order ) { |
|
return; |
|
} |
|
|
|
// Get applied coupons |
|
$coupons = $order->get_coupon_codes(); |
|
|
|
if ( empty( $coupons ) ) { |
|
return; |
|
} |
|
|
|
foreach ( $coupons as $coupon_code ) { |
|
$coupon_id = wc_get_coupon_id_by_code( $coupon_code ); |
|
|
|
if ( ! $coupon_id ) { |
|
continue; |
|
} |
|
|
|
// Check if this coupon is associated with an affiliate |
|
$affiliate_id = get_post_meta( $coupon_id, 'affwp_discount_affiliate', true ); |
|
|
|
if ( ! $affiliate_id ) { |
|
continue; |
|
} |
|
|
|
// Verify affiliate exists and is active |
|
$affiliate = affwp_get_affiliate( $affiliate_id ); |
|
|
|
if ( ! $affiliate || 'active' !== $affiliate->status ) { |
|
continue; |
|
} |
|
|
|
// Set affiliate tracking cookie to ensure proper attribution |
|
$affwp_ref = affwp_get_affiliate_username( $affiliate_id ); |
|
|
|
if ( $affwp_ref ) { |
|
// Set tracking cookie (30 days default) |
|
setcookie( |
|
'affwp_ref', |
|
$affwp_ref, |
|
time() + ( 30 * 24 * 60 * 60 ), |
|
COOKIEPATH, |
|
COOKIE_DOMAIN, |
|
is_ssl(), |
|
true |
|
); |
|
|
|
// Also set visit tracking |
|
setcookie( |
|
'affwp_ref_visit_id', |
|
uniqid(), |
|
time() + ( 30 * 24 * 60 * 60 ), |
|
COOKIEPATH, |
|
COOKIE_DOMAIN, |
|
is_ssl(), |
|
true |
|
); |
|
} |
|
|
|
// Only attribute to first affiliate coupon found |
|
break; |
|
} |
|
|
|
}, 5 ); // Run early to set cookies before referral is tracked |
|
|
|
/** |
|
* ======================= |
|
* PART 3: ADMIN ENHANCEMENTS |
|
* ======================= |
|
*/ |
|
|
|
/** |
|
* Add coupon column to affiliates list table |
|
*/ |
|
add_filter( 'affwp_affiliate_table_columns', function( $columns ) { |
|
$columns['coupon'] = __( 'Coupon Code', 'wbcom-affwp' ); |
|
return $columns; |
|
} ); |
|
|
|
/** |
|
* Display coupon code in affiliates list table |
|
*/ |
|
add_filter( 'affwp_affiliate_table_coupon', function( $value, $affiliate ) { |
|
|
|
$desired_code = affwp_get_affiliate_meta( $affiliate->affiliate_id, 'desired_coupon_code', true ); |
|
$coupon_id = affwp_get_affiliate_meta( $affiliate->affiliate_id, 'wc_coupon_id', true ); |
|
|
|
if ( $desired_code ) { |
|
if ( $coupon_id && get_post( $coupon_id ) ) { |
|
// Coupon exists and is active |
|
$edit_link = get_edit_post_link( $coupon_id ); |
|
return sprintf( |
|
'<strong style="color: green;">%s</strong> <a href="%s" target="_blank" style="text-decoration: none;">✏️</a>', |
|
esc_html( $desired_code ), |
|
esc_url( $edit_link ) |
|
); |
|
} else { |
|
// Coupon requested but not yet created |
|
return sprintf( |
|
'<em style="color: orange;">%s (pending)</em>', |
|
esc_html( $desired_code ) |
|
); |
|
} |
|
} |
|
|
|
return '—'; |
|
|
|
}, 10, 2 ); |
|
|
|
/** |
|
* Add admin notice for successful coupon creation |
|
*/ |
|
add_action( 'admin_notices', function() { |
|
if ( isset( $_GET['affwp_coupon_created'] ) && $_GET['affwp_coupon_created'] ) { |
|
?> |
|
<div class="notice notice-success is-dismissible"> |
|
<p><?php esc_html_e( 'WooCommerce coupon has been created and associated with the affiliate!', 'wbcom-affwp' ); ?></p> |
|
</div> |
|
<?php |
|
} |
|
} ); |
|
|
|
/** |
|
* USAGE NOTES: |
|
* |
|
* 1. Installation: |
|
* - Save this file to wp-content/mu-plugins/ folder |
|
* - It will load automatically (no activation needed) |
|
* |
|
* 2. Configuration: |
|
* - Default discount: 10% (modify via affwp_auto_coupon_settings filter) |
|
* - Field is optional on registration |
|
* - Coupons created when affiliate is approved |
|
* |
|
* 3. To retrieve data: |
|
* $coupon_code = affwp_get_affiliate_meta( $affiliate_id, 'desired_coupon_code', true ); |
|
* $coupon_id = affwp_get_affiliate_meta( $affiliate_id, 'wc_coupon_id', true ); |
|
* |
|
* 4. Hooks available: |
|
* - affwp_auto_coupon_settings - Modify coupon settings |
|
* - affwp_after_auto_coupon_created - After coupon is created |
|
*/ |