PluginProbe
WCPOS – Point of Sale (POS) plugin for WooCommerce / 1.10.19
WCPOS – Point of Sale (POS) plugin for WooCommerce v1.10.19
1.10.19 1.10.18 1.10.17 1.10.16 1.10.15 1.10.13 1.10.14 1.10.12 1.10.11 1.10.10 1.10.9 1.10.8 untagged-3d9b7ccddc54df87c672 1.10.7 1.10.6 1.10.5 1.10.3 1.10.4 1.10.2 1.10.1 1.10.0 1.9.17 1.9.15 1.9.16 1.9.14 All 163 releases
← All changes | includes/Activator.php +45 -17 1.10.131.10.19 View file →
@@ -98,11 +98,28 @@
98 98 /**
99 99 * Fired when the plugin is activated.
100 100 *
101 101 * @param bool $install_sync_schema Whether to install the sync schema.
102 + * @param bool $full_role_sync Whether to repair all default role capabilities.
102 103 */
103 - public function single_activate( bool $install_sync_schema = true ): void {
104 - $role_capabilities = self::role_capability_definition();
104 + public function single_activate( bool $install_sync_schema = true, bool $full_role_sync = true ): void {
105 + $role_capabilities = self::role_capability_definition();
106 + $capability_names = $role_capabilities;
107 + $capability_names['cashier'] = array_merge( array( 'access_woocommerce_pos' ), array_keys( $role_capabilities['cashier'] ) );
108 + $synced = get_option( 'woocommerce_pos_role_caps_synced', false );
109 + if ( ! $full_role_sync && false === $synced && get_option( 'woocommerce_pos_role_caps_fingerprint' ) === $this->role_caps_fingerprint() ) {
110 + $synced = $capability_names;
111 + }
112 + // An upgrade grants only capabilities new to the definition since the
113 + // last sync, so a capability the merchant removed on the Access screen
114 + // stays removed. Explicit activation still repairs every default.
115 + $granted = $capability_names;
116 + if ( ! $full_role_sync && \is_array( $synced ) ) {
117 + foreach ( $granted as $slug => $capabilities ) {
118 + $already = isset( $synced[ $slug ] ) && \is_array( $synced[ $slug ] ) ? $synced[ $slug ] : array();
119 + $granted[ $slug ] = array_values( array_diff( $capabilities, $already ) );
120 + }
121 + }
105 122
106 123 // Reseed the default template terms on the next request: (re)activation
107 124 // is the repair a merchant reaches for after deleting a term by hand.
108 125 // This also runs once per upgrade (version_check re-activates to sync
@@ -115,15 +132,15 @@
115 132 self::autoload_request_latches();
116 133 Admin\Permalink::ensure_default();
117 134
118 135 // create POS specific roles.
119 - $this->create_pos_roles();
136 + $this->create_pos_roles( $granted['cashier'] );
120 137
121 138 // add pos capabilities to non POS roles.
122 139 $this->add_pos_capability(
123 140 array(
124 - 'administrator' => $role_capabilities['administrator'],
125 - 'shop_manager' => $role_capabilities['shop_manager'],
141 + 'administrator' => $granted['administrator'],
142 + 'shop_manager' => $granted['shop_manager'],
126 143 )
127 144 );
128 145
129 146 $stored_roles = get_option( wp_roles()->role_key, array() );
@@ -128,13 +145,14 @@
128 145
129 146 $stored_roles = get_option( wp_roles()->role_key, array() );
130 147 $roles_are_persisted = is_array( $stored_roles );
131 148 if ( $roles_are_persisted ) {
132 - foreach ( $role_capabilities as $slug => $capabilities ) {
133 - $required_capabilities = 'cashier' === $slug
134 - ? array_merge( array( 'access_woocommerce_pos' ), array_keys( $capabilities ) )
135 - : $capabilities;
136 - foreach ( $required_capabilities as $capability ) {
149 + foreach ( $granted as $slug => $capabilities ) {
150 + if ( ! isset( $stored_roles[ $slug ] ) ) {
151 + $roles_are_persisted = false;
152 + break;
153 + }
154 + foreach ( $capabilities as $capability ) {
137 155 if ( empty( $stored_roles[ $slug ]['capabilities'][ $capability ] ) ) {
138 156 $roles_are_persisted = false;
139 157 break 2;
140 158 }
@@ -143,8 +161,11 @@
143 161 }
144 162
145 163 $obsolete_customer_create_cap = isset( $role_capabilities['cashier']['create_customers'] ) ? 'promote_users' : 'create_customers';
146 164 if ( $roles_are_persisted && empty( $stored_roles['cashier']['capabilities'][ $obsolete_customer_create_cap ] ) ) {
165 + // Snapshot first: a fingerprint that advanced past a failed snapshot
166 + // write would never retry it.
167 + update_option( 'woocommerce_pos_role_caps_synced', $capability_names, true );
147 168 update_option( 'woocommerce_pos_role_caps_fingerprint', $this->role_caps_fingerprint(), true );
148 169 }
149 170
150 171 // Flag the consent pop-up for the next admin page load. Done here
@@ -312,9 +333,10 @@
312 333 $plugin_needs_upgrade = version_compare( $old, VERSION, '<' );
313 334 $sync_needs_upgrade = Sync_Api::SCHEMA_VERSION !== get_option( Sync_Api::SCHEMA_OPTION, null );
314 335
315 336 $role_caps_fingerprint = $this->role_caps_fingerprint();
316 - $role_caps_need_sync = get_option( 'woocommerce_pos_role_caps_fingerprint' ) !== $role_caps_fingerprint;
337 + $role_caps_need_sync = get_option( 'woocommerce_pos_role_caps_fingerprint' ) !== $role_caps_fingerprint
338 + || false === get_option( 'woocommerce_pos_role_caps_synced' );
317 339 if ( ! $plugin_needs_upgrade && ! $sync_needs_upgrade && ! $role_caps_need_sync ) {
318 340 return;
319 341 }
320 342
@@ -326,9 +348,10 @@
326 348 $locked_plugin_needs_upgrade = version_compare( $locked_old, VERSION, '<' );
327 349 $locked_sync_needs_upgrade = Sync_Api::SCHEMA_VERSION !== get_option( Sync_Api::SCHEMA_OPTION, null );
328 350
329 351 $locked_role_caps_fingerprint = $this->role_caps_fingerprint();
330 - $locked_role_caps_need_sync = get_option( 'woocommerce_pos_role_caps_fingerprint' ) !== $locked_role_caps_fingerprint;
352 + $locked_role_caps_need_sync = get_option( 'woocommerce_pos_role_caps_fingerprint' ) !== $locked_role_caps_fingerprint
353 + || false === get_option( 'woocommerce_pos_role_caps_synced' );
331 354 if ( ! $locked_plugin_needs_upgrade && ! $locked_sync_needs_upgrade && ! $locked_role_caps_need_sync ) {
332 355 $this->release_db_upgrade_lock();
333 356 return;
334 357 }
@@ -346,9 +369,9 @@
346 369 // requires translations to be loaded (WordPress 6.7+).
347 370 add_action(
348 371 'init',
349 372 function () {
350 - $this->single_activate( false );
373 + $this->single_activate( false, false );
351 374 }
352 375 );
353 376 }
354 377
@@ -513,10 +536,13 @@
513 536 }
514 537
515 538 /**
516 539 * Add POS specific roles.
540 + *
541 + * @param string[]|null $capabilities Capability names to sync onto an existing role, or null for
542 + * every default. A missing role is always created with the full set.
517 543 */
518 - private function create_pos_roles(): void {
544 + private function create_pos_roles( ?array $capabilities = null ): void {
519 545 $role_capabilities = self::role_capability_definition();
520 546 $cashier_capabilities = $role_capabilities['cashier'];
521 547
522 548 add_role(
@@ -522,9 +548,11 @@
522 548 add_role(
523 549 'cashier',
524 550 /* translators: Plugin activation notice label. */
525 551 __( 'Cashier', 'woocommerce-pos' ),
526 - $cashier_capabilities
552 + // A missing role is created whole, access gate included, whatever
553 + // subset an incremental upgrade asked to sync.
554 + array_merge( array( 'access_woocommerce_pos' => true ), $cashier_capabilities )
527 555 );
528 556
529 557 $obsolete_customer_create_cap = isset( $cashier_capabilities['create_customers'] ) ? 'promote_users' : 'create_customers';
530 558 $cashier = get_role( 'cashier' );
@@ -531,14 +559,14 @@
531 559 if ( $cashier ) {
532 560 $cashier->remove_cap( $obsolete_customer_create_cap );
533 561 }
534 562
535 - // Sync all capabilities to the existing role. add_role() is a no-op when
563 + // Sync the requested capabilities to the role. add_role() is a no-op when
536 564 // the role already exists, so capabilities added in newer versions would
537 565 // never reach existing installs without this.
538 566 $this->add_pos_capability(
539 567 array(
540 - 'cashier' => array_merge(
568 + 'cashier' => $capabilities ?? array_merge(
541 569 array( 'access_woocommerce_pos' ),
542 570 array_keys( $cashier_capabilities )
543 571 ),
544 572 )