Make WordPress Core


Ignore:
Timestamp:
08/23/2022 05:46:46 PM (3 years ago)
Author:
SergeyBiryukov
Message:

Themes: Add support for Update URI header.

This allows third-party themes to avoid accidentally being overwritten with an update of a theme of a similar name from the WordPress.org Theme Directory.

Additionally, introduce the update_themes_{$hostname} filter, which third-party themes can use to offer updates for a given hostname.

If set, the Update URI header field should be a URI and have a unique hostname.

Some examples include:

  • https://wordpress.org/themes/example-theme/
  • https://example.com/my-theme/
  • my-custom-theme-name

Update URI: false also works, and unless there is code handling the false hostname, the theme will never get an update notification.

If the header is present, the WordPress.org API will currently only return updates for the theme if it matches the following format:

  • https://wordpress.org/themes/{$slug}/
  • w.org/theme/{$slug}

If the header has any other value, the API will not return a result and will ignore the theme for update purposes.

Follow-up to [50921].

Props dd32, meloniq, costdev, audrasjb, DavidAnderson, markjaquith, DrewAPicture, mweichert, design_dolphin, filosofo, sean212, nhuja, JeroenReumkens, infolu, dingdang, joyously, earnjam, williampatton, grapplerulrich, markparnell, apedog, afragen, miqrogroove, rmccue, crazycoders, jdgrimes, damonganto, joostdevalk, jorbin, georgestephanis, khromov, GeekStreetWP, jb510, Rarst, juliobox, Ipstenu, mikejolley, Otto42, gMagicScott, TJNowell, GaryJ, knutsp, mordauk, nvartolomei, aspexi, chriscct7, benoitchantre, ryno267, lev0, gregorlove, dougwollison, leemon, SergeyBiryukov.
See #14179, #23318, #32101.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/update.php

    r53753 r53933  
    506506         * @param array       $plugin_data      Plugin headers.
    507507         * @param string      $plugin_file      Plugin filename.
    508          * @param array       $locales          Installed locales to look translations for.
     508         * @param array       $locales          Installed locales to look up translations for.
    509509         */
    510510        $update = apply_filters( "update_plugins_{$hostname}", false, $plugin_data, $plugin_file, $locales );
     
    614614            'Author'     => $theme->get( 'Author' ),
    615615            'Author URI' => $theme->get( 'AuthorURI' ),
     616            'UpdateURI'  => $theme->get( 'UpdateURI' ),
    616617            'Template'   => $theme->get_template(),
    617618            'Stylesheet' => $theme->get_stylesheet(),
     
    745746    }
    746747
     748    // Support updates for any themes using the `Update URI` header field.
     749    foreach ( $themes as $theme_stylesheet => $theme_data ) {
     750        if ( ! $theme_data['UpdateURI'] || isset( $new_update->response[ $theme_stylesheet ] ) ) {
     751            continue;
     752        }
     753
     754        $hostname = wp_parse_url( esc_url_raw( $theme_data['UpdateURI'] ), PHP_URL_HOST );
     755
     756        /**
     757         * Filters the update response for a given theme hostname.
     758         *
     759         * The dynamic portion of the hook name, `$hostname`, refers to the hostname
     760         * of the URI specified in the `Update URI` header field.
     761         *
     762         * @since 6.1.0
     763         *
     764         * @param array|false $update {
     765         *     The theme update data with the latest details. Default false.
     766         *
     767         *     @type string $id           Optional. ID of the theme for update purposes, should be a URI
     768         *                                specified in the `Update URI` header field.
     769         *     @type string $theme        Directory name of the theme.
     770         *     @type string $version      The version of the theme.
     771         *     @type string $url          The URL for details of the theme.
     772         *     @type string $package      Optional. The update ZIP for the theme.
     773         *     @type string $tested       Optional. The version of WordPress the theme is tested against.
     774         *     @type string $requires_php Optional. The version of PHP which the theme requires.
     775         *     @type bool   $autoupdate   Optional. Whether the theme should automatically update.
     776         *     @type array  $translations {
     777         *         Optional. List of translation updates for the theme.
     778         *
     779         *         @type string $language   The language the translation update is for.
     780         *         @type string $version    The version of the theme this translation is for.
     781         *                                  This is not the version of the language file.
     782         *         @type string $updated    The update timestamp of the translation file.
     783         *                                  Should be a date in the `YYYY-MM-DD HH:MM:SS` format.
     784         *         @type string $package    The ZIP location containing the translation update.
     785         *         @type string $autoupdate Whether the translation should be automatically installed.
     786         *     }
     787         * }
     788         * @param array       $theme_data       Theme headers.
     789         * @param string      $theme_stylesheet Theme stylesheet.
     790         * @param array       $locales          Installed locales to look up translations for.
     791         */
     792        $update = apply_filters( "update_themes_{$hostname}", false, $theme_data, $theme_stylesheet, $locales );
     793
     794        if ( ! $update ) {
     795            continue;
     796        }
     797
     798        $update = (object) $update;
     799
     800        // Is it valid? We require at least a version.
     801        if ( ! isset( $update->version ) ) {
     802            continue;
     803        }
     804
     805        // This should remain constant.
     806        $update->id = $theme_data['UpdateURI'];
     807
     808        // WordPress needs the version field specified as 'new_version'.
     809        if ( ! isset( $update->new_version ) ) {
     810            $update->new_version = $update->version;
     811        }
     812
     813        // Handle any translation updates.
     814        if ( ! empty( $update->translations ) ) {
     815            foreach ( $update->translations as $translation ) {
     816                if ( isset( $translation['language'], $translation['package'] ) ) {
     817                    $translation['type'] = 'theme';
     818                    $translation['slug'] = isset( $update->theme ) ? $update->theme : $update->id;
     819
     820                    $new_update->translations[] = $translation;
     821                }
     822            }
     823        }
     824
     825        unset( $new_update->no_update[ $theme_stylesheet ], $new_update->response[ $theme_stylesheet ] );
     826
     827        if ( version_compare( $update->new_version, $theme_data['Version'], '>' ) ) {
     828            $new_update->response[ $theme_stylesheet ] = (array) $update;
     829        } else {
     830            $new_update->no_update[ $theme_stylesheet ] = (array) $update;
     831        }
     832    }
     833
    747834    set_site_transient( 'update_themes', $new_update );
    748835}
Note: See TracChangeset for help on using the changeset viewer.