diff --git a/includes/classes/class-extension.php b/includes/classes/class-extension.php index 4b40f56aed..b2bb989b98 100644 --- a/includes/classes/class-extension.php +++ b/includes/classes/class-extension.php @@ -53,6 +53,10 @@ public function setup_ajax_actions() { return; } + // Ensure WordPress only receives installable Directorist extension updates. + add_filter( 'pre_set_site_transient_update_plugins', [ $this, 'prepare_extension_update_packages' ], PHP_INT_MAX ); + add_filter( 'site_transient_update_plugins', [ $this, 'prepare_extension_update_packages' ], PHP_INT_MAX ); + // Ajax add_action( 'wp_ajax_atbdp_authenticate_the_customer', [ $this, 'authenticate_the_customer' ] ); add_action( 'wp_ajax_atbdp_download_file', [ $this, 'handle_file_download_request' ] ); @@ -957,10 +961,6 @@ private function check_extension_version_via_api( $plugin_key, $plugin_item, $cu return false; } - if ( ! is_array( $plugin_item ) || empty( $plugin_item['license'] ) || empty( $plugin_item['item_id'] ) ) { - return false; - } - if ( ! is_string( $current_version ) || empty( $current_version ) ) { return false; } @@ -968,8 +968,7 @@ private function check_extension_version_via_api( $plugin_key, $plugin_item, $cu // Sanitize inputs. $plugin_key = sanitize_key( $plugin_key ); $current_version = sanitize_text_field( $current_version ); - $license = sanitize_text_field( $plugin_item['license'] ); - $item_id = absint( $plugin_item['item_id'] ); + $license = is_array( $plugin_item ) && ! empty( $plugin_item['license'] ) ? sanitize_text_field( $plugin_item['license'] ) : ''; // Get extension definition. $default_extensions = static::get_default_extensions(); @@ -1061,10 +1060,12 @@ private function get_outdated_extensions_via_api() { $purchased_extensions = self::get_purchased_extension_list(); $default_extensions = static::get_default_extensions(); - if ( ! is_array( $purchased_extensions ) || ! is_array( $default_extensions ) ) { + if ( ! is_array( $default_extensions ) ) { return $outdated_plugins; } + $purchased_extensions = is_array( $purchased_extensions ) ? $purchased_extensions : array(); + // Loop through default extensions and check for updates. foreach ( $default_extensions as $plugin_key => $extension ) { // Validate extension data. @@ -1080,11 +1081,8 @@ private function get_outdated_extensions_via_api() { continue; } - // Check if user has license for this extension. + // Use the license when available. Version discovery does not require one. $plugin_item = self::extract_plugin_from_list( $plugin_key, $purchased_extensions ); - if ( empty( $plugin_item ) || ! is_array( $plugin_item ) || empty( $plugin_item['license'] ) ) { - continue; - } // Get current version. $current_version = isset( $plugins_data[ $base ]['Version'] ) ? $plugins_data[ $base ]['Version'] : '0.0.0'; @@ -1120,6 +1118,78 @@ private function get_outdated_extensions_via_api() { return $outdated_plugins; } + /** + * Add authorized packages to Directorist extension updates. + * + * The version API can advertise a new version without a license while + * returning an empty package. WordPress treats that response as an + * installable update and fails when the update is requested. Resolve the + * package from the current subscription, or remove the unusable update + * from WordPress's installable update list. The Directorist Extensions + * screen still reports the available version independently. + * + * @since 8.9.5 + * + * @param mixed $updates WordPress plugin update transient. + * @return mixed Filtered plugin update transient. + */ + public function prepare_extension_update_packages( $updates ) { + if ( ! is_object( $updates ) || empty( $updates->response ) || ! is_array( $updates->response ) ) { + return $updates; + } + + if ( empty( self::$extensions_aliases ) ) { + $this->setup_extensions_alias(); + } + + $purchased_extensions = self::get_purchased_extension_list(); + $purchased_extensions = is_array( $purchased_extensions ) ? $purchased_extensions : array(); + + foreach ( static::get_default_extensions() as $plugin_key => $extension ) { + if ( ! is_array( $extension ) ) { + continue; + } + + $plugin_base = isset( $extension['base'] ) ? $extension['base'] : $plugin_key . '/' . $plugin_key . '.php'; + + if ( empty( $updates->response[ $plugin_base ] ) ) { + continue; + } + + $update = $updates->response[ $plugin_base ]; + $package = is_object( $update ) && isset( $update->package ) ? $update->package : ''; + + if ( is_array( $update ) && isset( $update['package'] ) ) { + $package = $update['package']; + } + + if ( ! empty( $package ) ) { + continue; + } + + $plugin_item = self::extract_plugin_from_list( $plugin_key, $purchased_extensions ); + + if ( is_array( $plugin_item ) && empty( $plugin_item['item_id'] ) && ! empty( $extension['item_id'] ) ) { + $plugin_item['item_id'] = absint( $extension['item_id'] ); + } + + $package = self::get_file_download_link( $plugin_item, 'plugin' ); + + if ( empty( $package ) ) { + unset( $updates->response[ $plugin_base ] ); + continue; + } + + if ( is_object( $update ) ) { + $updates->response[ $plugin_base ]->package = esc_url_raw( $package ); + } elseif ( is_array( $update ) ) { + $updates->response[ $plugin_base ]['package'] = esc_url_raw( $package ); + } + } + + return $updates; + } + // extract_plugin_from_list public static function extract_plugin_from_list( $plugin_key = '', $list = [] ) {