Skip to content

Instantly share code, notes, and snippets.

@goranefbl
Last active May 19, 2025 10:53
Show Gist options
  • Save goranefbl/c2d13778a4dcc5f065d277196b35ec77 to your computer and use it in GitHub Desktop.
Save goranefbl/c2d13778a4dcc5f065d277196b35ec77 to your computer and use it in GitHub Desktop.
class-points-hooks.php
<?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