Skip to main content

SLoyalty Integration

ScentLok uses SLoyalty for customer loyalty and rewards program, allowing customers to earn and redeem points on purchases.

Overview

Platform: SLoyalty
API Key: e6838c7d
Purpose: Loyalty points, rewards, and customer retention

Key Features

  • Points earning on purchases
  • Tiered rewards program
  • Customer account widget
  • Checkout integration
  • Points redemption
  • Custom domain configuration

Configuration

API Credentials

// wp-config.php
define( 'SLOYALTY_API_KEY', 'e6838c7d' );
define( 'SLOYALTY_API_URL', 'https://api.sloyalty.com/v1' );
define( 'SLOYALTY_WIDGET_URL', 'https://widget.sloyalty.com' );

Checkout Domain

// Configure checkout domain for SLoyalty tracking
add_filter( 'bigcommerce/checkout/url', function( $url, $cart_id ) {
// Add SLoyalty tracking parameter
$url = add_query_arg([
'sloyalty_track' => 'true',
'sloyalty_key' => SLOYALTY_API_KEY,
], $url );

return $url;
}, 10, 2 );

Widget Integration

Account Widget

Display customer points balance and rewards:

// Add SLoyalty account widget shortcode
add_shortcode( 'sloyalty_account', function( $atts ) {
if ( ! is_user_logged_in() ) {
return '<p>Please log in to view your rewards.</p>';
}

$user = wp_get_current_user();
$customer_data = get_sloyalty_customer( $user->user_email );

if ( ! $customer_data ) {
return '<p>Unable to load rewards data.</p>';
}

ob_start();
?>
<div class="sloyalty-account-widget">
<div class="points-balance bg-gradient-to-r from-primary to-secondary p-6 rounded-lg text-white mb-6">
<div class="flex items-center justify-between">
<div>
<p class="text-sm opacity-90">Your Points Balance</p>
<p class="text-4xl font-bold"><?php echo number_format( $customer_data['points_balance'] ); ?></p>
</div>
<div class="tier-badge">
<span class="bg-white bg-opacity-20 px-4 py-2 rounded-full text-sm font-semibold">
<?php echo esc_html( $customer_data['tier_name'] ); ?> Member
</span>
</div>
</div>
</div>

<div class="rewards-grid grid grid-cols-1 md:grid-cols-2 gap-4 mb-6">
<div class="reward-card bg-white p-4 rounded-lg shadow">
<h4 class="font-semibold mb-2">Points Earned</h4>
<p class="text-2xl font-bold text-primary">
<?php echo number_format( $customer_data['lifetime_points'] ); ?>
</p>
</div>

<div class="reward-card bg-white p-4 rounded-lg shadow">
<h4 class="font-semibold mb-2">Points Redeemed</h4>
<p class="text-2xl font-bold text-secondary">
<?php echo number_format( $customer_data['points_redeemed'] ); ?>
</p>
</div>
</div>

<div class="available-rewards">
<h3 class="text-xl font-bold mb-4">Available Rewards</h3>
<div class="rewards-list space-y-4">
<?php foreach ( $customer_data['available_rewards'] as $reward ) : ?>
<div class="reward-item flex items-center justify-between p-4 border rounded-lg">
<div>
<h4 class="font-semibold"><?php echo esc_html( $reward['name'] ); ?></h4>
<p class="text-sm text-gray-600"><?php echo esc_html( $reward['description'] ); ?></p>
<p class="text-primary font-semibold mt-1">
<?php echo number_format( $reward['points_required'] ); ?> points
</p>
</div>
<button
class="btn-primary px-4 py-2 rounded-md"
data-reward-id="<?php echo esc_attr( $reward['id'] ); ?>"
<?php disabled( $customer_data['points_balance'] < $reward['points_required'] ); ?>
>
Redeem
</button>
</div>
<?php endforeach; ?>
</div>
</div>

<div class="points-history mt-6">
<h3 class="text-xl font-bold mb-4">Points History</h3>
<div class="history-list space-y-2">
<?php foreach ( $customer_data['recent_transactions'] as $transaction ) : ?>
<div class="transaction flex items-center justify-between p-3 bg-gray-50 rounded">
<div>
<p class="font-medium"><?php echo esc_html( $transaction['description'] ); ?></p>
<p class="text-sm text-gray-600">
<?php echo date( 'M j, Y', strtotime( $transaction['date'] ) ); ?>
</p>
</div>
<span class="<?php echo $transaction['points'] > 0 ? 'text-green-600' : 'text-red-600'; ?> font-semibold">
<?php echo $transaction['points'] > 0 ? '+' : ''; ?>
<?php echo number_format( $transaction['points'] ); ?>
</span>
</div>
<?php endforeach; ?>
</div>
</div>
</div>

<script>
// Handle reward redemption
document.querySelectorAll('.btn-primary[data-reward-id]').forEach(button => {
button.addEventListener('click', async function() {
const rewardId = this.dataset.rewardId;

if (!confirm('Are you sure you want to redeem this reward?')) {
return;
}

this.disabled = true;
this.textContent = 'Redeeming...';

try {
const response = await fetch('/wp-json/sloyalty/v1/redeem', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ reward_id: rewardId })
});

if (response.ok) {
alert('Reward redeemed successfully!');
location.reload();
} else {
throw new Error('Redemption failed');
}
} catch (error) {
alert('Unable to redeem reward. Please try again.');
this.disabled = false;
this.textContent = 'Redeem';
}
});
});
</script>
<?php
return ob_get_clean();
});

Product Page Widget

Display points earning potential on product pages:

// Add points earning display to product pages
add_action( 'bigcommerce/product/after_price', function( $post_id ) {
$price = get_post_meta( $post_id, 'bc_price', true );
$points = calculate_points_earned( $price );
?>
<div class="sloyalty-product-widget flex items-center gap-2 my-4">
<svg class="w-5 h-5 text-primary" fill="currentColor" viewBox="0 0 20 20">
<path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/>
</svg>
<span class="text-sm">
Earn <strong class="text-primary"><?php echo number_format( $points ); ?> points</strong> with this purchase
</span>
</div>
<?php
});

function calculate_points_earned( $price ) {
// 1 point per dollar spent
return floor( $price );
}

Mini Widget

Display points balance in header/menu:

// Mini points widget for header
function sloyalty_mini_widget() {
if ( ! is_user_logged_in() ) {
return '';
}

$user = wp_get_current_user();
$balance = get_sloyalty_balance( $user->user_email );

ob_start();
?>
<div class="sloyalty-mini-widget">
<a href="<?php echo home_url( '/account/rewards' ); ?>" class="flex items-center gap-2 text-sm">
<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 20 20">
<path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/>
</svg>
<span><?php echo number_format( $balance ); ?> Points</span>
</a>
</div>
<?php
return ob_get_clean();
}

API Integration

Get Customer Data

function get_sloyalty_customer( $email ) {
$cache_key = 'sloyalty_customer_' . md5( $email );
$customer = wp_cache_get( $cache_key );

if ( false === $customer ) {
$url = SLOYALTY_API_URL . '/customers/' . urlencode( $email );

$response = wp_remote_get( $url, [
'headers' => [
'Authorization' => 'Bearer ' . SLOYALTY_API_KEY,
'Content-Type' => 'application/json',
],
]);

if ( is_wp_error( $response ) ) {
error_log( 'SLoyalty API Error: ' . $response->get_error_message() );
return false;
}

$body = wp_remote_retrieve_body( $response );
$customer = json_decode( $body, true );

if ( isset( $customer['data'] ) ) {
$customer = $customer['data'];
wp_cache_set( $cache_key, $customer, '', 5 * MINUTE_IN_SECONDS );
}
}

return $customer;
}

function get_sloyalty_balance( $email ) {
$customer = get_sloyalty_customer( $email );
return $customer ? $customer['points_balance'] : 0;
}

Add Points Transaction

function add_sloyalty_points( $email, $points, $description ) {
$url = SLOYALTY_API_URL . '/transactions';

$data = [
'customer_email' => $email,
'points' => $points,
'description' => $description,
'transaction_type' => 'earn',
];

$response = wp_remote_post( $url, [
'headers' => [
'Authorization' => 'Bearer ' . SLOYALTY_API_KEY,
'Content-Type' => 'application/json',
],
'body' => json_encode( $data ),
]);

if ( is_wp_error( $response ) ) {
error_log( 'SLoyalty Add Points Error: ' . $response->get_error_message() );
return false;
}

// Clear cache
wp_cache_delete( 'sloyalty_customer_' . md5( $email ) );

return true;
}

Redeem Reward

function redeem_sloyalty_reward( $email, $reward_id ) {
$url = SLOYALTY_API_URL . '/redemptions';

$data = [
'customer_email' => $email,
'reward_id' => $reward_id,
];

$response = wp_remote_post( $url, [
'headers' => [
'Authorization' => 'Bearer ' . SLOYALTY_API_KEY,
'Content-Type' => 'application/json',
],
'body' => json_encode( $data ),
]);

if ( is_wp_error( $response ) ) {
error_log( 'SLoyalty Redemption Error: ' . $response->get_error_message() );
return false;
}

$body = wp_remote_retrieve_body( $response );
$result = json_decode( $body, true );

// Clear cache
wp_cache_delete( 'sloyalty_customer_' . md5( $email ) );

return $result;
}

// REST API endpoint for redemption
add_action( 'rest_api_init', function() {
register_rest_route( 'sloyalty/v1', '/redeem', [
'methods' => 'POST',
'callback' => 'handle_sloyalty_redemption',
'permission_callback' => function() {
return is_user_logged_in();
},
]);
});

function handle_sloyalty_redemption( $request ) {
$reward_id = $request->get_param( 'reward_id' );
$user = wp_get_current_user();

$result = redeem_sloyalty_reward( $user->user_email, $reward_id );

if ( $result ) {
return new WP_REST_Response([ 'success' => true, 'data' => $result ], 200 );
}

return new WP_Error( 'redemption_failed', 'Unable to redeem reward', [ 'status' => 400 ] );
}

Points Earning Rules

Purchase Points

// Award points on order completion
add_action( 'bigcommerce/order/created', function( $order_id, $order_data ) {
$customer_email = $order_data['billing_address']['email'];
$order_total = $order_data['total_inc_tax'];

// Calculate points (1 point per dollar)
$points = floor( $order_total );

// Add bonus points for high-value orders
if ( $order_total >= 200 ) {
$points += 50; // Bonus 50 points
}

// Award points
add_sloyalty_points(
$customer_email,
$points,
"Purchase - Order #{$order_id}"
);

// Send email notification
do_action( 'sloyalty/points_earned', $customer_email, $points );
}, 10, 2 );

Account Creation Bonus

// Award welcome bonus on account creation
add_action( 'user_register', function( $user_id ) {
$user = get_user_by( 'id', $user_id );

add_sloyalty_points(
$user->user_email,
100,
'Welcome Bonus'
);
});

Birthday Bonus

// Award birthday points
add_action( 'init', function() {
if ( ! wp_next_scheduled( 'sloyalty/birthday_check' ) ) {
wp_schedule_event( time(), 'daily', 'sloyalty/birthday_check' );
}
});

add_action( 'sloyalty/birthday_check', function() {
$users = get_users([
'meta_key' => 'birth_month_day',
'meta_value' => date( 'm-d' ),
]);

foreach ( $users as $user ) {
add_sloyalty_points(
$user->user_email,
200,
'Birthday Bonus'
);
}
});

Product Review Bonus

// Award points for product reviews
add_action( 'comment_post', function( $comment_id, $comment_approved ) {
if ( 1 !== $comment_approved ) {
return;
}

$comment = get_comment( $comment_id );

if ( 'bigcommerce_product' !== get_post_type( $comment->comment_post_ID ) ) {
return;
}

add_sloyalty_points(
$comment->comment_author_email,
25,
'Product Review'
);
}, 10, 2 );

Email Notifications

Points Earned Notification

// Send email when points are earned
add_action( 'sloyalty/points_earned', function( $email, $points ) {
$customer = get_sloyalty_customer( $email );

$subject = "You've earned {$points} points!";
$message = "
<h2>Congratulations!</h2>
<p>You've earned <strong>{$points} points</strong>.</p>
<p>Your new balance: <strong>{$customer['points_balance']} points</strong></p>
<p><a href='" . home_url( '/account/rewards' ) . "'>View your rewards</a></p>
";

wp_mail( $email, $subject, $message, [ 'Content-Type: text/html; charset=UTF-8' ] );
}, 10, 2 );

Reward Redeemed Notification

// Send email when reward is redeemed
add_action( 'sloyalty/reward_redeemed', function( $email, $reward_name, $points_used ) {
$subject = "Reward Redeemed: {$reward_name}";
$message = "
<h2>Reward Redeemed</h2>
<p>You've successfully redeemed: <strong>{$reward_name}</strong></p>
<p>Points used: <strong>{$points_used}</strong></p>
<p><a href='" . home_url( '/account/rewards' ) . "'>View your rewards</a></p>
";

wp_mail( $email, $subject, $message, [ 'Content-Type: text/html; charset=UTF-8' ] );
});

Tier System

Define Tiers

// Loyalty tier definitions
function get_sloyalty_tiers() {
return [
'bronze' => [
'name' => 'Bronze',
'min_points' => 0,
'points_multiplier' => 1.0,
'benefits' => [
'Standard rewards',
'Birthday bonus',
],
],
'silver' => [
'name' => 'Silver',
'min_points' => 500,
'points_multiplier' => 1.25,
'benefits' => [
'All Bronze benefits',
'25% more points per purchase',
'Early access to sales',
],
],
'gold' => [
'name' => 'Gold',
'min_points' => 1500,
'points_multiplier' => 1.5,
'benefits' => [
'All Silver benefits',
'50% more points per purchase',
'Free shipping on all orders',
'Exclusive products',
],
],
];
}

// Get customer's tier
function get_customer_tier( $lifetime_points ) {
$tiers = get_sloyalty_tiers();
$current_tier = 'bronze';

foreach ( $tiers as $tier_key => $tier ) {
if ( $lifetime_points >= $tier['min_points'] ) {
$current_tier = $tier_key;
}
}

return $tiers[ $current_tier ];
}

Troubleshooting

Check SLoyalty Connection

// Test SLoyalty API
wp_eval "
$response = wp_remote_get( SLOYALTY_API_URL . '/health', [
'headers' => [ 'Authorization' => 'Bearer ' . SLOYALTY_API_KEY ]
]);
echo wp_remote_retrieve_body( $response );
"

Debug Points Transaction

// Enable SLoyalty debug logging
define( 'SLOYALTY_DEBUG', true );

add_action( 'sloyalty/points_added', function( $email, $points, $description ) {
error_log( "SLoyalty: Added {$points} points to {$email} - {$description}" );
}, 10, 3 );

Clear Customer Cache

# Clear SLoyalty customer cache
wp cache flush --group=sloyalty