WordPress Version: 6.5
/**
* Retrieves theme installer pages from the WordPress.org Themes API.
*
* It is possible for a theme to override the Themes API result with three
* filters. Assume this is for themes, which can extend on the Theme Info to
* offer more choices. This is very powerful and must be used with care, when
* overriding the filters.
*
* The first filter, {@see 'themes_api_args'}, is for the args and gives the action
* as the second parameter. The hook for {@see 'themes_api_args'} must ensure that
* an object is returned.
*
* The second filter, {@see 'themes_api'}, allows a plugin to override the WordPress.org
* Theme API entirely. If `$action` is 'query_themes', 'theme_information', or 'feature_list',
* an object MUST be passed. If `$action` is 'hot_tags', an array should be passed.
*
* Finally, the third filter, {@see 'themes_api_result'}, makes it possible to filter the
* response object or array, depending on the `$action` type.
*
* Supported arguments per action:
*
* | Argument Name | 'query_themes' | 'theme_information' | 'hot_tags' | 'feature_list' |
* | -------------------| :------------: | :-----------------: | :--------: | :--------------: |
* | `$slug` | No | Yes | No | No |
* | `$per_page` | Yes | No | No | No |
* | `$page` | Yes | No | No | No |
* | `$number` | No | No | Yes | No |
* | `$search` | Yes | No | No | No |
* | `$tag` | Yes | No | No | No |
* | `$author` | Yes | No | No | No |
* | `$user` | Yes | No | No | No |
* | `$browse` | Yes | No | No | No |
* | `$locale` | Yes | Yes | No | No |
* | `$fields` | Yes | Yes | No | No |
*
* @since 2.8.0
*
* @param string $action API action to perform: Accepts 'query_themes', 'theme_information',
* 'hot_tags' or 'feature_list'.
* @param array|object $args {
* Optional. Array or object of arguments to serialize for the Themes API. Default empty array.
*
* @type string $slug The theme slug. Default empty.
* @type int $per_page Number of themes per page. Default 24.
* @type int $page Number of current page. Default 1.
* @type int $number Number of tags to be queried.
* @type string $search A search term. Default empty.
* @type string $tag Tag to filter themes. Default empty.
* @type string $author Username of an author to filter themes. Default empty.
* @type string $user Username to query for their favorites. Default empty.
* @type string $browse Browse view: 'featured', 'popular', 'updated', 'favorites'.
* @type string $locale Locale to provide context-sensitive results. Default is the value of get_locale().
* @type array $fields {
* Array of fields which should or should not be returned.
*
* @type bool $description Whether to return the theme full description. Default false.
* @type bool $sections Whether to return the theme readme sections: description, installation,
* FAQ, screenshots, other notes, and changelog. Default false.
* @type bool $rating Whether to return the rating in percent and total number of ratings.
* Default false.
* @type bool $ratings Whether to return the number of rating for each star (1-5). Default false.
* @type bool $downloaded Whether to return the download count. Default false.
* @type bool $downloadlink Whether to return the download link for the package. Default false.
* @type bool $last_updated Whether to return the date of the last update. Default false.
* @type bool $tags Whether to return the assigned tags. Default false.
* @type bool $homepage Whether to return the theme homepage link. Default false.
* @type bool $screenshots Whether to return the screenshots. Default false.
* @type int $screenshot_count Number of screenshots to return. Default 1.
* @type bool $screenshot_url Whether to return the URL of the first screenshot. Default false.
* @type bool $photon_screenshots Whether to return the screenshots via Photon. Default false.
* @type bool $template Whether to return the slug of the parent theme. Default false.
* @type bool $parent Whether to return the slug, name and homepage of the parent theme. Default false.
* @type bool $versions Whether to return the list of all available versions. Default false.
* @type bool $theme_url Whether to return theme's URL. Default false.
* @type bool $extended_author Whether to return nicename or nicename and display name. Default false.
* }
* }
* @return object|array|WP_Error Response object or array on success, WP_Error on failure. See the
* {@link https://developer.wordpress.org/reference/functions/themes_api/ function reference article}
* for more information on the make-up of possible return objects depending on the value of `$action`.
*/
function themes_api($action, $args = array())
{
// Include an unmodified $wp_version.
require ABSPATH . WPINC . '/version.php';
if (is_array($args)) {
$args = (object) $args;
}
if ('query_themes' === $action) {
if (!isset($args->per_page)) {
$args->per_page = 24;
}
}
if (!isset($args->locale)) {
$args->locale = get_user_locale();
}
if (!isset($args->wp_version)) {
$args->wp_version = substr($wp_version, 0, 3);
// x.y
}
/**
* Filters arguments used to query for installer pages from the WordPress.org Themes API.
*
* Important: An object MUST be returned to this filter.
*
* @since 2.8.0
*
* @param object $args Arguments used to query for installer pages from the WordPress.org Themes API.
* @param string $action Requested action. Likely values are 'theme_information',
* 'feature_list', or 'query_themes'.
*/
$args = apply_filters('themes_api_args', $args, $action);
/**
* Filters whether to override the WordPress.org Themes API.
*
* Returning a non-false value will effectively short-circuit the WordPress.org API request.
*
* If `$action` is 'query_themes', 'theme_information', or 'feature_list', an object MUST
* be passed. If `$action` is 'hot_tags', an array should be passed.
*
* @since 2.8.0
*
* @param false|object|array $override Whether to override the WordPress.org Themes API. Default false.
* @param string $action Requested action. Likely values are 'theme_information',
* 'feature_list', or 'query_themes'.
* @param object $args Arguments used to query for installer pages from the Themes API.
*/
$res = apply_filters('themes_api', false, $action, $args);
if (!$res) {
$url = 'http://api.wordpress.org/themes/info/1.2/';
$url = add_query_arg(array('action' => $action, 'request' => $args), $url);
$http_url = $url;
$ssl = wp_http_supports(array('ssl'));
if ($ssl) {
$url = set_url_scheme($url, 'https');
}
$http_args = array('timeout' => 15, 'user-agent' => 'WordPress/' . $wp_version . '; ' . home_url('/'));
$request = wp_remote_get($url, $http_args);
if ($ssl && is_wp_error($request)) {
if (!wp_doing_ajax()) {
trigger_error(sprintf(
/* translators: %s: Support forums URL. */
__('An unexpected error occurred. Something may be wrong with WordPress.org or this server’s configuration. If you continue to have problems, please try the <a href="%s">support forums</a>.'),
__('https://wordpress.org/support/forums/')
) . ' ' . __('(WordPress could not establish a secure connection to WordPress.org. Please contact your server administrator.)'), (headers_sent() || WP_DEBUG) ? E_USER_WARNING : E_USER_NOTICE);
}
$request = wp_remote_get($http_url, $http_args);
}
if (is_wp_error($request)) {
$res = new WP_Error('themes_api_failed', sprintf(
/* translators: %s: Support forums URL. */
__('An unexpected error occurred. Something may be wrong with WordPress.org or this server’s configuration. If you continue to have problems, please try the <a href="%s">support forums</a>.'),
__('https://wordpress.org/support/forums/')
), $request->get_error_message());
} else {
$res = json_decode(wp_remote_retrieve_body($request), true);
if (is_array($res)) {
// Object casting is required in order to match the info/1.0 format.
$res = (object) $res;
} elseif (null === $res) {
$res = new WP_Error('themes_api_failed', sprintf(
/* translators: %s: Support forums URL. */
__('An unexpected error occurred. Something may be wrong with WordPress.org or this server’s configuration. If you continue to have problems, please try the <a href="%s">support forums</a>.'),
__('https://wordpress.org/support/forums/')
), wp_remote_retrieve_body($request));
}
if (isset($res->error)) {
$res = new WP_Error('themes_api_failed', $res->error);
}
}
if (!is_wp_error($res)) {
// Back-compat for info/1.2 API, upgrade the theme objects in query_themes to objects.
if ('query_themes' === $action) {
foreach ($res->themes as $i => $theme) {
$res->themes[$i] = (object) $theme;
}
}
// Back-compat for info/1.2 API, downgrade the feature_list result back to an array.
if ('feature_list' === $action) {
$res = (array) $res;
}
}
}
/**
* Filters the returned WordPress.org Themes API response.
*
* @since 2.8.0
*
* @param array|stdClass|WP_Error $res WordPress.org Themes API response.
* @param string $action Requested action. Likely values are 'theme_information',
* 'feature_list', or 'query_themes'.
* @param stdClass $args Arguments used to query for installer pages from the WordPress.org Themes API.
*/
return apply_filters('themes_api_result', $res, $action, $args);
}