This guide will walk you through creating a personalised "Products For You" block using PersonalizeWP's REST API. This feature enhances user experience by showing tailored product recommendations based on visitor segments.
Overview
The "Products For You" block displays product recommendations specifically chosen for the current visitor based on their segment memberships. This implementation uses the /visitor-segments endpoint to retrieve the visitor's segments and then displays relevant products.
Prerequisites
- PersonalizeWP Pro installed and activated
- Segments properly configured in your PersonalizeWP dashboard
- Basic knowledge of JavaScript and WordPress development
- Access to your theme files or a custom plugin where you can add JavaScript code
Implementation Steps
Step 1: Create the HTML Structure
First, create the HTML structure for your "Products For You" block. You can add this to your theme or plugin as a snippet in a template, or you can adapt it to use in a custom Block Editor block:
<div class="pwp-products-for-you">
<h2>Products For You</h2>
<div class="pwp-recommended-products" id="pwp-recommended-products-container">
<!-- Products will be inserted here dynamically -->
</div>
</div>
Step 2: Fetch Visitor Segments and Display Recommended Products
Create a JavaScript function to fetch the visitor's segments and display recommended products from the PersonalizeWP REST API (you do not need to authenticate to the API from your own site):
NOTE: The UID is an obfuscated non-incrementing ID that is stored in the visitor’s local browser storage and is specific to their interaction with your site.
function initProductsForYouBlock() {
// Get the container element
const container = document.getElementById('pwp-recommended-products-container');
// If the container doesn't exist, exit early
if (!container) return;
// Fetch visitor segments and display recommended products
fetchVisitorSegmentsAndProducts(container);
}
async function fetchVisitorSegmentsAndProducts(container) {
const PWP = localStorage.getItem('pwp_tracked_user') || '';
const UID = (PWP) ? JSON.parse(PWP).id : null;
if (!UID) {
container.closest('.pwp-products-for-you').style.display = 'none';
return;
}
const baseURL = window.pwpSettings?.root || '/wp-json/';
const namespace = 'personalizewp/v1/';
const endpoint = 'visitor-segments';
try {
const response = await fetch(`${baseURL}${namespace}${endpoint}`, {
method: "POST",
cache: "no-cache",
headers: {
"Accept": "application/json, */*;q=0.1",
"Cache-Control": "no-cache, private",
"Content-type": "application/json",
"X-Requested-With": "XMLHttpRequest",
},
body: JSON.stringify({ uid: UID }),
});
if (!response.ok) {
throw new Error('Network response was not ok');
}
const segments = await response.json();
// If no segments, show default products or hide the container
if (segments.length === 0) {
showDefaultRecommendations(container);
return;
}
// Get product recommendations based on segments
const recommendedProducts = await getProductRecommendations(segments);
// Display the products or fall back to defaults if none found
if (recommendedProducts.length > 0) {
displayRecommendedProducts(recommendedProducts, container);
} else {
showDefaultRecommendations(container);
}
} catch (error) {
console.error('Error fetching visitor segments:', error);
showDefaultRecommendations(container);
}
}
async function getProductRecommendations(segments) {
// This function maps visitor segments to product recommendations.
// In a real implementation you'd have a more sophisticated mapping.
// Example: map segment IDs/types to product categories or IDs
const segmentProductMap = {
'high-value-customer': [101, 102, 103],
'tech-enthusiast': [201, 202, 203],
'fashion-lover': [301, 302, 303],
};
// Priority segments (you might prioritise some over others)
const prioritySegments = ['high-value-customer', 'new-visitor'];
// Find highest priority segment the visitor belongs to
let targetSegment = null;
for (const priority of prioritySegments) {
if (segments.some(segment => segment.type === priority)) {
targetSegment = priority;
break;
}
}
// If no priority segment found, use the first segment
if (!targetSegment && segments.length > 0) {
targetSegment = segments[0].type;
}
const productIds = segmentProductMap[targetSegment] || [];
if (productIds.length > 0) {
return await fetchProductsData(productIds);
}
return [];
}
async function fetchProductsData(productIds) {
// Simplified example using the WooCommerce REST API
const baseURL = '/wp-json/wc/v3/products';
const queryParams = new URLSearchParams({
include: productIds.join(','),
per_page: productIds.length
// In production, add proper authentication
});
const response = await fetch(`${baseURL}?${queryParams}`);
return await response.json();
}
function displayRecommendedProducts(products, container) {
container.innerHTML = '';
// Limit to 3 products for display
const limitedProducts = products.slice(0, 3);
limitedProducts.forEach(product => {
const productElement = createProductElement(product);
container.appendChild(productElement);
});
container.closest('.pwp-products-for-you').style.display = 'block';
}
function showDefaultRecommendations(container) {
// Show featured products as a fallback, or hide the block
fetchFeaturedProducts().then(products => {
if (products.length > 0) {
displayRecommendedProducts(products, container);
} else {
container.closest('.pwp-products-for-you').style.display = 'none';
}
}).catch(error => {
console.error('Error fetching featured products:', error);
container.closest('.pwp-products-for-you').style.display = 'none';
});
}
async function fetchFeaturedProducts() {
const baseURL = '/wp-json/wc/v3/products';
const queryParams = new URLSearchParams({
featured: true,
per_page: 3
});
const response = await fetch(`${baseURL}?${queryParams}`);
return await response.json();
}
// Helper function to create a product element
function createProductElement(product) {
const productDiv = document.createElement('div');
productDiv.className = 'pwp-product-item';
productDiv.innerHTML = `
<a href="${product.permalink}" class="pwp-product-link">
<div class="pwp-product-image">
<img src="${product.images[0]?.src || ''}" alt="${product.name}">
</div>
<div class="pwp-product-details">
<h3 class="pwp-product-title">${product.name}</h3>
<div class="pwp-product-price">${product.price_html}</div>
</div>
</a>
<button class="pwp-add-to-cart" data-product-id="${product.id}">
Add to Cart
</button>
`;
return productDiv;
}
// Initialise the block when DOM is ready
document.addEventListener('DOMContentLoaded', initProductsForYouBlock);
Step 3: Add CSS Styling
Add CSS to style your "Products For You" block:
.pwp-products-for-you {
margin: 2rem 0;
padding: 1.5rem;
background-color: #f7f7f7;
border-radius: 4px;
}
.pwp-products-for-you h2 {
margin-bottom: 1.5rem;
font-size: 1.5rem;
color: #333;
text-align: center;
}
.pwp-recommended-products {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 1.5rem;
}
.pwp-product-item {
border: 1px solid #eee;
border-radius: 4px;
padding: 1rem;
background-color: white;
transition: transform 0.2s, box-shadow 0.2s;
}
.pwp-product-item:hover {
transform: translateY(-3px);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
}
.pwp-product-image img {
width: 100%;
height: auto;
object-fit: cover;
border-radius: 3px;
}
.pwp-product-title {
margin: 0.5rem 0;
font-size: 1rem;
font-weight: 600;
}
.pwp-product-price {
color: #555;
margin-bottom: 0.5rem;
}
.pwp-add-to-cart {
width: 100%;
padding: 0.5rem;
background-color: #3498db;
color: white;
border: none;
border-radius: 3px;
cursor: pointer;
transition: background-color 0.2s;
}
.pwp-add-to-cart:hover {
background-color: #2980b9;
}
Step 4: Enqueue Your Script and Styles
Add this to your theme's functions.php file or your custom plugin:
function pwp_enqueue_products_for_you_scripts() {
// Enqueue on appropriate pages (home, shop, etc.)
if ( is_front_page() || is_shop() || is_product_category() ) {
wp_enqueue_script(
'pwp-products-for-you',
get_template_directory_uri() . '/assets/js/products-for-you.js',
array( 'jquery' ),
'1.0.0',
true
);
wp_enqueue_style(
'pwp-products-for-you-styles',
get_template_directory_uri() . '/assets/css/products-for-you.css',
array(),
'1.0.0'
);
// Pass the WordPress REST API root URL to JavaScript
wp_localize_script(
'pwp-products-for-you',
'pwpSettings',
array(
'root' => esc_url_raw( rest_url() ),
'nonce' => wp_create_nonce( 'wp_rest' ),
)
);
}
}
add_action( 'wp_enqueue_scripts', 'pwp_enqueue_products_for_you_scripts' );
Step 5: Add the Block to Your Theme
Insert the HTML structure in your theme's appropriate template file. For WooCommerce, you might add it to front-page.php, archive-product.php, or use a hook:
function pwp_add_products_for_you_block() {
echo '<div class="pwp-products-for-you">
<h2>Products For You</h2>
<div class="pwp-recommended-products" id="pwp-recommended-products-container">
<!-- Products will be inserted here dynamically -->
</div>
</div>';
}
add_action( 'woocommerce_before_shop_loop', 'pwp_add_products_for_you_block', 5 );
Result
When implemented correctly, your website will now display a "Products For You" block that shows personalised product recommendations based on the visitor's segments. This creates a tailored shopping experience that can significantly improve engagement and conversion rates.
Troubleshooting
If your "Products For You" block isn't working as expected:
- Check the browser console for JavaScript errors
- Verify that the visitor has a UID in local storage
- Test the API endpoint directly using the browser console
- Ensure your segment configuration is properly set up in PersonalizeWP
- Verify product data is being fetched correctly from WooCommerce
Common Issues and Solutions
| Issue | Solution |
|---|---|
| Block shows no products | Check if the visitor belongs to any segments or adjust your fallback strategy |
| Products don’t match expectation | Review segment mapping logic and ensure proper configuration |
| API errors | Verify endpoint URLs and authentication credentials |
| Performance concerns | Implement caching and limit API calls |
| Block appears on wrong pages | Review page condition logic in the enqueue_scripts function |
For additional help, please refer to the PersonalizeWP documentation or contact our support team.