6.5 KiB
Cart Validation
Cart validators verify business rules before cart operations complete. Each validator checks one specific aspect (inventory, pricing, shipping, etc.) and reports issues found.
Quick Reference
For experienced developers:
- Implement
ValidatorInterfacewith avalidate()method - Return
null(valid) orValidationIssue/ValidationIssue[](problems found) - Register via
woocommerce_paypal_payments_agentic_commerce_validatorshook
How Validation Works
When validators run:
POST /merchant-cart- Cart creationPUT /merchant-cart/{id}- Cart updatesPOST /merchant-cart/{id}/checkout- Checkout attempts
What happens with issues:
- AI agent receives all issues and attempts resolution with buyer
- Checkout is blocked until all issues are resolved
Execution order: Validators run in registration order.
Writing a Validator
Interface Location
modules/ppcp-agentic-commerce/src/CartValidation/ValidatorInterface.php
Return Values
Return one of:
nullorarray()- No issues foundValidationIssue- Single issueValidationIssue[]- Multiple issues
// Valid cart.
return null;
return array();
// Single problem.
return new MissingField( 'shipping_address is required' );
// Multiple problems.
return array( $issue1, $issue2 );
Simple Example
Minimum order validator with no dependencies:
<?php
declare( strict_types = 1 );
namespace WooCommerce\PayPalCommerce\AgenticCommerce\CartValidation;
use WooCommerce\PayPalCommerce\AgenticCommerce\Schema\PayPalCart;
use WooCommerce\PayPalCommerce\AgenticCommerce\Helper\CartHelper;
use WooCommerce\PayPalCommerce\AgenticCommerce\Validation\BusinessRuleViolation;
class MinimumOrderValidator implements ValidatorInterface {
private const MIN_ORDER_AMOUNT = 15.00;
public function validate( PayPalCart $cart ) {
$total = CartHelper::cart_item_total( $cart );
if ( $total < self::MIN_ORDER_AMOUNT ) {
return new BusinessRuleViolation(
sprintf( 'Order minimum is $%.2f', self::MIN_ORDER_AMOUNT )
);
}
return null;
}
}
Example with Dependencies
Product availability validator using ProductManager:
<?php
declare( strict_types = 1 );
namespace WooCommerce\PayPalCommerce\AgenticCommerce\CartValidation;
use WooCommerce\PayPalCommerce\AgenticCommerce\Schema\PayPalCart;
use WooCommerce\PayPalCommerce\AgenticCommerce\Helper\ProductManager;
use WooCommerce\PayPalCommerce\AgenticCommerce\Validation\InvalidData;
class ProductAvailabilityValidator implements ValidatorInterface {
private ProductManager $product_manager;
public function __construct( ProductManager $product_manager ) {
$this->product_manager = $product_manager;
}
public function validate( PayPalCart $cart ) {
$issues = array();
foreach ( $cart->items() as $key => $item ) {
$product = $this->product_manager->find_product( $item );
if ( ! $product || $product->get_status() !== 'publish' ) {
$issues[] = new InvalidData(
'Product is no longer available',
sprintf( 'Product "%s" cannot be purchased at the moment', $item->name() ),
"items[{$key}]"
);
}
}
return $issues ?: null;
}
}
Registration
Internal Development (DI Container)
Step 1: Add validator to modules/ppcp-agentic-commerce/services.php:
'agentic.validator.minimum-order' => static function ( ContainerInterface $c ): MinimumOrderValidator {
return new MinimumOrderValidator();
},
'agentic.validator.product-availability' => static function ( ContainerInterface $c ): ProductAvailabilityValidator {
return new ProductAvailabilityValidator(
$c->get( 'agentic.helper.product-manager' )
);
},
Step 2: Add service ID to CART_VALIDATION_SERVICES in AgenticCommerceModule.php:
private const CART_VALIDATION_SERVICES = array(
'agentic.validator.product',
'agentic.validator.inventory',
'agentic.validator.minimum-order', // ← Your validator
'agentic.validator.product-availability', // ← Your validator
);
Important: Array order determines execution order.
This array is then processed by the woocommerce_paypal_payments_agentic_commerce_validators action to register the validators.
Third-Party Plugins (Hook-Based)
Third-party plugins cannot access the DI container. Use the WordPress action hook instead:
add_action(
'woocommerce_paypal_payments_agentic_commerce_validators',
function( $processor ) {
// Instantiate directly (check constructor for required dependencies)
$validator = new MinimumOrderValidator();
$processor->register_validator( $validator );
}
);
Complete plugin example:
<?php
/**
* Plugin Name: Custom Cart Validation
*/
use WooCommerce\PayPalCommerce\AgenticCommerce\CartValidation\ValidatorInterface;
use WooCommerce\PayPalCommerce\AgenticCommerce\CartValidation\CartValidationProcessor;
use WooCommerce\PayPalCommerce\AgenticCommerce\Validation\BusinessRuleViolation;
use WooCommerce\PayPalCommerce\AgenticCommerce\Schema\PayPalCart;
class My_Custom_Validator implements ValidatorInterface {
public function validate( PayPalCart $cart ) {
if ( count( $cart->items() ) > 50 ) {
return new BusinessRuleViolation( 'Maximum 50 items per cart' );
}
return null;
}
}
add_action(
'woocommerce_paypal_payments_agentic_commerce_validators',
function( CartValidationProcessor $processor ) {
$processor->register_validator( new My_Custom_Validator() );
}
);
Best Practices
Single Responsibility
Each validator checks one business rule. Don't combine inventory + pricing in one validator.
Clear Messages
Error messages are shown to buyers via AI agent. Be specific and actionable:
// ✗ Bad - generic issue and vague message.
return new BusinessRuleViolation( 'Invalid order' );
// ✓ Good - specific issue, clear message.
return new ShippingUnavailable( 'This product ships to US addresses only' );
Performance Matters
- Leverage helper class caching where available
- Consider checking
$cart->has_validation_issue()to skip redundant checks
Validation Issue Types
Locate the most suitable issue class in modules/ppcp-agentic-commerce/src/Validation. Consider adding a new one if needed.