Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
68.57% covered (warning)
68.57%
24 / 35
71.43% covered (warning)
71.43%
5 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
WPCom_Themes_Api
68.57% covered (warning)
68.57%
24 / 35
71.43% covered (warning)
71.43%
5 / 7
18.25
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 fetch_themes
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
3
 handle_request
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
3
 fetch_all_non_delisted_themes
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 fetch_theme
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
3
 fetch_recommended_themes
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 search_themes
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2/**
3 * Class WPCom_Themes_Api.
4 * Retrieves themes from the WordPress.com themes API.
5 *
6 * @package automattic/jetpack-mu-wpcom
7 */
8
9/**
10 * Fetches themes from the WordPress.com themes API.
11 */
12class WPCom_Themes_Api {
13
14    /**
15     * The URL of the WordPress.com themes API.
16     */
17    const WP_COM_THEMES_API_URL = 'https://public-api.wordpress.com/wpcom/v2/themes?_envelope=1&page=1&number=1000';
18
19    /**
20     * The URL of the WordPress.com theme API.
21     */
22    const WP_COM_THEME_API_URL = 'https://public-api.wordpress.com/rest/v1.2/themes/%s?http_envelope=1';
23
24    /**
25     * Cache handler.
26     *
27     * @var WPCom_Themes_Cache $cache
28     */
29    private WPCom_Themes_Cache $cache;
30
31    /**
32     * Class constructor.
33     *
34     * @param WPCom_Themes_Cache $cache Cache handler.
35     */
36    public function __construct( WPCom_Themes_Cache $cache ) {
37        $this->cache = $cache;
38    }
39
40    /**
41     * Returns an array of themes fetched from the WordPress.com themes API.
42     * Caching is used to avoid fetching the themes on every request.
43     *
44     * @param string $cache_key Key of the cache where the API response will be cached.
45     * @param array  $params    Query params to pass to the API URL.
46     *
47     * @return array<stdClass> An array with all the WPCom themes.
48     */
49    protected function fetch_themes( string $cache_key, array $params = array() ): array {
50        $url = add_query_arg( $params, self::WP_COM_THEMES_API_URL );
51
52        return $this->cache->run_cached(
53            $cache_key,
54            function () use ( $url ) {
55                $body = $this->handle_request( $url );
56
57                // Null, not an empty array: run_cached() stores anything else.
58                return isset( $body->themes ) && is_array( $body->themes ) ? $body->themes : null;
59            }
60        ) ?? array();
61    }
62
63    /**
64     * Fetches the response from the given URL.
65     *
66     * @param string $url URL to fetch.
67     *
68     * @return ?stdClass Response body.
69     */
70    protected function handle_request( string $url ): ?stdClass {
71        $response = wp_remote_get( esc_url_raw( $url ) );
72        if ( 200 === wp_remote_retrieve_response_code( $response ) ) {
73            $body_json = json_decode( wp_remote_retrieve_body( $response ) );
74
75            if ( isset( $body_json->body ) ) {
76                return $body_json->body;
77            }
78        }
79
80        return null;
81    }
82
83    /**
84     * Returns all the WP.com themes.
85     *
86     * @return array<stdClass> An array with all the WPCom themes.
87     */
88    public function fetch_all_non_delisted_themes(): array {
89        return $this->fetch_themes( 'wpcom-themes-all' );
90    }
91
92    /**
93     * Returns the WP.com theme with the given slug.
94     *
95     * @param string $slug Theme slug.
96     *
97     * @return stdClass|null A WPCom theme object or null if not found.
98     */
99    public function fetch_theme( string $slug ): ?stdClass {
100        $url = sprintf( self::WP_COM_THEME_API_URL, $slug );
101
102        $theme = $this->cache->run_cached(
103            'wpcom-themes-' . $slug,
104            fn() => $this->handle_request( $url )
105        );
106
107        if ( ! $theme || isset( $theme->error ) ) {
108            return null;
109        }
110
111        return $theme;
112    }
113
114    /**
115     * Returns the collection of the recommended WP.com themes.
116     *
117     * @return array<stdClass> An array with all the recommended WPCom themes.
118     */
119    public function fetch_recommended_themes(): array {
120        return $this->fetch_themes(
121            'wpcom-themes-recommended',
122            array( 'collection' => 'recommended' )
123        );
124    }
125
126    /**
127     * Returns the WP.com themes that match the given search term.
128     *
129     * @param string $search Search term.
130     *
131     * @return array<stdClass> An array with all the matching WPCom themes.
132     */
133    public function search_themes( string $search ): array {
134        return $this->fetch_themes(
135            'wpcom-themes-search-' . md5( $search ),
136            array(
137                'search' => $search,
138                'sort'   => 'date',
139            )
140        );
141    }
142}