Last active
May 19, 2025 10:53
-
-
Save goranefbl/c2d13778a4dcc5f065d277196b35ec77 to your computer and use it in GitHub Desktop.
class-points-hooks.php
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 | |
/** | |
* Handles all WordPress and WooCommerce hook integrations for the points system | |
*/ | |
class WPGL_Points_Hooks | |
{ | |
private static $instance = null; | |
/** | |
* Initialize the class and check if WooCommerce is active | |
* Creates singleton instance if not already created | |
*/ | |
public static function init() | |
{ | |
// Ensure WooCommerce is active | |
if (!function_exists('WC')) { | |
return; | |
} | |
if (self::$instance === null) { | |
self::$instance = new self(); | |
} | |
self::register_hooks(); | |
} | |
/** | |
* Register all WordPress hooks for the points system | |
* - Points earning hooks for registration and order completion | |
* - Display hooks for showing points in orders and products | |
* - Points expiration cron job | |
* - My Account page integration | |
*/ | |
public static function register_hooks() | |
{ | |
// Points earning hooks | |
add_action('user_register', [__CLASS__, 'award_registration_points']); | |
add_action('woocommerce_order_status_changed', [__CLASS__, 'award_order_points']); | |
add_action('woocommerce_order_status_cancelled', [__CLASS__, 'remove_order_points']); | |
add_action('comment_post', [__CLASS__, 'award_product_review_points'], 10, 3); | |
add_action('wpgens_loyalty_daily_cron', [__CLASS__, 'process_birthday_points']); | |
// AJAX handlers | |
add_action('wp_ajax_wpgens_loyalty_social_action', [__CLASS__, 'handle_social_action']); | |
// Display hooks | |
add_filter('woocommerce_get_order_item_totals', [__CLASS__, 'add_points_earned_to_order'], 10, 2); | |
add_action('woocommerce_before_add_to_cart_form', [__CLASS__, 'display_points_earning_above_price'], 10); | |
// Account hooks | |
add_action('woocommerce_edit_account_form', [__CLASS__, 'add_birthday_field']); | |
add_action('woocommerce_save_account_details', [__CLASS__, 'save_birthday_field']); | |
add_filter('woocommerce_account_menu_items', [__CLASS__, 'add_loyalty_points_endpoint']); | |
add_action('init', [__CLASS__, 'add_loyalty_points_endpoint_hook']); | |
add_action('woocommerce_account_loyalty-points_endpoint', [__CLASS__, 'loyalty_points_content']); | |
// Admin order display hooks | |
add_action('woocommerce_admin_order_totals_after_total', [__CLASS__, 'display_points_in_admin_order'], 10, 1); | |
// Calculate points when order is created | |
add_action('woocommerce_new_order', [self::class, 'calculate_order_points'], 10, 1); | |
} | |
/** | |
* Award points when a new user registers | |
* - Gets registration action from earning actions | |
* - Checks if registration points are enabled | |
* - Awards points using the loyalty_update_points action | |
* | |
* @param int $user_id New user ID | |
*/ | |
public static function award_registration_points($user_id) | |
{ | |
$earning_actions = WPGL_Points_Core::get_earning_actions(); | |
$registration_action = array_filter($earning_actions, function ($action) { | |
return $action['type'] === WPGL_Points_Source_Type::REGISTRATION && $action['enabled']; | |
}); | |
if (!empty($registration_action)) { | |
$action = reset($registration_action); | |
$points = $action['points']; | |
if ($points > 0) { | |
do_action( | |
'wpgens_loyalty_update_points', | |
$user_id, | |
$points, | |
WPGL_Points_Activity_Type::EARN, | |
WPGL_Points_Source_Type::REGISTRATION, | |
null | |
); | |
} | |
} | |
// Check for guest order points to award | |
$settings = WPGL_Points_Core::get_settings(); | |
if (!$settings['assignToGuests']) { | |
return; | |
} | |
// Get user email | |
$user = get_userdata($user_id); | |
if (!$user || !$user->user_email || !function_exists('wc_get_orders')) { | |
return; | |
} | |
// Find orders with this email that have guest points | |
$orders = wc_get_orders(array( | |
'billing_email' => $user->user_email, | |
'meta_key' => '_wpgens_loyalty_guest_points', | |
'meta_compare' => 'EXISTS', | |
)); | |
foreach ($orders as $order) { | |
$guest_points = $order->get_meta('_wpgens_loyalty_guest_points'); | |
if ($guest_points > 0) { | |
// Award the points | |
do_action( | |
'wpgens_loyalty_update_points', | |
$user_id, | |
$guest_points, | |
WPGL_Points_Activity_Type::EARN, | |
WPGL_Points_Source_Type::PLACE_ORDER, | |
$order->get_id() | |
); | |
// Remove the guest points meta to prevent double awarding | |
$order->delete_meta_data('_wpgens_loyalty_guest_points'); | |
$order->save(); | |
// Add awarded flag | |
$order->update_meta_data('_wpgens_loyalty_points_awarded', true); | |
$order->update_meta_data('_wpgens_loyalty_points_amount', $guest_points); | |
$order->save(); | |
} | |
} | |
} | |
/** | |
* Award points when an order status changes | |
* - Uses pre-calculated points from order meta | |
* - Prevents duplicate points awards | |
* | |
* @param int $order_id WooCommerce order ID | |
*/ | |
public static function award_order_points($order_id) | |
{ | |
// Debug logging | |
WPGL_Logger::order("Starting points calculation for order", [ | |
'order_id' => $order_id | |
]); | |
// Ensure WooCommerce is loaded | |
if (!function_exists('wc_get_order')) { | |
WPGL_Logger::order("WooCommerce not loaded, aborting points calculation"); | |
return; | |
} | |
/** @disregard */ | |
$order = wc_get_order($order_id); | |
if (!$order) { | |
WPGL_Logger::order("Order not found", [ | |
'order_id' => $order_id | |
]); | |
return; | |
} | |
// Get settings | |
$settings = WPGL_Points_Core::get_settings(); | |
$allowed_statuses = isset($settings['orderStatuses']) ? $settings['orderStatuses'] : ['completed']; | |
$assign_to_guests = isset($settings['assignToGuests']) ? $settings['assignToGuests'] : false; | |
// Check if current order status is allowed | |
if (!in_array($order->get_status(), $allowed_statuses)) { | |
WPGL_Logger::order("Order status not in allowed statuses", [ | |
'order_id' => $order_id, | |
'status' => $order->get_status(), | |
'allowed_statuses' => $allowed_statuses | |
]); | |
return; | |
} | |
// Skip if points were already awarded | |
if ($order->get_meta('_wpgens_loyalty_points_awarded')) { | |
WPGL_Logger::order("Points already awarded", [ | |
'order_id' => $order_id | |
]); | |
return; | |
} | |
// Get pre-calculated points | |
$total_points = $order->get_meta('_wpgens_loyalty_points_amount'); | |
if (!$total_points) { | |
WPGL_Logger::order("No pre-calculated points found", [ | |
'order_id' => $order_id | |
]); | |
return; | |
} | |
// Get user ID from order | |
$user_id = $order->get_user_id(); | |
// If no user ID but assignToGuests is enabled, try to find user by email | |
if (!$user_id && $assign_to_guests) { | |
$billing_email = $order->get_billing_email(); | |
if ($billing_email) { | |
// Try to find a user with this email | |
$user = get_user_by('email', $billing_email); | |
if ($user) { | |
$user_id = $user->ID; | |
WPGL_Logger::order("Found registered user by email for guest order", [ | |
'order_id' => $order_id, | |
'email' => $billing_email, | |
'user_id' => $user_id | |
]); | |
} | |
} | |
} | |
// If still no user ID and not assigning to guests, exit | |
if (!$user_id && !$assign_to_guests) { | |
WPGL_Logger::order("No user ID found and assignToGuests is disabled", [ | |
'order_id' => $order_id | |
]); | |
return; | |
} | |
WPGL_Logger::points("Awarding points for order", [ | |
'order_id' => $order_id, | |
'total_points' => $total_points, | |
'user_id' => $user_id ?: 'guest' | |
]); | |
// If we have a user ID, award points to that user | |
if ($user_id) { | |
$result = do_action( | |
'wpgens_loyalty_update_points', | |
$user_id, | |
$total_points, | |
WPGL_Points_Activity_Type::EARN, | |
WPGL_Points_Source_Type::PLACE_ORDER, | |
$order_id | |
); | |
} else { | |
// For guest orders with assignToGuests enabled, store points with order | |
// These can be claimed later if the guest creates an account | |
$order->update_meta_data('_wpgens_loyalty_guest_points', $total_points); | |
$result = true; | |
WPGL_Logger::order("Stored points for guest order", [ | |
'order_id' => $order_id, | |
'points' => $total_points | |
]); | |
} | |
if ($result !== false) { | |
// Mark order as points awarded | |
$order->update_meta_data('_wpgens_loyalty_points_awarded', true); | |
$order->save(); | |
WPGL_Logger::order("Successfully saved points metadata", [ | |
'order_id' => $order_id, | |
'total_points' => $total_points | |
]); | |
} else { | |
WPGL_Logger::order("Failed to update points", [ | |
'order_id' => $order_id | |
]); | |
} | |
} | |
/** | |
* Add points information to order totals display | |
* Shows points earned in customer emails and my account order view | |
* | |
* @param array $total_rows Existing order total rows | |
* @param WC_Order $order Order object | |
* @return array Modified total rows | |
*/ | |
public static function add_points_earned_to_order($total_rows, $order) | |
{ | |
// Skip if no points or if in admin | |
if (is_admin() || !($points_earned = $order->get_meta('_wpgens_loyalty_points_amount'))) { | |
return $total_rows; | |
} | |
$total_rows['points_earned'] = array( | |
'label' => sprintf( | |
/* translators: %s: Points label */ | |
__('%s earned:', 'wpgens-points-and-rewards-program'), | |
WPGL_Points_Core::get_points_label($points_earned) | |
), | |
'value' => sprintf( | |
'%d', | |
$points_earned | |
) | |
); | |
return $total_rows; | |
} | |
/** | |
* Add birthday field to account details | |
*/ | |
public static function add_birthday_field() | |
{ | |
// Check if WooCommerce is active | |
if (!function_exists('woocommerce_form_field')) { | |
return; | |
} | |
$user_id = get_current_user_id(); | |
$birthday = get_user_meta($user_id, '_wpgens_loyalty_birthday', true); | |
// Check if birthday points are enabled | |
$earning_actions = WPGL_Points_Core::get_earning_actions(); | |
$birthday_action = array_filter($earning_actions, function ($action) { | |
return $action['type'] === WPGL_Points_Source_Type::BIRTHDAY && $action['enabled']; | |
}); | |
if (empty($birthday_action)) { | |
return; | |
} | |
// Add before the save button | |
echo '<fieldset>'; | |
echo '<legend>' . esc_html__('Loyalty Program', 'wpgens-points-and-rewards-program') . '</legend>'; | |
/** @disregard */ | |
woocommerce_form_field('wpgens_loyalty_birthday', array( | |
'type' => 'date', | |
'class' => array('form-row-wide'), | |
'label' => esc_html__('Birthday', 'wpgens-points-and-rewards-program'), | |
'required' => false, | |
'clear' => true | |
), $birthday); | |
echo '</fieldset>'; | |
} | |
/** | |
* Save birthday field from account details | |
*/ | |
public static function save_birthday_field($user_id) | |
{ | |
// Verify nonce for account details form | |
if (!isset($_POST['save-account-details-nonce']) || !wp_verify_nonce(sanitize_key($_POST['save-account-details-nonce']), 'save_account_details')) { | |
return; | |
} | |
if (isset($_POST['wpgens_loyalty_birthday'])) { | |
$birthday = sanitize_text_field(wp_unslash($_POST['wpgens_loyalty_birthday'])); | |
update_user_meta($user_id, '_wpgens_loyalty_birthday', $birthday); | |
} | |
} | |
/** | |
* Process birthday points daily | |
* - Runs via cron job | |
* - Checks for users with birthdays today | |
* - Awards points if not already awarded this year | |
*/ | |
public static function process_birthday_points() | |
{ | |
global $wpdb; | |
// Get birthday action from earning actions | |
$earning_actions = WPGL_Points_Core::get_earning_actions(); | |
$birthday_action = array_filter($earning_actions, function ($action) { | |
return $action['type'] === WPGL_Points_Source_Type::BIRTHDAY && $action['enabled']; | |
}); | |
if (empty($birthday_action)) { | |
return; | |
} | |
$action = reset($birthday_action); | |
$points = $action['points']; | |
if ($points <= 0) return; | |
// Get current month and day | |
$today = current_time('Y-m-d'); | |
$current_month_day = gmdate('m-d', strtotime($today)); | |
$current_year = gmdate('Y', strtotime($today)); | |
// Direct query is used for performance with large user bases | |
// Caching is not beneficial as this runs infrequently via cron and data changes regularly | |
// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery | |
// phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching | |
// Get users with birthdays today | |
$users = $wpdb->get_results($wpdb->prepare( | |
"SELECT user_id, meta_value as birthday | |
FROM {$wpdb->usermeta} | |
WHERE meta_key = '_wpgens_loyalty_birthday' | |
AND DATE_FORMAT(meta_value, '%%m-%%d') = %s", | |
$current_month_day | |
)); | |
// phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery | |
// phpcs:enable WordPress.DB.DirectDatabaseQuery.NoCaching | |
foreach ($users as $user) { | |
// Check if points were already awarded this year | |
$last_birthday_points = get_user_meta($user->user_id, '_wpgens_loyalty_last_birthday_points', true); | |
if ($last_birthday_points === $current_year) { | |
continue; | |
} | |
// Award points | |
do_action( | |
'wpgens_loyalty_update_points', | |
$user->user_id, | |
$points, | |
WPGL_Points_Activity_Type::EARN, | |
WPGL_Points_Source_Type::BIRTHDAY, | |
null | |
); | |
// Mark points as awarded for this year | |
update_user_meta($user->user_id, '_wpgens_loyalty_last_birthday_points', $current_year); | |
} | |
} | |
/** | |
* Display loyalty points content in My Account | |
* - Loads template for loyalty points page | |
* - Shows points balance and history | |
*/ | |
public static function loyalty_points_content() | |
{ | |
// Check if in test mode | |
$test_mode = get_option(WPGL_Points_Settings::OPTION_TEST_MODE, '0') === '1'; | |
// If in test mode, only show to admins | |
if ($test_mode && !current_user_can('manage_options')) { | |
wp_die(esc_html__('This feature is only available to administrators in test mode.', 'wpgens-points-and-rewards-program')); | |
} | |
// Birthday notice has been removed from here and moved to the birthday box in points-earn.php | |
WPGL_Template_Loader::get_template('myaccount-loyalty-points.php'); | |
} | |
/** | |
* Display points earning notice above product price | |
*/ | |
public static function display_points_earning_above_price() | |
{ | |
$branding = WPGL_Points_Core::get_branding(); | |
if (!$branding['showPointsEarningAboveProductPrice']) { | |
return; | |
} | |
global $product; | |
if (!$product) return; | |
// Get points using product-level settings or fallback to general settings | |
$points = WPGL_Points_Products::get_product_points($product); | |
if ($points === false) return; | |
if ($points <= 0) return; | |
echo '<div class="wpgens-product-single-earning-notice">'; | |
echo '<svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg"> | |
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.40585 5.78711C8.23261 5.4368 8.13525 5.04227 8.13525 4.625C8.13525 3.17525 9.31051 2 10.7603 2C11.4948 2 12.1588 2.30168 12.6353 2.78788C13.1117 2.30168 13.7757 2 14.5103 2C15.96 2 17.1353 3.17525 17.1353 4.625C17.1353 5.04227 17.0379 5.4368 16.8647 5.78711H19.1433C20.386 5.78711 21.3933 6.79447 21.3933 8.03711V8.50001C21.3933 9.31501 20.96 10.0288 20.3112 10.4236V19C20.3112 20.2426 19.3038 21.25 18.0612 21.25H7.2096C5.96696 21.25 4.9596 20.2426 4.9596 19V10.4236C4.31077 10.0288 3.87744 9.31501 3.87744 8.50001V8.03711C3.87744 6.79447 4.8848 5.78711 6.12744 5.78711H8.40585ZM14.5103 3.5C13.8889 3.5 13.3853 4.00368 13.3853 4.625V5.75H14.5103C15.1316 5.75 15.6353 5.24632 15.6353 4.625C15.6353 4.00368 15.1316 3.5 14.5103 3.5ZM11.8853 5.75V4.625C11.8853 4.00368 11.3816 3.5 10.7603 3.5C10.1389 3.5 9.63525 4.00368 9.63525 4.625C9.63525 5.24632 10.1389 5.75 10.7603 5.75H11.8853ZM18.8112 10.75H6.4596V19C6.4596 19.4142 6.79538 19.75 7.2096 19.75H18.0612C18.4754 19.75 18.8112 19.4142 18.8112 19V10.75ZM19.1433 9.25001C19.5576 9.25001 19.8933 8.91422 19.8933 8.50001V8.03711C19.8933 7.6229 19.5576 7.28711 19.1433 7.28711H6.12744C5.71323 7.28711 5.37744 7.6229 5.37744 8.03711V8.50001C5.37744 8.91422 5.71323 9.25001 6.12744 9.25001H19.1433Z" fill="#323544"/> | |
</svg>'; | |
// Get template and replace dynamic tags | |
$template = isset($branding['pointsEarningTemplate']) ? $branding['pointsEarningTemplate'] : 'Earn {{points}} {{points_label}} when you buy this product!'; | |
// Replace dynamic tags | |
$points_label = WPGL_Points_Core::get_points_label($points); | |
// phpcs:ignore Generic.PHP.ForbiddenFunctions.Found | |
$product_price = wc_price($product->get_price()); | |
$replacements = [ | |
'{{points}}' => esc_html($points), | |
'{{points_label}}' => esc_html($points_label), | |
'{{product_price}}' => $product_price | |
]; | |
$message = str_replace(array_keys($replacements), array_values($replacements), $template); | |
echo wp_kses_post($message); | |
echo '</div>'; | |
} | |
/** | |
* Display points in admin order totals section | |
* Shows breakdown of points per product | |
* | |
* @param int $order_id Order ID | |
*/ | |
public static function display_points_in_admin_order($order_id) | |
{ | |
/** @disregard */ | |
$order = wc_get_order($order_id); | |
if (!$order) return; | |
// Check if points were actually awarded | |
$points_awarded = $order->get_meta('_wpgens_loyalty_points_awarded'); | |
$points_earned = $order->get_meta('_wpgens_loyalty_points_amount'); | |
// If in test mode, only show for admin users | |
$test_mode = get_option(WPGL_Points_Settings::OPTION_TEST_MODE, '0') === '1'; | |
$user_id = $order->get_user_id(); | |
$user = get_userdata($user_id); | |
if ($test_mode && (!$user || !in_array('administrator', (array) $user->roles))) { | |
return; | |
} | |
if (!$points_earned) return; | |
echo '<tr>'; | |
echo '<td class="label">' . esc_html__('Points Earned:', 'wpgens-points-and-rewards-program') . '</td>'; | |
echo '<td width="1%"></td>'; | |
echo '<td class="total">'; | |
// Display total points with awarded status | |
echo '<strong>' . esc_html($points_earned) . ' ' . esc_html__('points', 'wpgens-points-and-rewards-program'); | |
if ($test_mode) { | |
echo ' (' . esc_html__('Test Mode', 'wpgens-points-and-rewards-program') . ')'; | |
} | |
if (!$points_awarded) { | |
echo ' (' . esc_html__('Not Awarded', 'wpgens-points-and-rewards-program') . ')'; | |
} | |
echo '</strong><br/>'; | |
// Display points breakdown per item | |
foreach ($order->get_items() as $item) { | |
$item_points = $item->get_meta('_wpgens_loyalty_points_earned'); | |
if ($item_points) { | |
$product_total = $item->get_total(); | |
/** @disregard */ | |
$message = sprintf( | |
/* translators: %1$s: Product name, %2$d: Points earned, %3$s: Formatted price, %4$d: Points rate per currency unit */ | |
esc_html__('→ %1$s: %2$d points (%3$s × %4$d points/currency)', 'wpgens-points-and-rewards-program'), | |
esc_html($item->get_name()), | |
intval($item_points), | |
// phpcs:ignore WordPress.VIP.ValidatedSanitizedInput.InputNotValidated, WordPress.WP.I18n.NonSingularStringLiteralText | |
wc_price($product_total), | |
intval($order->get_meta('_wpgens_loyalty_points_rate')) | |
); | |
echo '<small>' . wp_kses_post($message) . '</small><br/>'; | |
} | |
} | |
echo '</td>'; | |
echo '</tr>'; | |
} | |
/** | |
* Remove points when order is cancelled | |
* | |
* @param int $order_id WooCommerce order ID | |
*/ | |
public static function remove_order_points($order_id) | |
{ | |
if (!function_exists('wc_get_order')) return; | |
/** @disregard */ | |
$order = wc_get_order($order_id); | |
if (!$order) return; | |
$points_earned = $order->get_meta('_wpgens_loyalty_points_amount'); | |
if (!$points_earned) return; | |
$user_id = $order->get_user_id(); | |
if (!$user_id) return; | |
// Remove the points | |
do_action( | |
'wpgens_loyalty_update_points', | |
$user_id, | |
-$points_earned, | |
WPGL_Points_Activity_Type::DEDUCT, | |
WPGL_Points_Source_Type::ORDER_CANCELLED, | |
$order_id | |
); | |
// Remove the meta to prevent double deduction | |
$order->delete_meta_data('_wpgens_loyalty_points_amount'); | |
$order->save(); | |
} | |
/** | |
* Award points when a user leaves a product review | |
* - Checks if review is for a product | |
* - Verifies user is logged in | |
* - Awards points using the loyalty_update_points action | |
* | |
* @param int $comment_id Comment/review ID | |
* @param int $comment_approved Comment approval status | |
* @param array $commentdata Comment data array | |
*/ | |
public static function award_product_review_points($comment_id, $comment_approved, $commentdata) | |
{ | |
// Check if this is a product review | |
if (empty($commentdata['comment_type']) || $commentdata['comment_type'] !== 'review') { | |
return; | |
} | |
// Get user ID | |
$user_id = get_current_user_id(); | |
if (!$user_id) return; | |
// Only award points for approved reviews | |
if ($comment_approved !== 1) return; | |
// Get review action from earning actions | |
$earning_actions = WPGL_Points_Core::get_earning_actions(); | |
$review_action = array_filter($earning_actions, function ($action) { | |
return $action['type'] === WPGL_Points_Source_Type::PRODUCT_REVIEW && $action['enabled']; | |
}); | |
if (empty($review_action)) { | |
return; | |
} | |
$action = reset($review_action); | |
$points = $action['points']; | |
if ($points <= 0) return; | |
// Check if user already got points for reviewing this product | |
$product_id = $commentdata['comment_post_ID']; | |
$previous_review = get_comments([ | |
'user_id' => $user_id, | |
'post_id' => $product_id, | |
'type' => 'review', | |
'count' => true, | |
'comment__not_in' => [$comment_id] | |
]); | |
if ($previous_review > 0) return; // User already has another review for this product | |
do_action( | |
'wpgens_loyalty_update_points', | |
$user_id, | |
$points, | |
WPGL_Points_Activity_Type::EARN, | |
WPGL_Points_Source_Type::PRODUCT_REVIEW, | |
$comment_id | |
); | |
} | |
/** | |
* Add loyalty points tab to My Account menu | |
* - Adds new menu item for loyalty points | |
* - Maintains logout at end of menu | |
* | |
* @param array $items Existing menu items | |
* @return array Modified menu items | |
*/ | |
public static function add_loyalty_points_endpoint($items) | |
{ | |
// Check if in test mode | |
$test_mode = get_option(WPGL_Points_Settings::OPTION_TEST_MODE, '0') === '1'; | |
// If in test mode, only show to admins | |
if ($test_mode && !current_user_can('manage_options')) { | |
return $items; | |
} | |
$logout = false; | |
if (isset($items['customer-logout'])) { | |
$logout = $items['customer-logout']; | |
unset($items['customer-logout']); | |
} | |
$items['loyalty-points'] = __('Loyalty Points', 'wpgens-points-and-rewards-program'); | |
if ($logout) { | |
$items['customer-logout'] = $logout; | |
} | |
return $items; | |
} | |
/** | |
* Register loyalty points endpoint for My Account | |
* - Creates new endpoint for loyalty points page | |
* - Used by WordPress for URL routing | |
*/ | |
public static function add_loyalty_points_endpoint_hook() | |
{ | |
add_rewrite_endpoint('loyalty-points', EP_ROOT | EP_PAGES); | |
} | |
/** | |
* Handle social action points award via AJAX | |
*/ | |
public static function handle_social_action() | |
{ | |
check_ajax_referer('loyalty_points_nonce', 'nonce'); | |
$user_id = get_current_user_id(); | |
if (!$user_id) { | |
wp_send_json_error(__('You must be logged in to perform this action.', 'wpgens-points-and-rewards-program')); | |
} | |
if (!isset($_POST['social_action'])) { | |
wp_send_json_error(__('Missing social action parameter.', 'wpgens-points-and-rewards-program')); | |
} | |
$social_action = sanitize_text_field(wp_unslash($_POST['social_action'])); | |
if (!$social_action) { | |
wp_send_json_error(__('Invalid action.', 'wpgens-points-and-rewards-program')); | |
} | |
// Get completed actions | |
$completed_actions = get_user_meta($user_id, '_wpgens_loyalty_completed_actions', true) ?: array(); | |
if (in_array($social_action, $completed_actions)) { | |
wp_send_json_error(__('You have already completed this action.', 'wpgens-points-and-rewards-program')); | |
} | |
// Get action details | |
$earning_actions = WPGL_Points_Core::get_earning_actions(); | |
$action = array_filter($earning_actions, function ($a) use ($social_action) { | |
return $a['type'] === $social_action && $a['enabled']; | |
}); | |
if (empty($action)) { | |
wp_send_json_error(__('Invalid or disabled action.', 'wpgens-points-and-rewards-program')); | |
} | |
$action = reset($action); | |
$points = $action['points']; | |
if ($points <= 0) { | |
wp_send_json_error(__('No points available for this action.', 'wpgens-points-and-rewards-program')); | |
} | |
// Award points | |
do_action( | |
'wpgens_loyalty_update_points', | |
$user_id, | |
$points, | |
WPGL_Points_Activity_Type::EARN, | |
$social_action | |
); | |
// Mark action as completed | |
$completed_actions[] = $social_action; | |
update_user_meta($user_id, '_wpgens_loyalty_completed_actions', $completed_actions); | |
wp_send_json_success(__('Points awarded successfully!', 'wpgens-points-and-rewards-program')); | |
} | |
/** | |
* Calculate and store points when an order is created | |
* | |
* @param int $order_id WooCommerce order ID | |
*/ | |
public static function calculate_order_points($order_id) | |
{ | |
// Debug logging | |
WPGL_Logger::order("Starting points calculation for new order", [ | |
'order_id' => $order_id | |
]); | |
// Ensure WooCommerce is loaded | |
if (!function_exists('wc_get_order')) { | |
WPGL_Logger::order("WooCommerce not loaded, aborting points calculation"); | |
return; | |
} | |
/** @disregard */ | |
$order = wc_get_order($order_id); | |
if (!$order) { | |
WPGL_Logger::order("Order not found", [ | |
'order_id' => $order_id | |
]); | |
return; | |
} | |
// Get settings | |
$settings = WPGL_Points_Core::get_settings(); | |
$exclude_taxes = isset($settings['conversionRate']['excludeTaxes']) ? $settings['conversionRate']['excludeTaxes'] : false; | |
// Get order action from earning actions | |
$earning_actions = WPGL_Points_Core::get_earning_actions(); | |
$order_action = array_filter($earning_actions, function ($action) { | |
return $action['type'] === WPGL_Points_Source_Type::PLACE_ORDER && $action['enabled']; | |
}); | |
if (empty($order_action)) { | |
WPGL_Logger::order("No enabled PLACE_ORDER action found in earning actions"); | |
return; | |
} | |
$action = reset($order_action); | |
$points_rate = $action['points']; // Points per currency unit | |
$total_points = 0; | |
WPGL_Logger::points("Starting product points calculation", [ | |
'points_rate' => $points_rate, | |
'exclude_taxes' => $exclude_taxes ? 'yes' : 'no' | |
]); | |
// Calculate points for each product | |
foreach ($order->get_items() as $item) { | |
$product = $item->get_product(); | |
if (!$product) { | |
WPGL_Logger::order("Product not found for item", [ | |
'order_id' => $order_id | |
]); | |
continue; | |
} | |
// Calculate the item price to use for points calculation | |
$item_price = $exclude_taxes ? $item->get_total() : ($item->get_total() + $item->get_total_tax()); | |
$unit_price = $item_price / $item->get_quantity(); | |
// Get points for this product using product-level settings or fallback to general settings | |
$product_points = WPGL_Points_Products::get_product_points($product, $unit_price); | |
if ($product_points !== false) { | |
$total_item_points = $product_points * $item->get_quantity(); | |
$total_points += $total_item_points; | |
WPGL_Logger::points("Product points calculated", [ | |
'product_id' => $product->get_id(), | |
'points' => $product_points, | |
'quantity' => $item->get_quantity(), | |
'total_points' => $total_item_points, | |
'price_used' => $unit_price, | |
'exclude_taxes' => $exclude_taxes ? 'yes' : 'no' | |
]); | |
// Store points earned for this specific item | |
$item->update_meta_data('_wpgens_loyalty_points_earned', $total_item_points); | |
$item->update_meta_data('_wpgens_loyalty_points_rate', $points_rate); | |
$item->save(); | |
} else { | |
WPGL_Logger::product("Product not eligible for points", [ | |
'product_id' => $product->get_id(), | |
'reason' => 'disabled or on sale' | |
]); | |
} | |
} | |
// Store total points in order meta | |
if ($total_points > 0) { | |
$order->update_meta_data('_wpgens_loyalty_points_amount', $total_points); | |
$order->update_meta_data('_wpgens_loyalty_points_rate', $points_rate); | |
$order->save(); | |
WPGL_Logger::order("Successfully stored calculated points", [ | |
'order_id' => $order_id, | |
'total_points' => $total_points, | |
'points_rate' => $points_rate | |
]); | |
} else { | |
WPGL_Logger::order("No points to store", [ | |
'order_id' => $order_id | |
]); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment