From df6f4fd9de92ea8f25fc8472f97dfb74eab059cf Mon Sep 17 00:00:00 2001 From: costdev <79332690+costdev@users.noreply.github.com> Date: Sat, 4 Oct 2025 04:08:24 +0100 Subject: [PATCH 01/28] Rename `is_fair_plugin()` to `is_fair_package()`. Signed-off-by: costdev <79332690+costdev@users.noreply.github.com> --- inc/packages/admin/namespace.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/inc/packages/admin/namespace.php b/inc/packages/admin/namespace.php index 287bbc06..ac8fb555 100644 --- a/inc/packages/admin/namespace.php +++ b/inc/packages/admin/namespace.php @@ -299,7 +299,7 @@ function set_slug_to_hashed() : void { } /** - * Check if this is a FAIR plugin, for legacy data. + * Check if this is a FAIR package, for legacy data. * * FAIR data is bridged into legacy data via the _fair property, and needs * to have a valid DID. We can use this to enhance our existing metadata. @@ -307,7 +307,7 @@ function set_slug_to_hashed() : void { * @param array|stdClass $api_data Legacy dotorg-formatted data to check. * @return bool */ -function is_fair_plugin( $api_data ) : bool { +function is_fair_package( $api_data ) : bool { $api = (array) $api_data; if ( empty( $api['_fair'] ) ) { return false; @@ -382,7 +382,7 @@ function maybe_hijack_legacy_plugin_info() { } // Is this a FAIR plugin, actually? - if ( ! is_fair_plugin( $api ) ) { + if ( ! is_fair_package( $api ) ) { return; } @@ -472,7 +472,7 @@ function sort_sections_in_api( $res ) { * @return array Altered actions. */ function maybe_hijack_plugin_install_button( $links, $plugin ) { - if ( ! is_fair_plugin( $plugin ) || ! str_contains( $plugin['slug'], '-did--' ) ) { + if ( ! is_fair_package( $plugin ) || ! str_contains( $plugin['slug'], '-did--' ) ) { return $links; } @@ -513,7 +513,7 @@ function maybe_hijack_plugin_install_button( $links, $plugin ) { * @return string Plugin card description. */ function maybe_add_data_to_description( $description, $plugin ) { - if ( ! is_fair_plugin( $plugin ) ) { + if ( ! is_fair_package( $plugin ) ) { return $description; } From a19f617a86980b5e3b88e0c6c0771a980318dc16 Mon Sep 17 00:00:00 2001 From: costdev <79332690+costdev@users.noreply.github.com> Date: Sat, 4 Oct 2025 04:09:06 +0100 Subject: [PATCH 02/28] Organize plugin and theme hooks. Signed-off-by: costdev <79332690+costdev@users.noreply.github.com> --- inc/packages/admin/namespace.php | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/inc/packages/admin/namespace.php b/inc/packages/admin/namespace.php index ac8fb555..06573419 100644 --- a/inc/packages/admin/namespace.php +++ b/inc/packages/admin/namespace.php @@ -25,12 +25,10 @@ function bootstrap() { return; } + // Plugins. add_filter( 'install_plugins_tabs', __NAMESPACE__ . '\\add_direct_tab' ); add_filter( 'plugins_api', __NAMESPACE__ . '\\handle_did_during_ajax', 10, 3 ); add_filter( 'plugins_api', 'FAIR\\Packages\\search_by_did', 10, 3 ); - add_filter( 'upgrader_package_options', 'FAIR\\Packages\\cache_did_for_install', 10, 1 ); - add_action( 'upgrader_post_install', 'FAIR\\Packages\\delete_cached_did_for_install', 10, 3 ); - add_filter( 'upgrader_pre_download', 'FAIR\\Packages\\upgrader_pre_download', 10, 1 ); add_action( 'install_plugins_' . TAB_DIRECT, __NAMESPACE__ . '\\render_tab_direct' ); add_action( 'load-plugin-install.php', __NAMESPACE__ . '\\load_plugin_install' ); add_action( 'install_plugins_pre_plugin-information', __NAMESPACE__ . '\\maybe_hijack_plugin_info', 0 ); @@ -41,6 +39,15 @@ function bootstrap() { add_action( 'wp_ajax_check_plugin_dependencies', __NAMESPACE__ . '\\set_slug_to_hashed' ); add_filter( 'wp_list_table_class_name', __NAMESPACE__ . '\\maybe_override_list_table' ); + // Themes. + add_filter( 'themes_api', __NAMESPACE__ . '\\handle_did_during_ajax', 10, 3 ); + add_filter( 'themes_api', 'FAIR\\Packages\\search_by_did', 10, 3 ); + + // Common. + add_filter( 'upgrader_package_options', 'FAIR\\Packages\\cache_did_for_install', 10, 1 ); + add_action( 'upgrader_post_install', 'FAIR\\Packages\\delete_cached_did_for_install', 10, 3 ); + add_filter( 'upgrader_pre_download', 'FAIR\\Packages\\upgrader_pre_download', 10, 1 ); + // Needed for pre WordPress 6.9 compatibility. if ( ! is_wp_version_compatible( '6.9' ) ) { add_action( 'install_plugins_featured', __NAMESPACE__ . '\\replace_featured_message' ); From e5c2a2ec60124f79d56fb76c5f6ce581573f0157 Mon Sep 17 00:00:00 2001 From: costdev <79332690+costdev@users.noreply.github.com> Date: Sat, 4 Oct 2025 04:09:43 +0100 Subject: [PATCH 03/28] Add AJAX DID support. Signed-off-by: costdev <79332690+costdev@users.noreply.github.com> --- inc/packages/admin/namespace.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/inc/packages/admin/namespace.php b/inc/packages/admin/namespace.php index 06573419..3aa97437 100644 --- a/inc/packages/admin/namespace.php +++ b/inc/packages/admin/namespace.php @@ -111,13 +111,13 @@ function replace_featured_message() { /** * Handles the AJAX request for plugin information when a DID is present. * - * @param mixed $result The result of the plugins_api call. + * @param mixed $result The result of the API call. * @param string $action The action being performed. - * @param object $args The arguments passed to the plugins_api call. + * @param object $args The arguments passed to the API call. * @return mixed */ function handle_did_during_ajax( $result, $action, $args ) { - if ( ! wp_doing_ajax() || 'plugin_information' !== $action || ! isset( $args->slug ) ) { + if ( ! wp_doing_ajax() || ! isset( $args->slug ) || ( 'plugin_information' !== $action && 'theme_information' !== $action ) ) { return $result; } From 7caee11a1784e7e47bb7cb44b8fb4f359f553959 Mon Sep 17 00:00:00 2001 From: costdev <79332690+costdev@users.noreply.github.com> Date: Sat, 4 Oct 2025 04:10:55 +0100 Subject: [PATCH 04/28] Add "Search by DID" support. Signed-off-by: costdev <79332690+costdev@users.noreply.github.com> --- inc/packages/namespace.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/inc/packages/namespace.php b/inc/packages/namespace.php index 9733ae4f..9de07e76 100644 --- a/inc/packages/namespace.php +++ b/inc/packages/namespace.php @@ -1020,13 +1020,13 @@ function fetch_and_validate_package_alias( DIDDocument $did ) { /** * Enable searching by DID. * - * @param mixed $result The result of the plugins_api call. + * @param mixed $result The result of the API call. * @param string $action The action being performed. - * @param stdClass $args The arguments passed to the plugins_api call. + * @param stdClass $args The arguments passed to the API call. * @return mixed The search result for the DID. */ function search_by_did( $result, $action, $args ) { - if ( 'query_plugins' !== $action || empty( $args->search ) ) { + if ( empty( $args->search ) || ( 'query_plugins' !== $action && 'query_themes' !== $action ) ) { return $result; } @@ -1041,8 +1041,9 @@ function search_by_did( $result, $action, $args ) { return $result; } + $type = explode( '_', $action )[1]; $result = [ - 'plugins' => [ $api_data ], + $type => [ $type === 'plugin' ? $api_data : (object) $api_data ], 'info' => [ 'page' => 1, 'pages' => 1, From 00cea1130b93f2db8addae3ff8fdd98dbb981374 Mon Sep 17 00:00:00 2001 From: costdev <79332690+costdev@users.noreply.github.com> Date: Sat, 4 Oct 2025 04:12:18 +0100 Subject: [PATCH 05/28] Alter slugs for theme cards too. Signed-off-by: costdev <79332690+costdev@users.noreply.github.com> --- inc/packages/admin/namespace.php | 49 +++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/inc/packages/admin/namespace.php b/inc/packages/admin/namespace.php index 3aa97437..574ba6c0 100644 --- a/inc/packages/admin/namespace.php +++ b/inc/packages/admin/namespace.php @@ -42,6 +42,7 @@ function bootstrap() { // Themes. add_filter( 'themes_api', __NAMESPACE__ . '\\handle_did_during_ajax', 10, 3 ); add_filter( 'themes_api', 'FAIR\\Packages\\search_by_did', 10, 3 ); + add_filter( 'themes_api_result', __NAMESPACE__ . '\\alter_slugs', 10, 3 ); // Common. add_filter( 'upgrader_package_options', 'FAIR\\Packages\\cache_did_for_install', 10, 1 ); @@ -408,30 +409,58 @@ function maybe_hijack_legacy_plugin_info() { } /** - * Filters the Plugin Installation API response results. + * Filters the Installation API response results. * * @param object|WP_Error $res Response object or WP_Error. - * @param string $action The type of information being requested from the Plugin Installation API. - * @param object $args Plugin API arguments. - * @return object|WP_Error + * @param string $action The type of information being requested from the Installation API. + * @param object $args API arguments. */ function handle_did_in_search_results( $res, $action, $args ) { - if ( 'query_plugins' !== $action ) { + if ( 'query_plugins' !== $action && 'query_themes' !== $action ) { return $res; } - if ( empty( $res->plugins ) ) { + $type = explode( '_', $action )[1]; + + if ( + ( $type === 'plugin' && empty( $res->plugins ) ) + || ( $type === 'theme' && empty( $res->themes ) ) + ) { return $res; } +<<<<<<< HEAD // Alter the slugs to our globally unique version and populate release cache. - foreach ( $res->plugins as &$plugin ) { - if ( ! is_fair_plugin( $plugin ) ) { + $items = $type === 'plugin' ? $res->plugins : $res->themes; + + // Alter the slugs to our globally unique version. + foreach ( $items as &$item ) { + if ( ! is_fair_package( $item ) ) { continue; } - $did = $plugin['_fair']['id']; - $plugin['slug'] = esc_attr( $plugin['slug'] . '-' . str_replace( ':', '--', $did ) ); + if ( $type === 'plugin' ) { + $did = $item['_fair']['id']; + $item['slug'] = esc_attr( $item['slug'] . '-' . str_replace( ':', '--', $did ) ); + } else { + // Installed themes need to have the slug-didhash format + // so their activation status can be determined. + $did_hash = Packages\get_did_hash( $item->_fair['id'] ); + $slug = $item->slug; + if ( ! str_ends_with( $slug, '-' . $did_hash ) ) { + $slug = $item->slug . '-' . $did_hash; + } + $theme = wp_get_theme( $slug ); + if ( $theme->exists() ) { + $item->slug = esc_attr( $slug ); + continue; + } + + // Themes that aren't installed need the slug--escaped-did format + // so their metadata can be retrieved. + $did = $item->_fair['id']; + $item->slug = esc_attr( $item->slug . '-' . str_replace( ':', '--', $did ) ); + } Packages\add_package_to_release_cache( $did ); } From 8613628c0568f648e9d7868e1a29c3a8366b54f3 Mon Sep 17 00:00:00 2001 From: costdev <79332690+costdev@users.noreply.github.com> Date: Sat, 4 Oct 2025 04:16:20 +0100 Subject: [PATCH 06/28] After an AJAX installation, use the theme's installed slug for AJAX activation. Signed-off-by: costdev <79332690+costdev@users.noreply.github.com> --- inc/packages/admin/namespace.php | 41 ++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/inc/packages/admin/namespace.php b/inc/packages/admin/namespace.php index 574ba6c0..0ec0c92d 100644 --- a/inc/packages/admin/namespace.php +++ b/inc/packages/admin/namespace.php @@ -43,6 +43,7 @@ function bootstrap() { add_filter( 'themes_api', __NAMESPACE__ . '\\handle_did_during_ajax', 10, 3 ); add_filter( 'themes_api', 'FAIR\\Packages\\search_by_did', 10, 3 ); add_filter( 'themes_api_result', __NAMESPACE__ . '\\alter_slugs', 10, 3 ); + add_action( 'load-themes.php', __NAMESPACE__ . '\\set_stylesheet_to_hashed_on_theme_activation' ); // Common. add_filter( 'upgrader_package_options', 'FAIR\\Packages\\cache_did_for_install', 10, 1 ); @@ -306,6 +307,46 @@ function set_slug_to_hashed() : void { $_POST['slug'] = explode( '-did--', $escaped_slug, 2 )[0] . '-' . Packages\get_did_hash( $did ); } +/** + * Set the stylesheet to the hashed version on theme activation. + * + * After installing a theme via AJAX, the activation button's link + * includes the escaped DID, not the hash of the DID. + * + * The stylesheet parameter needs to be in the slug-didhash format + * so that the theme can be found. + * + * The nonce also needs to be regenerated as the action includes + * the stylesheet. + * + * @return void + */ +function set_stylesheet_to_hashed_on_theme_activation() { + // phpcs:ignore HM.PHP.Isset.MultipleArguments + if ( ! isset( $_GET['action'], $_GET['stylesheet'] ) || $_GET['action'] !== 'activate' ) { + return; + } + + $stylesheet = sanitize_text_field( wp_unslash( $_GET['stylesheet'] ) ); + check_admin_referer( 'switch-theme_' . $stylesheet ); + + if ( ! str_contains( $stylesheet, '-did--' ) ) { + return; + } + + $did = 'did:' . explode( '-did:', str_replace( '--', ':', $stylesheet ), 2 )[1]; + if ( ! preg_match( '/^did:plc:.+$/', $did ) ) { + return; + } + + $hashed_stylesheet = explode( '-did--', $stylesheet, 2 )[0] . '-' . Packages\get_did_hash( $did ); + $_GET['stylesheet'] = $hashed_stylesheet; + $_REQUEST['stylesheet'] = $hashed_stylesheet; + $new_nonce = wp_create_nonce( 'switch-theme_' . $hashed_stylesheet ); + $_GET['_wpnonce'] = $new_nonce; + $_REQUEST['_wpnonce'] = $new_nonce; +} + /** * Check if this is a FAIR package, for legacy data. * From 08bba9ce860df7e93d39374bba56bd235925c36d Mon Sep 17 00:00:00 2001 From: costdev <79332690+costdev@users.noreply.github.com> Date: Sat, 4 Oct 2025 04:17:07 +0100 Subject: [PATCH 07/28] Handle differences in plugin/theme author shape in update data. Signed-off-by: costdev <79332690+costdev@users.noreply.github.com> --- inc/packages/namespace.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/inc/packages/namespace.php b/inc/packages/namespace.php index 9de07e76..1c21ee33 100644 --- a/inc/packages/namespace.php +++ b/inc/packages/namespace.php @@ -665,8 +665,6 @@ function get_package_data( $did ) { $response = [ 'name' => $metadata->name, - 'author' => $metadata->authors[0]->name, - 'author_uri' => $metadata->authors[0]->url, 'slug' => $metadata->slug, 'slug_didhash' => $metadata->slug . '-' . get_did_hash( $did ), $type => $filename, @@ -695,6 +693,12 @@ function get_package_data( $did ) { ]; if ( 'theme' === $type ) { $response['theme_uri'] = $response['url']; + $response['author'] = [ + 'display_name' => $metadata->authors[0]->name, + ]; + } else { + $response['author'] = $metadata->authors[0]->name; + $response['author_uri'] = $metadata->authors[0]->url; } return $response; From 5c6ceedee31d325b04a7ee2164a7862947229650 Mon Sep 17 00:00:00 2001 From: costdev <79332690+costdev@users.noreply.github.com> Date: Sat, 4 Oct 2025 04:17:23 +0100 Subject: [PATCH 08/28] Add `preview_url` to a theme's update data. Signed-off-by: costdev <79332690+costdev@users.noreply.github.com> --- inc/packages/namespace.php | 1 + 1 file changed, 1 insertion(+) diff --git a/inc/packages/namespace.php b/inc/packages/namespace.php index 1c21ee33..4166c30a 100644 --- a/inc/packages/namespace.php +++ b/inc/packages/namespace.php @@ -693,6 +693,7 @@ function get_package_data( $did ) { ]; if ( 'theme' === $type ) { $response['theme_uri'] = $response['url']; + $response['preview_url'] = $metadata->url ?? ''; $response['author'] = [ 'display_name' => $metadata->authors[0]->name, ]; From 9c384582b09b12051ead71164138d8764ebbb84b Mon Sep 17 00:00:00 2001 From: costdev <79332690+costdev@users.noreply.github.com> Date: Sat, 4 Oct 2025 04:19:38 +0100 Subject: [PATCH 09/28] Set the theme's slug to `slug-didhash` when preparing it for JS. Signed-off-by: costdev <79332690+costdev@users.noreply.github.com> --- inc/updater/class-updater.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/inc/updater/class-updater.php b/inc/updater/class-updater.php index aa6f415b..d640f1e6 100644 --- a/inc/updater/class-updater.php +++ b/inc/updater/class-updater.php @@ -271,6 +271,11 @@ public function customize_theme_update_html( $prepared_themes ) { return $prepared_themes; } + $did_hash = Packages\get_did_hash( $this->did ); + if ( ! str_ends_with( $theme->slug, '-' . $did_hash ) ) { + $theme->slug = $theme->slug . '-' . $did_hash; + } + if ( ! empty( $prepared_themes[ $theme->slug ]['hasUpdate'] ) ) { $prepared_themes[ $theme->slug ]['update'] = $this->append_theme_actions_content( $theme ); } else { From 272b915b7ce6de25e03711d07828b8bed040e502 Mon Sep 17 00:00:00 2001 From: costdev <79332690+costdev@users.noreply.github.com> Date: Sat, 4 Oct 2025 05:05:01 +0100 Subject: [PATCH 10/28] If available, add the hostname to the theme's description. Signed-off-by: costdev <79332690+costdev@users.noreply.github.com> --- inc/packages/admin/namespace.php | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/inc/packages/admin/namespace.php b/inc/packages/admin/namespace.php index 0ec0c92d..5c2f3900 100644 --- a/inc/packages/admin/namespace.php +++ b/inc/packages/admin/namespace.php @@ -44,6 +44,7 @@ function bootstrap() { add_filter( 'themes_api', 'FAIR\\Packages\\search_by_did', 10, 3 ); add_filter( 'themes_api_result', __NAMESPACE__ . '\\alter_slugs', 10, 3 ); add_action( 'load-themes.php', __NAMESPACE__ . '\\set_stylesheet_to_hashed_on_theme_activation' ); + add_filter( 'wp_prepare_themes_for_js', __NAMESPACE__ . '\\maybe_add_data_to_theme_description', 10, 1 ); // Common. add_filter( 'upgrader_package_options', 'FAIR\\Packages\\cache_did_for_install', 10, 1 ); @@ -604,3 +605,33 @@ function maybe_add_data_to_description( $description, $plugin ) { $description .= '
' . $additional_description; + } else { + $theme['description'] .= $additional_description . ''; + } + } + unset( $theme ); + return $themes; +} From 8572a63edf9dbbe752e31a929342911ab639a993 Mon Sep 17 00:00:00 2001 From: costdev <79332690+costdev@users.noreply.github.com> Date: Sat, 4 Oct 2025 06:29:38 +0100 Subject: [PATCH 11/28] Support the "Live Preview" link immediately after installation. Signed-off-by: costdev <79332690+costdev@users.noreply.github.com> --- inc/packages/admin/namespace.php | 39 ++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/inc/packages/admin/namespace.php b/inc/packages/admin/namespace.php index 5c2f3900..4c6ae508 100644 --- a/inc/packages/admin/namespace.php +++ b/inc/packages/admin/namespace.php @@ -44,6 +44,7 @@ function bootstrap() { add_filter( 'themes_api', 'FAIR\\Packages\\search_by_did', 10, 3 ); add_filter( 'themes_api_result', __NAMESPACE__ . '\\alter_slugs', 10, 3 ); add_action( 'load-themes.php', __NAMESPACE__ . '\\set_stylesheet_to_hashed_on_theme_activation' ); + add_action( 'plugins_loaded', __NAMESPACE__ . '\\set_theme_to_hashed_for_customize', 9 ); add_filter( 'wp_prepare_themes_for_js', __NAMESPACE__ . '\\maybe_add_data_to_theme_description', 10, 1 ); // Common. @@ -348,6 +349,44 @@ function set_stylesheet_to_hashed_on_theme_activation() { $_REQUEST['_wpnonce'] = $new_nonce; } +/** + * Set the theme to the hashed version in the customizer. + * + * Immediately after installation, the "Live Preview" button + * includes the escaped DID, not the hash of the DID. + * + * The theme parameter needs to be in the slug-didhash format + * so that the theme can be found. + * + * @return void + */ +function set_theme_to_hashed_for_customize() { + // phpcs:ignore HM.PHP.Isset.MultipleArguments + if ( ! isset( $_GET['theme'] ) || ! isset( $_GET['return'] ) ) { + return; + } + + $request_uri = wp_unslash( $_SERVER['REQUEST_URI'] ); + if ( ! str_contains( $request_uri, 'customize.php' ) ) { + return; + } + + + $theme = sanitize_text_field( wp_unslash( $_GET['theme'] ) ); + if ( ! str_contains( $theme, '-did--' ) ) { + return; + } + + $did = 'did:' . explode( '-did:', str_replace( '--', ':', $theme ), 2 )[1]; + if ( ! preg_match( '/^did:plc:.+$/', $did ) ) { + return; + } + + $hashed_theme = explode( '-did--', $theme, 2 )[0] . '-' . Packages\get_did_hash( $did ); + $_GET['theme'] = $hashed_theme; + $_REQUEST['theme'] = $hashed_theme; +} + /** * Check if this is a FAIR package, for legacy data. * From fff6a88a13e4b35757f4c2cbd6c34fa70cd14f48 Mon Sep 17 00:00:00 2001 From: costdev <79332690+costdev@users.noreply.github.com> Date: Sat, 4 Oct 2025 06:41:21 +0100 Subject: [PATCH 12/28] Swap from hooking `plugins_loaded` to hooking `clean_url` instead. Signed-off-by: costdev <79332690+costdev@users.noreply.github.com> --- inc/packages/admin/namespace.php | 34 +++++++++++--------------------- 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/inc/packages/admin/namespace.php b/inc/packages/admin/namespace.php index 4c6ae508..b68c8fa1 100644 --- a/inc/packages/admin/namespace.php +++ b/inc/packages/admin/namespace.php @@ -44,7 +44,7 @@ function bootstrap() { add_filter( 'themes_api', 'FAIR\\Packages\\search_by_did', 10, 3 ); add_filter( 'themes_api_result', __NAMESPACE__ . '\\alter_slugs', 10, 3 ); add_action( 'load-themes.php', __NAMESPACE__ . '\\set_stylesheet_to_hashed_on_theme_activation' ); - add_action( 'plugins_loaded', __NAMESPACE__ . '\\set_theme_to_hashed_for_customize', 9 ); + add_filter( 'clean_url', __NAMESPACE__ . '\\set_theme_to_hashed_for_customize', 10, 3 ); add_filter( 'wp_prepare_themes_for_js', __NAMESPACE__ . '\\maybe_add_data_to_theme_description', 10, 1 ); // Common. @@ -360,31 +360,21 @@ function set_stylesheet_to_hashed_on_theme_activation() { * * @return void */ -function set_theme_to_hashed_for_customize() { - // phpcs:ignore HM.PHP.Isset.MultipleArguments - if ( ! isset( $_GET['theme'] ) || ! isset( $_GET['return'] ) ) { - return; - } - - $request_uri = wp_unslash( $_SERVER['REQUEST_URI'] ); - if ( ! str_contains( $request_uri, 'customize.php' ) ) { - return; - } +function set_theme_to_hashed_for_customize( $url ) { + if ( str_contains( $url, 'customize.php?theme=' ) ) { + $theme = explode( 'theme=', $url )[1]; + if ( str_contains( $theme, '-did--' ) ) { + $did = 'did:' . explode( '-did:', str_replace( '--', ':', $theme ), 2 )[1]; - $theme = sanitize_text_field( wp_unslash( $_GET['theme'] ) ); - if ( ! str_contains( $theme, '-did--' ) ) { - return; - } - - $did = 'did:' . explode( '-did:', str_replace( '--', ':', $theme ), 2 )[1]; - if ( ! preg_match( '/^did:plc:.+$/', $did ) ) { - return; + if ( preg_match( '/^did:plc:.+$/', $did ) ) { + $hashed_theme = explode( '-did--', $theme, 2 )[0] . '-' . Packages\get_did_hash( $did ); + $url = str_replace( $theme, $hashed_theme, $url ); + } + } } - $hashed_theme = explode( '-did--', $theme, 2 )[0] . '-' . Packages\get_did_hash( $did ); - $_GET['theme'] = $hashed_theme; - $_REQUEST['theme'] = $hashed_theme; + return $url; } /** From 2064dbe315bcbc0ba6dbca3c9346be342749ee1a Mon Sep 17 00:00:00 2001 From: costdev <79332690+costdev@users.noreply.github.com> Date: Sat, 4 Oct 2025 06:43:13 +0100 Subject: [PATCH 13/28] Fix the docblock for `set_theme_to_hashed_for_customize()`. Signed-off-by: costdev <79332690+costdev@users.noreply.github.com> --- inc/packages/admin/namespace.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/inc/packages/admin/namespace.php b/inc/packages/admin/namespace.php index b68c8fa1..f240eb5f 100644 --- a/inc/packages/admin/namespace.php +++ b/inc/packages/admin/namespace.php @@ -358,7 +358,8 @@ function set_stylesheet_to_hashed_on_theme_activation() { * The theme parameter needs to be in the slug-didhash format * so that the theme can be found. * - * @return void + * @param string $url The URL to filter. + * @return string */ function set_theme_to_hashed_for_customize( $url ) { if ( str_contains( $url, 'customize.php?theme=' ) ) { From 94b6deafa27bfd8ddd31b51e2a908adde049c5ea Mon Sep 17 00:00:00 2001 From: costdev <79332690+costdev@users.noreply.github.com> Date: Sat, 4 Oct 2025 20:37:36 +0100 Subject: [PATCH 14/28] Add a space before the `return` statement. Signed-off-by: costdev <79332690+costdev@users.noreply.github.com> --- inc/packages/admin/namespace.php | 1 + 1 file changed, 1 insertion(+) diff --git a/inc/packages/admin/namespace.php b/inc/packages/admin/namespace.php index f240eb5f..d24f28a2 100644 --- a/inc/packages/admin/namespace.php +++ b/inc/packages/admin/namespace.php @@ -663,5 +663,6 @@ function maybe_add_data_to_theme_description( $themes ) { } } unset( $theme ); + return $themes; } From 7e153dc62b5b5a7fb9512e7790153ee0eb077cbd Mon Sep 17 00:00:00 2001 From: costdev <79332690+costdev@users.noreply.github.com> Date: Fri, 7 Nov 2025 17:17:56 +0000 Subject: [PATCH 15/28] Use plurals for the type checks. Signed-off-by: costdev <79332690+costdev@users.noreply.github.com> --- inc/packages/admin/namespace.php | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/inc/packages/admin/namespace.php b/inc/packages/admin/namespace.php index d24f28a2..a6c2e7ee 100644 --- a/inc/packages/admin/namespace.php +++ b/inc/packages/admin/namespace.php @@ -495,23 +495,20 @@ function handle_did_in_search_results( $res, $action, $args ) { $type = explode( '_', $action )[1]; if ( - ( $type === 'plugin' && empty( $res->plugins ) ) - || ( $type === 'theme' && empty( $res->themes ) ) + ( $type === 'plugins' && empty( $res->plugins ) ) + || ( $type === 'themes' && empty( $res->themes ) ) ) { return $res; } -<<<<<<< HEAD // Alter the slugs to our globally unique version and populate release cache. - $items = $type === 'plugin' ? $res->plugins : $res->themes; - - // Alter the slugs to our globally unique version. + $items = $type === 'plugins' ? $res->plugins : $res->themes; foreach ( $items as &$item ) { if ( ! is_fair_package( $item ) ) { continue; } - if ( $type === 'plugin' ) { + if ( $type === 'plugins' ) { $did = $item['_fair']['id']; $item['slug'] = esc_attr( $item['slug'] . '-' . str_replace( ':', '--', $did ) ); } else { From 21c73116378a94d992a73c82addd5aa0b6b59256 Mon Sep 17 00:00:00 2001 From: costdev <79332690+costdev@users.noreply.github.com> Date: Fri, 7 Nov 2025 17:20:19 +0000 Subject: [PATCH 16/28] Don't use plurals for the type checks. Signed-off-by: costdev <79332690+costdev@users.noreply.github.com> --- inc/packages/admin/namespace.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/inc/packages/admin/namespace.php b/inc/packages/admin/namespace.php index a6c2e7ee..91e68b9b 100644 --- a/inc/packages/admin/namespace.php +++ b/inc/packages/admin/namespace.php @@ -492,23 +492,23 @@ function handle_did_in_search_results( $res, $action, $args ) { return $res; } - $type = explode( '_', $action )[1]; + $type = rtrim( explode( '_', $action )[1], 's' ); if ( - ( $type === 'plugins' && empty( $res->plugins ) ) - || ( $type === 'themes' && empty( $res->themes ) ) + ( $type === 'plugin' && empty( $res->plugins ) ) + || ( $type === 'theme' && empty( $res->themes ) ) ) { return $res; } // Alter the slugs to our globally unique version and populate release cache. - $items = $type === 'plugins' ? $res->plugins : $res->themes; + $items = $type === 'plugin' ? $res->plugins : $res->themes; foreach ( $items as &$item ) { if ( ! is_fair_package( $item ) ) { continue; } - if ( $type === 'plugins' ) { + if ( $type === 'plugin' ) { $did = $item['_fair']['id']; $item['slug'] = esc_attr( $item['slug'] . '-' . str_replace( ':', '--', $did ) ); } else { From 7f1b875a823d8e447d9b99efa26cf3c4f0567dc9 Mon Sep 17 00:00:00 2001 From: Andy Fragen