| @@ -539,11 +539,34 @@ | ||
| 539 | 539 | ) { |
| 540 | 540 | return $transient_data; |
| 541 | 541 | } |
| 542 | 542 | |
| 543 | + // Alias. | |
| 544 | + $basename = $this->_fs->premium_plugin_basename(); | |
| 545 | + | |
| 543 | 546 | global $wp_current_filter; |
| 544 | 547 | |
| 545 | - if ( ! empty( $wp_current_filter ) && in_array( 'upgrader_process_complete', $wp_current_filter ) ) { | |
| 548 | + /** | |
| 549 | + * During bulk updates, avoid re-injecting update data for the plugin itself once it has already been updated. | |
| 550 | + * | |
| 551 | + * If the custom package is re-added to the transient after the plugin update, WordPress may detect the package again and incorrectly report "The plugin is at the latest version" for a pending update, since the custom package version matches the currently installed version. | |
| 552 | + * | |
| 553 | + * Behavior differs depending on how the bulk update is triggered. Please refer to the inline comments for each flow below for details. | |
| 554 | + */ | |
| 555 | + if ( | |
| 556 | + ! empty( $wp_current_filter ) && ( | |
| 557 | + /** | |
| 558 | + * update-core.php and other upgrader pages: | |
| 559 | + * The `upgrader_process_complete` action fires only once after all updates have finished. In this case, it is the current action (`$wp_current_filter[0]`), while `self::$_upgrade_basename` may contain any plugin basename. | |
| 560 | + */ | |
| 561 | + 'upgrader_process_complete' === $wp_current_filter[0] || | |
| 562 | + /** | |
| 563 | + * AJAX bulk updates (e.g., from the Plugins page): | |
| 564 | + * The `upgrader_process_complete` action fires multiple times — once for each plugin after it finishes updating. In this flow, it is not the current action (`$wp_current_filter[0]`) because it is triggered from another action. Instead, we compare `self::$_upgrade_basename` with the basename of the plugin currently being updated, since the `upgrader_process_complete` action runs separately for each plugin. | |
| 565 | + */ | |
| 566 | + ( in_array( 'upgrader_process_complete', $wp_current_filter ) && self::$_upgrade_basename === $basename ) | |
| 567 | + ) | |
| 568 | + ) { | |
| 546 | 569 | return $transient_data; |
| 547 | 570 | } |
| 548 | 571 | |
| 549 | 572 | if ( ! isset( $this->_update_details ) ) { |
| @@ -564,11 +587,8 @@ | ||
| 564 | 587 | */ |
| 565 | 588 | $this->_update_details = $this->get_update_details( $new_version ); |
| 566 | 589 | } |
| 567 | 590 | } |
| 568 | - | |
| 569 | - // Alias. | |
| 570 | - $basename = $this->_fs->premium_plugin_basename(); | |
| 571 | 591 | |
| 572 | 592 | if ( is_object( $this->_update_details ) ) { |
| 573 | 593 | if ( isset( $transient_data->no_update ) ) { |
| 574 | 594 | unset( $transient_data->no_update[ $basename ] ); |