This comprehensive guide covers both CoCart v4 (stable) and CoCart v5+ (pre-release) callback systems. Choose the version that matches your CoCart installation.
Cart callbacks allow you to extend CoCart’s functionality by creating custom cart update operations. This tutorial shows you how to create, register, and use custom callbacks for both CoCart versions.
Version Differences Overview
CoCart v4 (Stable)
CoCart v5+ (Pre-release)
- Base class:
CoCart_Cart_Extension_Callback
- Registration:
cocart_register_extension_callback action hook
- Totals calculation:
$this->recalculate_totals()
- Status: Production ready
What are Cart Callbacks?
Cart callbacks are custom PHP classes that execute when the cart is updated via the /wp-json/cocart/v2/cart/update endpoint. They allow you to:
- Apply discounts or loyalty points
- Update cart metadata
- Integrate with third-party services
- Implement custom cart validation rules
- Add special promotions or fees
Creating a Custom Callback
Let’s create a loyalty points callback that works with both CoCart versions:
Step 1: Basic Class Structure
The base class differs between versions:
CoCart v4 (Stable)
CoCart v5+ (Pre-release)
v4 Basic Callback Structure
<?php
/**
* Loyalty Points Callback for CoCart v4
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class Loyalty_Points_CoCart_Callback extends CoCart_Cart_Extension_Callback {
/**
* Callback name - this identifies your callback
*/
protected $name = 'apply-loyalty-points';
// Callback method goes here...
}
The $name property is crucial - it’s used as the namespace parameter when calling your callback via the API.
The validation logic remains the same across both versions:
public function callback( $request, $controller ) {
try {
// Safety check: Ensure cart has items
if ( $controller->is_completely_empty() ) {
throw new CoCart_Data_Exception(
'cocart_cart_empty',
__( 'Cart is empty. Please add items to cart first.', 'cart-rest-api-for-woocommerce' ),
404
);
}
// Extract custom data from request
$data = isset( $request['data'] ) ? $request['data'] : array();
// Validate required parameters
if ( empty( $data['points'] ) || ! is_numeric( $data['points'] ) ) {
throw new CoCart_Data_Exception(
'cocart_invalid_points',
__( 'Please provide a valid number of points to redeem.', 'cart-rest-api-for-woocommerce' ),
400
);
}
// Continue with callback logic...
} catch ( CoCart_Data_Exception $e ) {
return CoCart_Response::get_error_response(
$e->getErrorCode(),
$e->getMessage(),
$e->getCode(),
$e->getAdditionalData()
);
}
}
Step 3: Custom Logic Implementation
The business logic implementation is identical across both versions:
Custom Logic Implementation
// Inside the callback method, after validation...
$points_to_redeem = intval( $data['points'] );
$current_user = wp_get_current_user();
$cart_updated = false;
if ( $current_user->exists() ) {
// Get user's available points
$available_points = get_user_meta( $current_user->ID, 'loyalty_points', true );
$available_points = intval( $available_points );
// Check if user has enough points
if ( $available_points >= $points_to_redeem ) {
// Calculate discount (1 point = $0.10)
$discount_amount = $points_to_redeem * 0.10;
// Apply discount to cart
WC()->cart->add_fee(
sprintf( __( 'Loyalty Points Discount (%d points)', 'your-textdomain' ), $points_to_redeem ),
-$discount_amount
);
// Deduct points from user account
$new_points_balance = $available_points - $points_to_redeem;
update_user_meta( $current_user->ID, 'loyalty_points', $new_points_balance );
// Store redeemed points in session for reference
WC()->session->set( 'redeemed_loyalty_points', $points_to_redeem );
$cart_updated = true;
wc_add_notice(
sprintf(
__( 'Applied %d loyalty points for $%.2f discount. Remaining balance: %d points.', 'your-textdomain' ),
$points_to_redeem,
$discount_amount,
$new_points_balance
),
'success'
);
} else {
throw new CoCart_Data_Exception(
'cocart_insufficient_points',
sprintf(
__( 'Insufficient points. You have %d points available.', 'your-textdomain' ),
$available_points
),
400
);
}
} else {
throw new CoCart_Data_Exception(
'cocart_authentication_required',
__( 'Please log in to redeem loyalty points.', 'your-textdomain' ),
401
);
}
Step 4: Totals Calculation
The totals calculation method differs between versions:
CoCart v4 (Stable)
CoCart v5+ (Pre-release)
// After your custom logic...
if ( $cart_updated ) {
// v4 uses class method
$this->recalculate_totals( $request, $controller );
// Add success notice only if no errors occurred
if ( 0 === wc_notice_count( 'error' ) ) {
// Custom success message already added above
}
}
return true;
Registering Your Callback
The registration method differs between CoCart versions:
If you registered a callback before with version 4 or lower of CoCart, you will need to register them again for v5+. We simplified the callback system to perform better in version 5.
Registration Steps
- Save your callback class to a PHP file (e.g.,
loyalty-points-callback.php)
- Include the file in your theme or plugin
- Register using the appropriate method for your CoCart version
CoCart v4 (Stable)
CoCart v5+ (Pre-release)
add_action( 'cocart_register_extension_callback', 'register_loyalty_points_callback_v4' );
function register_loyalty_points_callback_v4( $callback ) {
// Load your callback class file
include_once( dirname( __FILE__) . '/callbacks/loyalty-points-callback.php' );
// Register the callback instance using action hook
$callback->register( new Loyalty_Points_CoCart_Callback() );
}
Migration from v4 to v5+
If you’re upgrading from CoCart v4, here’s what changes:
v4 Registration (Old)
v5+ Registration (New)
add_action( 'cocart_register_extension_callback', 'register_callback' );
function register_callback( $callback ) {
include_once( dirname( __FILE__) . '/callback.php' );
$callback->register( new My_Callback() );
}
Multiple Callbacks Registration
You can register multiple callbacks in one function:
add_filter( 'cocart_rest_callbacks', 'register_all_my_callbacks' );
function register_all_my_callbacks( $callbacks ) {
// Include all callback files
include_once( dirname( __FILE__) . '/callbacks/loyalty-points-callback.php' );
include_once( dirname( __FILE__) . '/callbacks/gift-card-callback.php' );
include_once( dirname( __FILE__) . '/callbacks/shipping-insurance-callback.php' );
// Register all callbacks
$callbacks[] = new Loyalty_Points_CoCart_Callback();
$callbacks[] = new Gift_Card_CoCart_Callback();
$callbacks[] = new Shipping_Insurance_CoCart_Callback();
return $callbacks;
}
Using Your Callback
The API usage remains identical across both versions - only the backend registration method differs.
API Request Structure
API Usage (Both Versions)
curl --location --request POST 'https://example-store.com/wp-json/cocart/v2/cart/update' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_JWT_TOKEN' \
--data '{
"namespace": "apply-loyalty-points",
"data": {
"points": 50
}
}'
JavaScript Usage
Frontend Integration (Both Versions)
async function redeemLoyaltyPoints(points) {
try {
const response = await fetch('/wp-json/cocart/v2/cart/update', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${userToken}`
},
body: JSON.stringify({
namespace: 'apply-loyalty-points',
data: {
points: points
}
})
});
const result = await response.json();
if (response.ok) {
console.log('Points redeemed successfully:', result);
updateCartDisplay(result);
} else {
console.error('Failed to redeem points:', result.message);
showErrorMessage(result.message);
}
} catch (error) {
console.error('Network error:', error);
}
}
// Usage remains the same
redeemLoyaltyPoints(25);
The new callback system offers several advantages:
- Reduced overhead: Filter-based registration is more efficient
- Better memory usage: Callbacks are loaded only when needed
- Faster initialization: Streamlined callback discovery
Enhanced Developer Experience
- Simpler registration: No need for complex callback objects
- Better debugging: Clearer callback flow
- Easier testing: Direct instantiation for unit tests
Backward Compatibility Considerations
v5+ callbacks are not backward compatible with v4. You must update your registration code when upgrading.
What breaks:
- Registration method (action hook vs filter)
- Base class name change
- Totals calculation method
What stays the same:
- API endpoint usage
- Callback
$name property
- Error handling patterns
- Frontend integration code
Best Practices
General Best Practices (Both Versions)
- Always validate input data - Never trust user input
- Use proper error handling - Throw CoCart_Data_Exception for consistent error responses
- Check authentication when needed - Verify user permissions for sensitive operations
- Provide clear feedback - Use WooCommerce notices to inform users of what happened
- Test thoroughly - Test all success and error scenarios
Version-Specific Best Practices
CoCart v4 (Stable)
CoCart v5+ (Pre-release)
- Use action hook registration -
cocart_register_extension_callback
- Extend correct base class -
CoCart_Cart_Extension_Callback
- Use class totals method - Call
$this->recalculate_totals()
- Follow established patterns - Production-tested approach
Troubleshooting
Common Issues (Both Versions)
- Callback not found: Check that your namespace matches the
$name property
- Class not loaded: Ensure your include path is correct
- Authentication errors: Verify user login status for user-specific callbacks
Version-Specific Issues
CoCart v4 (Stable)
CoCart v5+ (Pre-release)
- Registration not working: Check
cocart_register_extension_callback action
- Totals not updating: Ensure you’re calling
$this->recalculate_totals()
- Base class error: Verify extending
CoCart_Cart_Extension_Callback
Debug Mode
Enable debug mode to see detailed error messages:
// Add to wp-config.php
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
Debug Callback Registration
CoCart v4 (Stable)
CoCart v5+ (Pre-release)
Debug v4 Callback Registration
add_action( 'cocart_register_extension_callback', function( $callback ) {
error_log( 'CoCart v4 callback system initialized' );
});
Version Compatibility Summary
| Feature | CoCart v4 (Stable) | CoCart v5+ (Pre-release) |
|---|
| Base Class | CoCart_Cart_Extension_Callback | CoCart_REST_Callback |
| Registration | Action hook | Filter |
| Hook Name | cocart_register_extension_callback | cocart_rest_callbacks |
| Registration Method | $callback->register() | $callbacks[] = new Class() |
| Totals Calculation | $this->recalculate_totals() | $controller->calculate_totals() |
| Performance | Standard | Improved |
| API Usage | Same | Same |
| Backward Compatible | Yes (with older versions) | No (requires migration) |
| Production Ready | ✅ Yes | ⚠️ Testing only |
Choose the version that matches your CoCart installation and development needs.