diff --git a/modules/ppcp-agentic-commerce/services.php b/modules/ppcp-agentic-commerce/services.php
index bdb7cc5ac..e2d22e259 100644
--- a/modules/ppcp-agentic-commerce/services.php
+++ b/modules/ppcp-agentic-commerce/services.php
@@ -29,8 +29,13 @@
use WooCommerce\PayPalCommerce\AgenticCommerce\Merchant\MerchantMetadataProvider;
use WooCommerce\PayPalCommerce\AgenticCommerce\Registration\RegistrationService;
use WooCommerce\PayPalCommerce\AgenticCommerce\Registration\RegistrationEligibility;
+use WooCommerce\PayPalCommerce\AgenticCommerce\Inspector\InspectionFormHandler;
+use WooCommerce\PayPalCommerce\AgenticCommerce\Inspector\InspectionStatusPage;
use WooCommerce\PayPalCommerce\AgenticCommerce\Helper\AgenticCheckoutProcessor;
use WooCommerce\PayPalCommerce\AgenticCommerce\Cart\PayPalCartToCartDataAdapter;
+use WooCommerce\PayPalCommerce\AgenticCommerce\Inspector\InspectionSessionData;
+use WooCommerce\PayPalCommerce\AgenticCommerce\Inspector\Page\RegistrationStatusSection;
+use WooCommerce\PayPalCommerce\AgenticCommerce\Inspector\Page\CartSessionSection;
return array(
// Configuration.
@@ -170,4 +175,35 @@
$c->get( 'agentic.registration.eligibility' )
);
},
+
+ // Inspector.
+ 'agentic.inspector.form_handler' => static function ( ContainerInterface $c ): InspectionFormHandler {
+ return new InspectionFormHandler(
+ $c->get( 'agentic.registration.handler' ),
+ $c->get( 'woocommerce.logger.woocommerce' )
+ );
+ },
+ 'agentic.inspector.session_info' => static function ( ContainerInterface $c ): InspectionSessionData {
+ return new InspectionSessionData();
+ },
+ 'agentic.inspector.page.status' => static function ( ContainerInterface $c ): RegistrationStatusSection {
+ return new RegistrationStatusSection(
+ $c->get( 'agentic.registration.handler' ),
+ $c->get( 'agentic.registration.eligibility' ),
+ $c->get( 'agentic.auth.provider' ),
+ $c->get( 'settings.data.general' )
+ );
+ },
+ 'agentic.inspector.page.session' => static function ( ContainerInterface $c ): CartSessionSection {
+ return new CartSessionSection(
+ $c->get( 'agentic.inspector.session_info' ),
+ );
+ },
+ 'agentic.inspector.page' => static function ( ContainerInterface $c ): InspectionStatusPage {
+ return new InspectionStatusPage(
+ $c->get( 'agentic.inspector.form_handler' ),
+ $c->get( 'agentic.inspector.page.status' ),
+ $c->get( 'agentic.inspector.page.session' )
+ );
+ },
);
diff --git a/modules/ppcp-agentic-commerce/src/AgenticCommerceModule.php b/modules/ppcp-agentic-commerce/src/AgenticCommerceModule.php
index 272eba41a..1f8b2edd4 100644
--- a/modules/ppcp-agentic-commerce/src/AgenticCommerceModule.php
+++ b/modules/ppcp-agentic-commerce/src/AgenticCommerceModule.php
@@ -19,6 +19,7 @@
use WooCommerce\PayPalCommerce\AgenticCommerce\Registration\RegistrationService;
use WooCommerce\PayPalCommerce\AgenticCommerce\Registration\RegistrationEligibility;
use WooCommerce\PayPalCommerce\AgenticCommerce\Setting\AgenticSettingsDataModel;
+use WooCommerce\PayPalCommerce\AgenticCommerce\Inspector\InspectionStatusPage;
/**
* Entry point that integrates agentic commerce logic with the plugin's DI system.
@@ -75,12 +76,14 @@ public function run( ContainerInterface $container ): bool {
// Sync eligibility cache on init (when WC is available).
$this->sync_eligibility_cache( $agentic_settings, $eligibility_check );
+ $inspector = $container->get( 'agentic.inspector.page' );
+ assert( $inspector instanceof InspectionStatusPage );
+ $inspector->init();
+
// Early exit if features should not be initialized.
if ( ! $agentic_settings->should_initialize_features() ) {
$this->ensure_deregistered( $registration_handler );
- // todo: also remove scheduled action?
-
return true;
}
diff --git a/modules/ppcp-agentic-commerce/src/Cart/PayPalCartToCartDataAdapter.php b/modules/ppcp-agentic-commerce/src/Cart/PayPalCartToCartDataAdapter.php
index aff93e46b..50eed0a8e 100644
--- a/modules/ppcp-agentic-commerce/src/Cart/PayPalCartToCartDataAdapter.php
+++ b/modules/ppcp-agentic-commerce/src/Cart/PayPalCartToCartDataAdapter.php
@@ -57,6 +57,7 @@ public function translate( PayPalCart $paypal_cart ): CartData {
static fn( $issue ): string => $issue->to_array()['message'],
$issues
);
+ // TODO: This is possibly incorrect. Cart should be stored in session and returned to the agent with a validation issue rather than throwing an error.
throw new ValidationException(
$error_messages,
'Cart validation failed'
diff --git a/modules/ppcp-agentic-commerce/src/Config/AgenticWebhookConfiguration.php b/modules/ppcp-agentic-commerce/src/Config/AgenticWebhookConfiguration.php
index 723eeb386..026e113bc 100644
--- a/modules/ppcp-agentic-commerce/src/Config/AgenticWebhookConfiguration.php
+++ b/modules/ppcp-agentic-commerce/src/Config/AgenticWebhookConfiguration.php
@@ -14,7 +14,7 @@
class AgenticWebhookConfiguration {
private const LIVE_BASE_URL = 'https://d.joinhoney.com';
- private const SANDBOX_BASE_URL = 'https://d-sandbox.joinhoney.com';
+ private const SANDBOX_BASE_URL = 'https://d-staging.joinhoney.com';
private const ENDPOINT_REGISTRATION_INSTALL = '/webhooks/ws/install';
private const ENDPOINT_REGISTRATION_UNINSTALL = '/webhooks/ws/uninstall';
diff --git a/modules/ppcp-agentic-commerce/src/Inspector/InspectionFormHandler.php b/modules/ppcp-agentic-commerce/src/Inspector/InspectionFormHandler.php
new file mode 100644
index 000000000..c5812f46c
--- /dev/null
+++ b/modules/ppcp-agentic-commerce/src/Inspector/InspectionFormHandler.php
@@ -0,0 +1,177 @@
+registration_service = $registration_service;
+ $this->logger = $logger;
+ }
+
+ public function init(): void {
+ add_action( 'admin_post_ppcp_agentic_toggle_registration', fn() => $this->handle_toggle() );
+ }
+
+ /**
+ * Handle the registration toggle form submission.
+ */
+ private function handle_toggle(): void {
+ $this->logger->info( 'Inspector: Registration toggle form submitted' );
+
+ $toggle_action = $this->verify_request_and_get_action();
+ $this->logger->info( "Inspector: Toggle action requested: {$toggle_action}" );
+
+ $notice = 'error';
+ if ( $toggle_action === 'register' ) {
+ $notice = $this->handle_registration();
+ } elseif ( $toggle_action === 'unregister' ) {
+ $notice = $this->handle_unregistration();
+ } else {
+ $notice = $this->handle_invalid_action( $toggle_action );
+ }
+
+ $this->redirect_to_status_page( $notice );
+ }
+
+ /**
+ * Verify nonce and user capability, then return the toggle action.
+ *
+ * @return string The toggle action ('register', 'unregister', or empty string).
+ */
+ private function verify_request_and_get_action(): string {
+ // phpcs:disable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
+ if ( empty( $_POST['ppcp_agentic_nonce'] ) ) {
+ return '';
+ }
+
+ // Verify nonce and get toggle action in same method.
+ if (
+ ! is_string( $_POST['ppcp_agentic_nonce'] ) ||
+ ! wp_verify_nonce( wp_unslash( $_POST['ppcp_agentic_nonce'] ), 'ppcp_agentic_toggle_nonce' )
+ ) {
+ $this->logger->error( 'Inspector: Nonce verification failed' );
+ wp_die( esc_html__( 'Security check failed.', 'woocommerce-paypal-payments' ) );
+ }
+
+ // Verify toggle action is a string.
+ if ( empty( $_POST['toggle_action'] ) || ! is_string( $_POST['toggle_action'] ) ) {
+ return '';
+ }
+ // phpcs:enable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
+
+ // Check user capability.
+ if ( ! current_user_can( 'manage_woocommerce' ) ) {
+ $this->logger->error( 'Inspector: User lacks manage_woocommerce capability' );
+ wp_die( esc_html__( 'You do not have permission to perform this action.', 'woocommerce-paypal-payments' ) );
+ }
+
+ return sanitize_text_field( wp_unslash( $_POST['toggle_action'] ) );
+ }
+
+ /**
+ * Handle registration attempt.
+ *
+ * @return string Notice type ('registered' or 'error').
+ */
+ private function handle_registration(): string {
+ $this->logger->info( 'Inspector: Attempting to register with RegistrationService' );
+ $result = $this->registration_service->register();
+
+ if ( is_wp_error( $result ) ) {
+ $this->logger->error(
+ 'Inspector: Registration failed',
+ array(
+ 'error_code' => $result->get_error_code(),
+ 'error_message' => $result->get_error_message(),
+ )
+ );
+
+ return 'error';
+ }
+
+ $this->logger->info( 'Inspector: Registration successful', array( 'result' => $result ) );
+
+ return 'registered';
+ }
+
+ /**
+ * Handle unregistration attempt.
+ *
+ * @return string Notice type ('unregistered' or 'error').
+ */
+ private function handle_unregistration(): string {
+ $this->logger->info( 'Inspector: Attempting to unregister with RegistrationService' );
+ $result = $this->registration_service->deregister();
+
+ if ( is_wp_error( $result ) ) {
+ $this->logger->error(
+ 'Inspector: Unregistration failed',
+ array(
+ 'error_code' => $result->get_error_code(),
+ 'error_message' => $result->get_error_message(),
+ )
+ );
+
+ return 'error';
+ }
+
+ $this->logger->info( 'Inspector: Unregistration successful', array( 'result' => $result ) );
+
+ return 'unregistered';
+ }
+
+ /**
+ * Handle invalid toggle action.
+ *
+ * @param string $toggle_action The invalid action.
+ * @return string Notice type ('error').
+ */
+ private function handle_invalid_action( string $toggle_action ): string {
+ $this->logger->warning( "Inspector: Invalid toggle action: {$toggle_action}" );
+
+ return 'error';
+ }
+
+ /**
+ * Redirect back to the status page with a notice.
+ *
+ * @param string $notice Notice type to display.
+ */
+ private function redirect_to_status_page( string $notice ): void {
+ $redirect_url = add_query_arg(
+ array(
+ 'page' => 'wc-status',
+ 'tab' => 'paypal-agentic',
+ 'ppcp_agentic_notice' => $notice,
+ ),
+ admin_url( 'admin.php' )
+ );
+
+ $this->logger->info( "Inspector: Redirecting to status page with notice: {$notice}" );
+ wp_safe_redirect( $redirect_url );
+ exit;
+ }
+}
diff --git a/modules/ppcp-agentic-commerce/src/Inspector/InspectionSessionData.php b/modules/ppcp-agentic-commerce/src/Inspector/InspectionSessionData.php
new file mode 100644
index 000000000..3da4f36d4
--- /dev/null
+++ b/modules/ppcp-agentic-commerce/src/Inspector/InspectionSessionData.php
@@ -0,0 +1,265 @@
+session = new AgenticWcSession();
+ $this->session->init();
+ }
+
+ /**
+ * List all agentic cart sessions with summary information.
+ *
+ * Returns lightweight session metadata without full cart details.
+ * Useful for displaying a list of sessions in an admin interface.
+ *
+ * @return array Array of session summaries, each containing:
+ * - session_id: string
+ * - created: int|null Unix timestamp
+ * - modified: int|null Unix timestamp
+ * - item_count: int Number of items in cart
+ * - ec_token: string PayPal EC token
+ */
+ public function list_all_sessions(): array {
+ $all_sessions = $this->get_all_sessions();
+ $session_summaries = array();
+
+ foreach ( $all_sessions as $session ) {
+ // Check if this session contains agentic commerce data.
+ if ( ! isset( $session['session_value'][ self::SESSION_KEY ] ) ) {
+ continue;
+ }
+
+ $session_data = $session['session_value'][ self::SESSION_KEY ];
+
+ // Validate required data structure.
+ if ( ! is_array( $session_data ) || ! isset( $session_data['cart'] ) ) {
+ continue;
+ }
+
+ // Count items without fully parsing the cart.
+ $item_count = 0;
+ if ( isset( $session_data['cart']['items'] ) && is_array( $session_data['cart']['items'] ) ) {
+ $item_count = count( $session_data['cart']['items'] );
+ }
+
+ $session_summaries[] = array(
+ 'session_id' => $session['session_key'],
+ 'created' => $session_data['created'] ?? null,
+ 'modified' => $session_data['modified'] ?? null,
+ 'item_count' => $item_count,
+ 'ec_token' => $session_data['ec_token'] ?? '',
+ );
+ }
+
+ // Sort by created date, newest first.
+ usort(
+ $session_summaries,
+ function ( $a, $b ) {
+ $a_time = $a['created'] ?? 0;
+ $b_time = $b['created'] ?? 0;
+
+ return $b_time <=> $a_time;
+ }
+ );
+
+ return $session_summaries;
+ }
+
+ /**
+ * Inspect a specific cart session by ID.
+ *
+ * Returns full cart details including all items, totals, and metadata.
+ * Use this when you need complete information about a specific session.
+ *
+ * @param string $session_id The session ID to inspect.
+ * @return array|null Array with full session details or null if not found:
+ * - session_id: string
+ * - cart: PayPalCart Full cart object
+ * - ec_token: string PayPal EC token
+ * - created: int|null Unix timestamp
+ * - modified: int|null Unix timestamp
+ * - expires: int|null Unix timestamp when session expires
+ */
+ public function inspect_cart_session( string $session_id ): ?array {
+ if ( ! $this->session->load_session_by_id( $session_id ) ) {
+ return null;
+ }
+
+ $session_data = $this->session->get( self::SESSION_KEY );
+
+ if ( ! is_array( $session_data ) || ! isset( $session_data['cart'] ) ) {
+ return null;
+ }
+
+ try {
+ $cart = PayPalCart::from_array( $session_data['cart'] );
+
+ // Get expiry time from database.
+ $expires = $this->get_session_expiry( $session_id );
+
+ return array(
+ 'session_id' => $session_id,
+ 'cart' => $cart,
+ 'ec_token' => $session_data['ec_token'] ?? '',
+ 'created' => $session_data['created'] ?? null,
+ 'modified' => $session_data['modified'] ?? null,
+ 'expires' => $expires,
+ );
+ } catch ( \Exception $e ) {
+ return null;
+ }
+ }
+
+ /**
+ * Get session statistics for dashboard display.
+ *
+ * Provides aggregate statistics about agentic commerce sessions.
+ *
+ * @return array Statistics including:
+ * - total_sessions: int
+ * - total_items: int
+ * - oldest_session: int|null Unix timestamp
+ * - newest_session: int|null Unix timestamp
+ * - average_age_hours: float|null
+ */
+ public function get_session_statistics(): array {
+ $sessions = $this->list_all_sessions();
+
+ if ( empty( $sessions ) ) {
+ return array(
+ 'total_sessions' => 0,
+ 'total_items' => 0,
+ 'oldest_session' => null,
+ 'newest_session' => null,
+ 'average_age_hours' => null,
+ );
+ }
+
+ $total_items = 0;
+ $oldest = null;
+ $newest = null;
+ $total_age = 0;
+ $sessions_with_age = 0;
+
+ foreach ( $sessions as $session ) {
+ $total_items += $session['item_count'];
+
+ if ( $session['created'] ) {
+ if ( $oldest === null || $session['created'] < $oldest ) {
+ $oldest = $session['created'];
+ }
+ if ( $newest === null || $session['created'] > $newest ) {
+ $newest = $session['created'];
+ }
+
+ $age = time() - $session['created'];
+
+ $total_age += $age;
+
+ ++$sessions_with_age;
+ }
+ }
+
+ $average_age_hours = $sessions_with_age > 0
+ ? ( $total_age / $sessions_with_age ) / 3600
+ : null;
+
+ return array(
+ 'total_sessions' => count( $sessions ),
+ 'total_items' => $total_items,
+ 'oldest_session' => $oldest,
+ 'newest_session' => $newest,
+ 'average_age_hours' => $average_age_hours,
+ );
+ }
+
+ /**
+ * Get the expiry timestamp for a session.
+ *
+ * @param string $session_id The session ID.
+ * @return int|null Unix timestamp or null if not found.
+ */
+ private function get_session_expiry( string $session_id ): ?int {
+ global $wpdb;
+
+ $expiry = $wpdb->get_var(
+ $wpdb->prepare(
+ "SELECT session_expiry FROM {$wpdb->prefix}woocommerce_sessions
+ WHERE session_key = %s",
+ $session_id
+ )
+ );
+
+ return $expiry ? (int) $expiry : null;
+ }
+
+ /**
+ * Get all active sessions from the database.
+ *
+ * This method directly queries the WooCommerce sessions table.
+ * Only used for inspection purposes.
+ *
+ * @return array Array of sessions with 'session_key' and 'session_value' (unserialized).
+ */
+ private function get_all_sessions(): array {
+ global $wpdb;
+
+ $results = $wpdb->get_results(
+ $wpdb->prepare(
+ "SELECT session_key, session_value FROM {$wpdb->prefix}woocommerce_sessions
+ WHERE session_expiry > %d",
+ time()
+ )
+ );
+
+ if ( ! $results ) {
+ return array();
+ }
+
+ $sessions = array();
+ foreach ( $results as $row ) {
+ $sessions[] = array(
+ 'session_key' => $row->session_key,
+ 'session_value' => maybe_unserialize( $row->session_value ),
+ );
+ }
+
+ return $sessions;
+ }
+}
diff --git a/modules/ppcp-agentic-commerce/src/Inspector/InspectionStatusPage.php b/modules/ppcp-agentic-commerce/src/Inspector/InspectionStatusPage.php
new file mode 100644
index 000000000..ec896ebe0
--- /dev/null
+++ b/modules/ppcp-agentic-commerce/src/Inspector/InspectionStatusPage.php
@@ -0,0 +1,60 @@
+form_handler = $form_handler;
+ $this->registration_section = $registration_section;
+ $this->session_section = $session_section;
+ }
+
+ /**
+ * Initialize the status tab and form handler by registering WordPress hooks.
+ */
+ public function init(): void {
+ $this->form_handler->init();
+
+ add_filter( 'woocommerce_admin_status_tabs', fn( array $tabs ) => $this->add_tab( $tabs ), 99 );
+ add_action( 'woocommerce_admin_status_content_paypal-agentic', fn() => $this->registration_section->render(), 10 );
+ add_action( 'woocommerce_admin_status_content_paypal-agentic', fn() => $this->session_section->render(), 11 );
+ }
+
+ /**
+ * Add PayPal Agentic tab to WooCommerce status tabs.
+ *
+ * @param array $tabs Existing status tabs.
+ * @return array Modified tabs array with PayPal Agentic tab added.
+ */
+ private function add_tab( array $tabs ): array {
+ $tabs['paypal-agentic'] = __( 'PayPal Agentic', 'woocommerce-paypal-payments' );
+
+ return $tabs;
+ }
+}
diff --git a/modules/ppcp-agentic-commerce/src/Inspector/Page/CartSessionSection.php b/modules/ppcp-agentic-commerce/src/Inspector/Page/CartSessionSection.php
new file mode 100644
index 000000000..c9b52c5b4
--- /dev/null
+++ b/modules/ppcp-agentic-commerce/src/Inspector/Page/CartSessionSection.php
@@ -0,0 +1,376 @@
+inspector = $inspector;
+ }
+
+ /**
+ * Render the cart session section.
+ */
+ public function render(): void {
+ $stats = $this->inspector->get_session_statistics();
+ $sessions = $this->inspector->list_all_sessions();
+
+ // Check if we should inspect a specific session.
+ $inspect_session_id = $this->get_inspected_session_id();
+
+ ?>
+
+
+
+
+ render_session_details( $inspect_session_id ); ?>
+
+
+ render_statistics_table( $stats ); ?>
+ render_session_list( $sessions, $inspect_session_id ); ?>
+
+
+
+
+
+ |
+
+ |
+
+
+
+
+ | : |
+
+ render_help( __( 'Number of active agentic cart sessions', 'woocommerce-paypal-payments' ) ); ?>
+ |
+ |
+
+
+ | : |
+
+ render_help( __( 'Total number of items across all carts', 'woocommerce-paypal-payments' ) ); ?>
+ |
+ |
+
+
+
+ | : |
+
+ render_help( __( 'Average age of sessions in hours', 'woocommerce-paypal-payments' ) ); ?>
+ |
+
+ hours
+ |
+
+
+
+
+
+
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+ 'wc-status',
+ 'tab' => 'paypal-agentic',
+ 'inspect_session' => $session_id,
+ 'inspect_nonce' => wp_create_nonce( 'ppcp_inspect_session_' . $session_id ),
+ ),
+ admin_url( 'admin.php' )
+ );
+
+ $is_inspecting = $inspect_session_id === $session_id;
+ ?>
+ >
+
+
+ ...
+
+ |
+ |
+ |
+ |
+ h |
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+ inspector->inspect_cart_session( $session_id );
+
+ if ( ! $details ) {
+ ?>
+
+
+
+
+
+
+
+
+
+
+
+ | : |
+ |
+
+
+ | : |
+ |
+
+
+ | : |
+ |
+
+
+ | : |
+ |
+
+
+ | : |
+ |
+
+
+
+
+
+
+
+
+
+
+ | : |
+ totals->subtotal . ' ' . $cart->currency ); ?> |
+
+
+ | : |
+ totals->shipping . ' ' . $cart->currency ); ?> |
+
+
+ | : |
+ totals->tax . ' ' . $cart->currency ); ?> |
+
+
+ | : |
+ totals->discount . ' ' . $cart->currency ); ?> |
+
+
+ | : |
+ totals->total . ' ' . $cart->currency ); ?> |
+
+
+
+
+
+
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+
+ items as $item ) : ?>
+
+
+ name ); ?>
+ image_url ) ) : ?>
+
+
+ |
+ sku ?: '-' ); ?> |
+ quantity ); ?> |
+ unit_amount . ' ' . $cart->currency ); ?> |
+
+ unit_amount * $item->quantity ) . ' ' . $cart->currency ); ?>
+ |
+
+
+
+
+
+ shipping_address ) ) : ?>
+
+
+ shipping_address;
+ echo esc_html( $address->name ?? '' );
+ if ( ! empty( $address->address_line_1 ) ) {
+ echo '
' . esc_html( $address->address_line_1 );
+ }
+ if ( ! empty( $address->address_line_2 ) ) {
+ echo '
' . esc_html( $address->address_line_2 );
+ }
+ if ( ! empty( $address->city ) || ! empty( $address->state ) || ! empty( $address->postal_code ) ) {
+ echo '
' . esc_html(
+ implode(
+ ', ',
+ array_filter(
+ array(
+ $address->city ?? '',
+ $address->state ?? '',
+ $address->postal_code ?? '',
+ )
+ )
+ )
+ );
+ }
+ if ( ! empty( $address->country_code ) ) {
+ echo '
' . esc_html( $address->country_code );
+ }
+ ?>
+
+
+
+
+
+
+
+
+ registration_service = $registration_service;
+ $this->eligibility_check = $eligibility_check;
+ $this->auth_provider = $auth_provider;
+ $this->general_settings = $general_settings;
+ }
+
+ /**
+ * Render the registration status section.
+ */
+ public function render(): void {
+ $is_eligible = $this->eligibility_check->is_eligible();
+ $is_registered = $this->registration_service->is_registered();
+ $merchant_id = $this->general_settings->get_merchant_id();
+ $auth_service = $this->auth_provider->auth_service();
+
+ ?>
+
+
+
+ render_notices(); ?>
+
+
+
+
+ |
+
+ |
+
+
+
+
+ |
+ :
+ |
+
+ render_help( __( 'Whether this store can use agentic commerce features', 'woocommerce-paypal-payments' ) ); ?>
+ |
+
+ render_boolean_badge(
+ $is_eligible,
+ esc_html__( 'Eligible', 'woocommerce-paypal-payments' ),
+ esc_html__( 'Not eligible', 'woocommerce-paypal-payments' )
+ );
+ ?>
+ |
+
+
+ |
+ :
+ |
+
+ render_help( __( 'Which implementation verifies the JWK token?', 'woocommerce-paypal-payments' ) ); ?>
+ |
+
+ %s', get_class( $auth_service ) ) ); ?>
+ |
+
+
+ |
+ :
+ |
+
+ render_help( __( 'Is the store registered with the joinhoney service?', 'woocommerce-paypal-payments' ) ); ?>
+ |
+
+
+ render_boolean_badge(
+ $is_registered,
+ esc_html__( 'Registered', 'woocommerce-paypal-payments' ),
+ esc_html__( 'Not registered', 'woocommerce-paypal-payments' )
+ );
+ ?>
+ render_toggle_form( $is_registered ); ?>
+
+ |
+
+
+
+ |
+ :
+ |
+ |
+ |
+
+
+
+
+
+
+
+ __( 'Successfully registered with PayPal Agentic Commerce.', 'woocommerce-paypal-payments' ),
+ 'unregistered' => __( 'Successfully unregistered from PayPal Agentic Commerce.', 'woocommerce-paypal-payments' ),
+ 'error' => __( 'Failed to update registration status. Please try again.', 'woocommerce-paypal-payments' ),
+ );
+
+ if ( ! isset( $messages[ $notice_type ] ) ) {
+ return;
+ }
+
+ $class = $notice_type === 'error' ? 'error' : 'updated';
+ ?>
+
+ ',
+ esc_attr( $label )
+ )
+ );
+ }
+
+ /**
+ * Render a boolean status badge (yes/no with icon).
+ *
+ * @param bool $is_true Whether the status is true.
+ * @param string $label_true Label to display when true.
+ * @param string $label_false Label to display when false.
+ */
+ protected function render_boolean_badge( bool $is_true, string $label_true, string $label_false ): void {
+ if ( $is_true ) {
+ echo wp_kses_post(
+ sprintf(
+ ' %s',
+ $label_true
+ )
+ );
+
+ return;
+ }
+
+ echo wp_kses_post(
+ sprintf(
+ ' %s',
+ $label_false
+ )
+ );
+ }
+}
diff --git a/modules/ppcp-agentic-commerce/src/Registration/RegistrationService.php b/modules/ppcp-agentic-commerce/src/Registration/RegistrationService.php
index 795e27974..0d097282f 100644
--- a/modules/ppcp-agentic-commerce/src/Registration/RegistrationService.php
+++ b/modules/ppcp-agentic-commerce/src/Registration/RegistrationService.php
@@ -24,6 +24,7 @@ public function __construct(
AgenticWebhookConfiguration $webhook_urls,
MerchantMetadataProvider $metadata_provider
) {
+
$this->webhook_urls = $webhook_urls;
$this->metadata_provider = $metadata_provider;
}
diff --git a/tests/PHPUnit/AgenticCommerce/Config/AgenticWebhookConfigurationTest.php b/tests/PHPUnit/AgenticCommerce/Config/AgenticWebhookConfigurationTest.php
index 9ed332e2d..b11d70f11 100644
--- a/tests/PHPUnit/AgenticCommerce/Config/AgenticWebhookConfigurationTest.php
+++ b/tests/PHPUnit/AgenticCommerce/Config/AgenticWebhookConfigurationTest.php
@@ -51,9 +51,9 @@ public function environment_specific_url_provider(): array {
return array(
'sandbox environment uses sandbox base URL' => array(
false,
- 'https://d-sandbox.joinhoney.com/webhooks/ws/install',
- 'https://d-sandbox.joinhoney.com/webhooks/ws/uninstall',
- 'https://d-sandbox.joinhoney.com/webhooks/products',
+ 'https://d-staging.joinhoney.com/webhooks/ws/install',
+ 'https://d-staging.joinhoney.com/webhooks/ws/uninstall',
+ 'https://d-staging.joinhoney.com/webhooks/products',
),
'production environment uses live base URL' => array(
true,