PluginProbe ʕ •ᴥ•ʔ
WooCommerce Square / 5.4.2
WooCommerce Square v5.4.2
5.4.2 5.4.1 5.4.0 trunk 1.0.25 1.0.26 1.0.27 1.0.28 1.0.29 1.0.30 1.0.31 1.0.32 1.0.33 1.0.34 1.0.35 1.0.36 1.0.37 1.0.38 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.3.0 2.3.1 2.3.2 2.3.3 2.3.4 2.4.0 2.4.1 2.5.0 2.5.1 2.5.2 2.5.3 2.6.0 2.7.0 2.8.0 2.9.0 2.9.1 3.0.0 3.0.1 3.0.2 3.0.3 3.1.0 3.2.0 3.3.0 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.6.1 3.7.0 3.7.1 3.8.0 3.8.1 3.8.2 3.8.3 3.9.0 4.0.0 4.1.0 4.2.0 4.2.1 4.2.2 4.2.3 4.3.0 4.3.1 4.3.2 4.4.0 4.4.1 4.4.2 4.5.0 4.5.1 4.5.2 4.6.0 4.6.1 4.6.2 4.6.3 4.6.4 4.7.0 4.7.1 4.7.2 4.7.3 4.7.4 4.8.0 4.8.1 4.8.2 4.8.3 4.8.4 4.8.5 4.8.6 4.8.7 4.8.8 4.9.0 4.9.1 4.9.2 4.9.3 4.9.4 4.9.5 4.9.6 4.9.7 4.9.8 4.9.9 5.0.0 5.0.1 5.1.0 5.1.1 5.1.2 5.2.0 5.3.0 5.3.1 5.3.2 5.3.3
woocommerce-square / includes / Internal / Abilities / Domain / GetSyncRecords.php
woocommerce-square / includes / Internal / Abilities / Domain Last commit date
AbstractSquareAbility.php 1 month ago GetConnectionStatus.php 1 month ago GetLocations.php 1 month ago GetOrderPaymentStatus.php 1 month ago GetPendingJobs.php 1 month ago GetProductSyncState.php 1 month ago GetSyncRecords.php 1 month ago GetSyncStatus.php 1 month ago
GetSyncRecords.php
164 lines
1 <?php
2 /**
3 * Get sync records ability definition.
4 *
5 * @package WooCommerce\Square
6 */
7
8 // @phan-file-suppress PhanUndeclaredClassMethod, PhanUndeclaredFunction @phan-suppress-current-line UnusedSuppression -- Abilities API + AbilityDefinition added in WC 10.9; suppression covers older-WC compat runs where this class never loads.
9
10 namespace WooCommerce\Square\Internal\Abilities\Domain;
11
12 defined( 'ABSPATH' ) || exit;
13
14 use Automattic\WooCommerce\Abilities\AbilityDefinition;
15 use WooCommerce\Square\Internal\Abilities\Abilities_Registrar;
16 use WooCommerce\Square\Sync\Records;
17
18 /**
19 * Registers the woocommerce-square/get-sync-records ability.
20 *
21 * Returns entries from the Square sync log (per-product warnings, errors,
22 * hidden products) so agents can diagnose "why didn't product X sync?" or
23 * "what went wrong in yesterday's sync?". Filter parameters mirror the
24 * subset of arguments accepted by Records::get_records() that make sense
25 * to expose: type, product_id, limit, sort. orderby stays internal at
26 * 'date' for predictability.
27 *
28 * Backing detail: Records::get_records() applies `max(50, $limit)` — that
29 * is a floor, not a ceiling, so the service itself returns up to 50
30 * records regardless of values below 50. The 50-record upper bound is
31 * enforced by the input schema's `maximum: 50` on the `limit` property,
32 * which clamps oversize requests before they reach the backing service.
33 * Each Record is coerced to a plain associative array so the internal
34 * Record class shape stays out of the ability contract.
35 *
36 * @internal Only loaded when WooCommerce 10.9+ is active.
37 */
38 class GetSyncRecords extends AbstractSquareAbility implements AbilityDefinition {
39
40 public static function get_name(): string {
41 return 'woocommerce-square/get-sync-records';
42 }
43
44 public static function get_registration_args(): array {
45 return array(
46 'label' => __( 'Get Square sync records', 'woocommerce-square' ),
47 'description' => __( 'Return entries from the Square sync log (per-product warnings, errors, hidden products) with optional filters by type, product, sort and limit. Limit is clamped to 50 by the input schema.', 'woocommerce-square' ),
48 'category' => self::CATEGORY_SLUG,
49 'input_schema' => array(
50 'type' => 'object',
51 'default' => (object) array(),
52 'properties' => array(
53 'type' => array(
54 'type' => 'string',
55 'description' => __( 'Filter records by type. Optional.', 'woocommerce-square' ),
56 ),
57 'product_id' => array(
58 'type' => 'integer',
59 'minimum' => 1,
60 'description' => __( 'Filter records to those attached to a specific WooCommerce product ID. Optional.', 'woocommerce-square' ),
61 ),
62 'sort' => array(
63 'type' => 'string',
64 'enum' => array( 'ASC', 'DESC' ),
65 'default' => 'DESC',
66 'description' => __( 'Sort direction (by date). Defaults to DESC (newest first).', 'woocommerce-square' ),
67 ),
68 'limit' => array(
69 'type' => 'integer',
70 'minimum' => 1,
71 'maximum' => 50,
72 'default' => 50,
73 'description' => __( 'Maximum number of records to return. The schema enforces a hard upper bound of 50.', 'woocommerce-square' ),
74 ),
75 ),
76 'additionalProperties' => false,
77 ),
78 'execute_callback' => array( self::class, 'execute' ),
79 'permission_callback' => array( Abilities_Registrar::class, 'can_manage_woocommerce_square' ),
80 'meta' => array(
81 'annotations' => array(
82 'readonly' => true,
83 'destructive' => false,
84 'idempotent' => true,
85 ),
86 'show_in_rest' => true,
87 'mcp' => array(
88 'public' => true,
89 ),
90 ),
91 );
92 }
93
94 /**
95 * Execute callback.
96 *
97 * @param mixed $input Filter args (type, product_id, sort, limit).
98 * @return array|\WP_Error Array of record summaries.
99 */
100 public static function execute( $input = null ) {
101 // Records is a static service — no plugin instance involved — so we
102 // guard the class itself rather than reaching for
103 // AbstractSquareAbility::get_settings_handler_or_error() /
104 // get_sync_handler_or_error(), which gate on the plugin instance and
105 // its handlers. The error code is intentionally identical so MCP
106 // clients see a uniform "plugin not initialized" surface.
107 if ( ! class_exists( Records::class ) ) {
108 return new \WP_Error(
109 'woocommerce_square_not_initialized',
110 __( 'Square for WooCommerce is not initialized.', 'woocommerce-square' )
111 );
112 }
113
114 $input = is_array( $input ) ? $input : array();
115
116 // Runtime clamp duplicates the schema's `minimum: 1` / `maximum: 50` bound on `limit`.
117 // The Abilities Loader applies the schema before execute() runs, so this branch only
118 // kicks in for direct callers that reach execute() outside the loader (tests, other
119 // PHP code). Keeping both copies guards against a future reader tightening one side
120 // of the contract and leaving the other stale.
121 $limit = isset( $input['limit'] ) ? max( 1, min( 50, (int) $input['limit'] ) ) : 50;
122
123 $args = array(
124 'orderby' => 'date',
125 'sort' => isset( $input['sort'] ) && 'ASC' === $input['sort'] ? 'ASC' : 'DESC',
126 'limit' => $limit,
127 );
128
129 if ( ! empty( $input['type'] ) ) {
130 $args['type'] = (string) $input['type'];
131 }
132 if ( ! empty( $input['product_id'] ) ) {
133 $args['product'] = (int) $input['product_id'];
134 }
135
136 // Records::get_records() applies max(50, $limit) as a floor, so a
137 // limit < 50 still returns up to 50 records. Trim post-fetch so the
138 // ability honors the schema's `minimum: 1` (no point advertising a
139 // contract the backing service does not enforce).
140 $records = Records::get_records( $args );
141 if ( ! is_array( $records ) ) {
142 return array();
143 }
144 $records = array_slice( $records, 0, $limit );
145
146 $out = array();
147 foreach ( $records as $record ) {
148 if ( ! is_object( $record ) ) {
149 continue;
150 }
151 $out[] = array(
152 'id' => method_exists( $record, 'get_id' ) ? (string) $record->get_id() : '',
153 'type' => method_exists( $record, 'get_type' ) ? (string) $record->get_type() : '',
154 'message' => method_exists( $record, 'get_message' ) ? (string) $record->get_message() : '',
155 'product_id' => method_exists( $record, 'get_product_id' ) ? ( $record->get_product_id() ? (int) $record->get_product_id() : null ) : null,
156 'timestamp' => method_exists( $record, 'get_timestamp' ) ? (int) $record->get_timestamp() : 0,
157 'is_resolved' => method_exists( $record, 'is_resolved' ) ? (bool) $record->is_resolved() : false,
158 );
159 }
160
161 return $out;
162 }
163 }
164