← All changes
|
jetpack_vendor/automattic/jetpack-premium-analytics/src/Sync/class-configuration.php
+69
-117
16.2
→
16.3-beta
View file →
| @@ -1,12 +1,8 @@ | ||
| 1 | 1 | <?php |
| 2 | 2 | /** |
| 3 | - * TEMPORARY: interim port for WOOA7S-1550 — remove when the shared sync-modules composer package lands. | |
| 3 | + * Premium Analytics glue for the shared WooCommerce Analytics sync module. | |
| 4 | 4 | * |
| 5 | - * Plain replacement for woocommerce-analytics' src/Internal/Jetpack/Sync/Configuration.php, invoked | |
| 6 | - * from {@see \Automattic\Jetpack\PremiumAnalytics\Analytics::init()} since this package has no PHP-DI | |
| 7 | - * container to wire it through like upstream. Omits upstream's connection bootstrap and admin-script enqueue. | |
| 8 | - * | |
| 9 | 5 | * @package automattic/jetpack-premium-analytics |
| 10 | 6 | */ |
| 11 | 7 | |
| 12 | 8 | namespace Automattic\Jetpack\PremiumAnalytics\Sync; |
| @@ -12,37 +8,44 @@ | ||
| 12 | 8 | namespace Automattic\Jetpack\PremiumAnalytics\Sync; |
| 13 | 9 | |
| 14 | 10 | use Automattic\Jetpack\Config; |
| 15 | 11 | use Automattic\Jetpack\Sync\Data_Settings; |
| 16 | -use Automattic\Jetpack\Sync\Modules as JetpackSyncModules; | |
| 17 | 12 | use Automattic\Jetpack\Sync\Modules\Meta as Meta_Module; |
| 18 | 13 | use Automattic\Jetpack\Sync\Modules\Posts as Posts_Module; |
| 19 | 14 | use Automattic\Jetpack\Sync\Modules\Term_Relationships as Term_Relationships_Module; |
| 20 | 15 | use Automattic\Jetpack\Sync\Modules\Terms as Terms_Module; |
| 16 | +use Automattic\Jetpack\Sync\Modules\WooCommerce_Analytics as WooCommerce_Analytics_Module; | |
| 21 | 17 | |
| 22 | 18 | defined( 'ABSPATH' ) || exit; |
| 23 | 19 | |
| 24 | 20 | /** |
| 25 | - * Registers the WooCommerce Analytics Jetpack Sync module and its supporting filters. | |
| 21 | + * Opts in to the shared WooCommerce Analytics sync module and registers the | |
| 22 | + * Premium Analytics-specific sync configuration. | |
| 26 | 23 | */ |
| 27 | 24 | class Configuration { |
| 28 | 25 | |
| 29 | - use Utilities; | |
| 26 | + /** | |
| 27 | + * FQCN of the Analytics module shipped by the standalone WooCommerce Analytics plugin. | |
| 28 | + * | |
| 29 | + * Must track that plugin's class: if it drifts, both modules load under the same | |
| 30 | + * name and every analytics event syncs twice. Moot once that plugin consumes the | |
| 31 | + * shared module, since the class strings then match. | |
| 32 | + * | |
| 33 | + * @since 0.9.0 | |
| 34 | + * @var string | |
| 35 | + */ | |
| 36 | + const ANALYTICS_PLUGIN_MODULE_FQCN = 'Automattic\\WooCommerce\\Analytics\\Internal\\Jetpack\\Sync\\Modules\\Analytics'; | |
| 30 | 37 | |
| 31 | 38 | /** |
| 32 | - * List of post meta to add to Sync's post meta whitelist. | |
| 33 | - * Any changes to these meta will be synced to WordPress.com. | |
| 39 | + * Bookings post meta to add to Sync's post meta whitelist. Bookings are synced | |
| 40 | + * via the Posts + Meta modules; there is no dedicated bookings sync module. | |
| 34 | 41 | * |
| 42 | + * Product meta needed by analytics reports is whitelisted by the shared module. | |
| 43 | + * | |
| 35 | 44 | * @static |
| 36 | 45 | * @var array |
| 37 | 46 | */ |
| 38 | 47 | private static $postmeta_to_sync = array( |
| 39 | - // Products. | |
| 40 | - '_stock', | |
| 41 | - '_stock_quantity', | |
| 42 | - '_cogs_total_value', | |
| 43 | - '_global_unique_id', | |
| 44 | - // Bookings. | |
| 45 | 48 | '_booking_parent_id', |
| 46 | 49 | '_booking_duplicate_of', |
| 47 | 50 | '_booking_product_id', |
| 48 | 51 | '_booking_resource_id', |
| @@ -58,18 +61,22 @@ | ||
| 58 | 61 | '_booking_attendance_status', |
| 59 | 62 | ); |
| 60 | 63 | |
| 61 | 64 | /** |
| 62 | - * Entry point called from Analytics::init(). Schedules the Sync hookups on plugins_loaded; | |
| 63 | - * the actual registration is a no-op unless WooCommerce is active (see {@see configure_sync()}). | |
| 65 | + * Entry point called from Analytics::init(). Schedules the Sync hookups on | |
| 66 | + * plugins_loaded; the actual registration is a no-op unless WooCommerce is active | |
| 67 | + * (see {@see configure_sync()}). | |
| 64 | 68 | * |
| 69 | + * Call it before plugins_loaded completes: the Config built in configure_sync() wires | |
| 70 | + * Sync\Main::configure() from a plugins_loaded priority 2 handler that never fires later. | |
| 71 | + * | |
| 65 | 72 | * @return void |
| 66 | 73 | */ |
| 67 | 74 | public static function register(): void { |
| 68 | 75 | $instance = new self(); |
| 69 | 76 | |
| 70 | - // Defer to plugins_loaded so the WooCommerce-active guard runs after every plugin loads; priority 1 | |
| 71 | - // also lets the Jetpack Config constructed below run its on_plugins_loaded (priority 2) handler in the same cycle. | |
| 77 | + // plugins_loaded priority 1: every plugin has loaded for the WooCommerce guard, and the | |
| 78 | + // Config constructed in configure_sync() still gets its priority 2 handler in this cycle. | |
| 72 | 79 | if ( did_action( 'plugins_loaded' ) ) { |
| 73 | 80 | $instance->configure_sync(); |
| 74 | 81 | } else { |
| 75 | 82 | add_action( 'plugins_loaded', array( $instance, 'configure_sync' ), 1 ); |
| @@ -85,13 +92,11 @@ | ||
| 85 | 92 | return class_exists( 'WooCommerce' ) || function_exists( 'WC' ); |
| 86 | 93 | } |
| 87 | 94 | |
| 88 | 95 | /** |
| 89 | - * Register the Jetpack Sync filters and ensure the Sync feature, when WooCommerce is active. | |
| 96 | + * Register the Jetpack Sync filters and ensure the Sync feature when WooCommerce | |
| 97 | + * is active. | |
| 90 | 98 | * |
| 91 | - * No-op unless WooCommerce is active, since the module relies on WooCommerce runtime symbols | |
| 92 | - * (WC_Order, the wc_order_stats table, OrderUtil, etc.). | |
| 93 | - * | |
| 94 | 99 | * @return void |
| 95 | 100 | */ |
| 96 | 101 | public function configure_sync(): void { |
| 97 | 102 | if ( ! self::is_woocommerce_active() ) { |
| @@ -97,11 +102,11 @@ | ||
| 97 | 102 | if ( ! self::is_woocommerce_active() ) { |
| 98 | 103 | return; |
| 99 | 104 | } |
| 100 | 105 | |
| 101 | - add_filter( 'jetpack_sync_modules', array( $this, 'add_woocommerce_analytics_module' ) ); | |
| 106 | + // The shared module is registered through the Sync config below; this only drops a duplicate. | |
| 107 | + add_filter( 'jetpack_sync_modules', array( $this, 'remove_duplicate_woocommerce_analytics_module' ), PHP_INT_MAX ); | |
| 102 | 108 | add_filter( 'jetpack_full_sync_config', array( $this, 'expand_full_sync_config' ) ); |
| 103 | - add_filter( 'jetpack_sync_checksum_allowed_tables', array( $this, 'add_order_stats_to_checksum' ) ); | |
| 104 | 109 | add_filter( 'jetpack_sync_post_meta_whitelist', array( $this, 'add_meta_to_sync_post_meta_whitelist' ) ); |
| 105 | 110 | |
| 106 | 111 | ( new Config() )->ensure( 'sync', $this->get_jetpack_sync_config() ); |
| 107 | 112 | } |
| @@ -106,43 +111,27 @@ | ||
| 106 | 111 | ( new Config() )->ensure( 'sync', $this->get_jetpack_sync_config() ); |
| 107 | 112 | } |
| 108 | 113 | |
| 109 | 114 | /** |
| 110 | - * Add the WooCommerce Analytics module to the list of Jetpack Sync modules. | |
| 115 | + * Jetpack Sync module configuration. | |
| 111 | 116 | * |
| 112 | - * @param array $modules The current list of sync module class names. | |
| 113 | - * @return array | |
| 114 | - */ | |
| 115 | - public function add_woocommerce_analytics_module( $modules ) { | |
| 116 | - if ( is_array( $modules ) && ! in_array( WooCommerce_Analytics_Module::class, $modules, true ) ) { | |
| 117 | - $modules[] = WooCommerce_Analytics_Module::class; | |
| 118 | - } | |
| 119 | - | |
| 120 | - return $modules; | |
| 121 | - } | |
| 122 | - | |
| 123 | - /** | |
| 124 | - * Jetpack Sync module configuration. | |
| 117 | + * MUST_SYNC_DATA_SETTINGS is merged in because Data_Settings falls back to the full default | |
| 118 | + * whitelist for any filter a consumer leaves out, which would widen standalone sites. | |
| 125 | 119 | * |
| 126 | 120 | * @return array Jetpack Sync config array. |
| 127 | 121 | */ |
| 128 | 122 | private function get_jetpack_sync_config(): array { |
| 129 | - $jetpack_sync_modules = array_keys( | |
| 130 | - array_filter( | |
| 131 | - array( | |
| 132 | - WooCommerce_Analytics_Module::class => true, | |
| 133 | - Meta_Module::class => true, | |
| 134 | - Posts_Module::class => true, | |
| 135 | - Terms_Module::class => true, | |
| 136 | - Term_Relationships_Module::class => true, | |
| 137 | - ) | |
| 138 | - ) | |
| 139 | - ); | |
| 140 | - | |
| 141 | 123 | return array_merge_recursive( |
| 142 | 124 | Data_Settings::MUST_SYNC_DATA_SETTINGS, |
| 143 | 125 | array( |
| 144 | - 'jetpack_sync_modules' => $jetpack_sync_modules, | |
| 126 | + 'jetpack_sync_modules' => array( | |
| 127 | + WooCommerce_Analytics_Module::class, | |
| 128 | + Meta_Module::class, | |
| 129 | + Posts_Module::class, | |
| 130 | + Terms_Module::class, | |
| 131 | + Term_Relationships_Module::class, | |
| 132 | + ), | |
| 133 | + // Listed explicitly so the contract does not depend on which other Sync modules load. | |
| 145 | 134 | 'jetpack_sync_options_whitelist' => array( |
| 146 | 135 | 'woocommerce_custom_orders_table_enabled', // Required for HPOS checksums. |
| 147 | 136 | 'woocommerce_excluded_report_order_statuses', // Required for generating analytics reports. |
| 148 | 137 | 'woocommerce_date_type', // Date used to determine the date range for analytics reports. |
| @@ -147,10 +136,10 @@ | ||
| 147 | 136 | 'woocommerce_excluded_report_order_statuses', // Required for generating analytics reports. |
| 148 | 137 | 'woocommerce_date_type', // Date used to determine the date range for analytics reports. |
| 149 | 138 | ), |
| 150 | 139 | 'jetpack_sync_constants_whitelist' => array( |
| 151 | - // Syncing this triggers WPCom to provision the WC Analytics tables (WOOA7S-1643). | |
| 152 | - // WC_ANALYTICS_VERSION is omitted: only woocommerce-analytics defines it, so a PA-only store would sync null. | |
| 140 | + // Syncing it makes WPCOM provision the WC Analytics tables (WOOA7S-1643). WC_ANALYTICS_VERSION | |
| 141 | + // belongs to the standalone plugin and would only sync null on a PA-only store. | |
| 153 | 142 | 'JETPACK_PREMIUM_ANALYTICS__VERSION', |
| 154 | 143 | ), |
| 155 | 144 | ) |
| 156 | 145 | ); |
| @@ -156,19 +145,36 @@ | ||
| 156 | 145 | ); |
| 157 | 146 | } |
| 158 | 147 | |
| 159 | 148 | /** |
| 160 | - * Expand full sync config with module required by WooCommerce Analytics if not already present. | |
| 149 | + * Drop the standalone plugin's Analytics module in favor of the shared one. | |
| 161 | 150 | * |
| 162 | - * @param array $config The current full sync configuration. | |
| 163 | - * @return array The modified full sync configuration. | |
| 151 | + * Sync dedups by class name only, so both would load and sync every event twice. The shared | |
| 152 | + * module wins because the released standalone one syncs no lookup data, while the sync package | |
| 153 | + * advertises the lookup checksum tables for any module of this name. | |
| 154 | + * | |
| 155 | + * Runs at PHP_INT_MAX because Data_Settings re-asserts its whole module list at priority 10. | |
| 156 | + * | |
| 157 | + * @param array|mixed $modules Current Sync module class names. | |
| 158 | + * @return array|mixed Updated Sync module class names. | |
| 164 | 159 | */ |
| 165 | - public function expand_full_sync_config( array $config ): array { | |
| 166 | - if ( ! $this->can_site_sync_orders() ) { | |
| 167 | - return $config; | |
| 160 | + public function remove_duplicate_woocommerce_analytics_module( $modules ) { | |
| 161 | + // An emptied list is a kill switch (Jetpack's uninstaller uses one); leave it alone. | |
| 162 | + if ( ! is_array( $modules ) || empty( $modules ) ) { | |
| 163 | + return $modules; | |
| 168 | 164 | } |
| 169 | 165 | |
| 170 | - // Let's ensure Terms and Term_Relationships will always get synced before Posts during Full Sync. | |
| 166 | + return array_values( array_diff( $modules, array( self::ANALYTICS_PLUGIN_MODULE_FQCN ) ) ); | |
| 167 | + } | |
| 168 | + | |
| 169 | + /** | |
| 170 | + * Add the Analytics module to full sync, first in line. | |
| 171 | + * | |
| 172 | + * @param array $config Current full-sync configuration. | |
| 173 | + * @return array Updated full-sync configuration. | |
| 174 | + */ | |
| 175 | + public function expand_full_sync_config( array $config ): array { | |
| 176 | + // Terms and term relationships must be synced before posts. | |
| 171 | 177 | if ( isset( $config['posts'] ) ) { |
| 172 | 178 | unset( $config['posts'] ); |
| 173 | 179 | $config += array( 'posts' => 1 ); |
| 174 | 180 | } |
| @@ -180,63 +186,9 @@ | ||
| 180 | 186 | return $config; |
| 181 | 187 | } |
| 182 | 188 | |
| 183 | 189 | /** |
| 184 | - * Adds the order stats table to the checksum allowed tables. | |
| 185 | - * | |
| 186 | - * @param array $tables The current checksum allowed tables. | |
| 187 | - * @return array The modified checksum allowed tables. | |
| 188 | - */ | |
| 189 | - public function add_order_stats_to_checksum( array $tables ): array { | |
| 190 | - if ( ! $this->can_site_sync_orders() ) { | |
| 191 | - return $tables; | |
| 192 | - } | |
| 193 | - | |
| 194 | - global $wpdb; | |
| 195 | - $order_stats_checksum_table = array( | |
| 196 | - 'wc_order_stats' => array( | |
| 197 | - 'table' => "{$wpdb->prefix}wc_order_stats", | |
| 198 | - 'range_field' => 'order_id', | |
| 199 | - 'key_fields' => array( 'order_id' ), | |
| 200 | - 'checksum_fields' => array( 'date_paid', 'date_completed', 'total_sales' ), | |
| 201 | - 'checksum_text_fields' => array( 'status' ), | |
| 202 | - 'is_table_enabled_callback' => function () { | |
| 203 | - return false !== JetpackSyncModules::get_module( 'woocommerce_analytics' ); | |
| 204 | - }, | |
| 205 | - ), | |
| 206 | - 'wc_order_product_lookup' => array( | |
| 207 | - 'table' => "{$wpdb->prefix}wc_order_product_lookup", | |
| 208 | - 'range_field' => 'order_id', | |
| 209 | - 'key_fields' => array( 'order_id', 'order_item_id' ), | |
| 210 | - 'checksum_fields' => array( 'product_id', 'variation_id', 'product_qty', 'product_net_revenue', 'date_created' ), | |
| 211 | - 'is_table_enabled_callback' => function () { | |
| 212 | - return false !== JetpackSyncModules::get_module( 'woocommerce_analytics' ); | |
| 213 | - }, | |
| 214 | - ), | |
| 215 | - 'wc_order_coupon_lookup' => array( | |
| 216 | - 'table' => "{$wpdb->prefix}wc_order_coupon_lookup", | |
| 217 | - 'range_field' => 'order_id', | |
| 218 | - 'key_fields' => array( 'order_id', 'coupon_id' ), | |
| 219 | - 'checksum_fields' => array( 'discount_amount', 'date_created' ), | |
| 220 | - 'is_table_enabled_callback' => function () { | |
| 221 | - return false !== JetpackSyncModules::get_module( 'woocommerce_analytics' ); | |
| 222 | - }, | |
| 223 | - ), | |
| 224 | - 'wc_order_tax_lookup' => array( | |
| 225 | - 'table' => "{$wpdb->prefix}wc_order_tax_lookup", | |
| 226 | - 'range_field' => 'order_id', | |
| 227 | - 'key_fields' => array( 'order_id', 'tax_rate_id' ), | |
| 228 | - 'checksum_fields' => array( 'order_tax', 'total_tax', 'shipping_tax', 'date_created' ), | |
| 229 | - 'is_table_enabled_callback' => function () { | |
| 230 | - return false !== JetpackSyncModules::get_module( 'woocommerce_analytics' ); | |
| 231 | - }, | |
| 232 | - ), | |
| 233 | - ); | |
| 234 | - return array_merge( $tables, $order_stats_checksum_table ); | |
| 235 | - } | |
| 236 | - | |
| 237 | - /** | |
| 238 | - * Add WC Analytics post meta to Sync's post meta whitelist. | |
| 190 | + * Add Bookings post meta to Sync's post meta whitelist. | |
| 239 | 191 | * Any changes to these meta will be synced to WordPress.com. |
| 240 | 192 | * |
| 241 | 193 | * @param array $whitelist Existing post meta whitelist. |
| 242 | 194 | * @return array Updated post meta whitelist. |