Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
34.43% covered (danger)
34.43%
21 / 61
11.11% covered (danger)
11.11%
1 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
Wpcom_Block_Patterns_Utils
34.43% covered (danger)
34.43%
21 / 61
11.11% covered (danger)
11.11%
1 / 9
283.77
0.00% covered (danger)
0.00%
0 / 1
 remote_get
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
12
 remote_get_as_user
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
30
 cache_add
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 cache_get
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 get_patterns_cache_key
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 get_block_patterns_locale
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 maybe_get_pattern_block_types_from_pattern_meta
87.50% covered (warning)
87.50%
7 / 8
0.00% covered (danger)
0.00%
0 / 1
5.05
 get_block_types_from_categories
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
56
 get_pattern_post_types_from_pattern
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
6
1<?php
2/**
3 * Block Patterns Utils.
4 *
5 * @package automattic/jetpack-mu-wpcom
6 */
7
8use Automattic\Jetpack\Connection\Client;
9use Automattic\Jetpack\Jetpack_Mu_Wpcom\Common;
10
11/**
12 * Class Wpcom_Block_Patterns_Utils
13 */
14class Wpcom_Block_Patterns_Utils {
15    /**
16     * Make remote get requests.
17     *
18     * @param string $request_url The request URL.
19     * @return array              The response.
20     */
21    public function remote_get( $request_url ) {
22        $args = array( 'timeout' => 20 );
23
24        if ( function_exists( 'wpcom_json_api_get' ) ) {
25            $response = wpcom_json_api_get( $request_url, $args );
26        } else {
27            $response = wp_remote_get( $request_url, $args );
28        }
29
30        if ( 200 !== wp_remote_retrieve_response_code( $response ) ) {
31            return array();
32        }
33        return json_decode( wp_remote_retrieve_body( $response ), true );
34    }
35
36    /**
37     * Make a GET request to the WordPress.com REST API as the current user.
38     *
39     * On WPCOM Simple sites the request is dispatched in-process via WPCOM_API_Direct so the
40     * current logged-in WP.com user is the authenticated user. Everywhere else we route through
41     * Jetpack's Client::wpcom_json_api_request_as_user, which signs the request with the user's
42     * Jetpack token.
43     *
44     * @param string $path          API path (e.g. `/ptk/patterns/en?site=...`). The full URL is built by the Jetpack Client.
45     * @param string $version       API version. Default `2`.
46     * @param string $base_api_path API root segment, `wpcom` or `rest`. Default `wpcom`.
47     * @return array                Decoded response body, or an empty array on failure.
48     */
49    public function remote_get_as_user( $path, $version = '2', $base_api_path = 'wpcom' ) {
50        $args = array(
51            'method'  => 'GET',
52            'timeout' => 20,
53        );
54
55        if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
56            require_lib( 'wpcom-api-direct' );
57            $validated_args            = Client::validate_args_for_wpcom_json_api_request( $path, $version, $args, $base_api_path );
58            $validated_args['user_id'] = get_current_user_id();
59            $response                  = \WPCOM_API_Direct::do_request( $validated_args );
60        } else {
61            $response = Client::wpcom_json_api_request_as_user( $path, $version, $args, null, $base_api_path );
62        }
63
64        if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) {
65            return array();
66        }
67
68        return json_decode( wp_remote_retrieve_body( $response ), true );
69    }
70
71    /**
72     * A wrapper for wp_cache_add.
73     *
74     * @param  int|string $key    The cache key to use for retrieval later.
75     * @param  mixed      $data   The data to add to the cache.
76     * @param  string     $group  The group to add the cache to. Enables the same key to be used across groups. Default empty.
77     * @param  int        $expire When the cache data should expire, in seconds.
78     *                            Default 0 (no expiration).
79     * @return bool               True on success, false if cache key and group already exist.
80     */
81    public function cache_add( $key, $data, $group, $expire ) {
82        return wp_cache_add( $key, $data, $group, $expire );
83    }
84
85    /**
86     * A wrapper for wp_cache_get.
87     *
88     * @param int|string $key   The key under which the cache contents are stored.
89     * @param string     $group Where the cache contents are grouped. Default empty.
90     * @return mixed|false      The cache contents on success, false on failure to retrieve contents.
91     */
92    public function cache_get( $key, $group ) {
93        return wp_cache_get( $key, $group );
94    }
95
96    /**
97     * Returns a cache key per locale.
98     *
99     * @return string locale slug
100     */
101    public function get_patterns_cache_key() {
102        return 'wpcom_block_patterns_' . $this->get_block_patterns_locale();
103    }
104
105    /**
106     * Get the locale to be used for fetching block patterns
107     *
108     * @return string locale slug
109     */
110    public function get_block_patterns_locale() {
111        // Block patterns display in the user locale.
112        $language = get_user_locale();
113        return Common\get_iso_639_locale( $language );
114    }
115
116    /**
117     * Check for block type values in the pattern_meta tag.
118     * When tags have a prefix of `block_type_`, we expect the remaining suffix to be a blockType value.
119     * We'll add these values to the `(array) blockType` options property when registering the pattern
120     * via `register_block_pattern`.
121     *
122     * @param array $pattern A pattern with a 'pattern_meta' array.
123     *
124     * @return array         An array of block types defined in pattern meta.
125     */
126    public function maybe_get_pattern_block_types_from_pattern_meta( $pattern ) {
127        $block_types = array();
128
129        if ( ! isset( $pattern['pattern_meta'] ) || empty( $pattern['pattern_meta'] ) ) {
130            return $block_types;
131        }
132
133        foreach ( $pattern['pattern_meta'] as $pattern_meta => $value ) {
134            // Match against tags starting with `block_type_`.
135            $split_slug = preg_split( '/^block_type_/', $pattern_meta );
136
137            if ( isset( $split_slug[1] ) ) {
138                $block_types[] = $split_slug[1];
139            }
140        }
141
142        return $block_types;
143    }
144
145    /**
146     * Using the pattern categories, generate the `blockTypes` property for
147     * registering the pattern via `register_block_pattern`.
148     *
149     * @param array $pattern A pattern with categories.
150     *
151     * @return array         An array of block types.
152     */
153    public function get_block_types_from_categories( $pattern ) {
154        $block_types = array();
155
156        if ( ! isset( $pattern['categories'] ) || empty( $pattern['categories'] ) ) {
157            return $block_types;
158        }
159
160        foreach ( $pattern['categories'] as $key => $value ) {
161            switch ( $key ) {
162                case 'header':
163                    $block_types[] = 'core/template-part/header';
164                    break;
165                case 'footer':
166                    $block_types[] = 'core/template-part/footer';
167                    break;
168                case 'posts':
169                    $block_types[] = 'core/query';
170                    break;
171            }
172        }
173
174        return $block_types;
175    }
176
177    /**
178     * Return pattern post types based on the pattern's blockTypes.
179     *
180     * @param array $pattern A pattern array such as is passed to `register_block_pattern`.
181     *
182     * @return array $postTypes An array of post type names such as is passed to `register_block_pattern`.
183     */
184    public function get_pattern_post_types_from_pattern( $pattern ) {
185        $post_types = array_key_exists( 'postTypes', $pattern ) ? $pattern['postTypes'] : array();
186        if ( $post_types ) {
187            // If some postTypes are explicitly set then respect the pattern author's intent.
188            return $post_types;
189        }
190
191        $block_types       = array_key_exists( 'blockTypes', $pattern ) ? $pattern['blockTypes'] : array();
192        $block_types_count = count( $block_types );
193        $template_parts    = array_filter(
194            $block_types,
195            function ( $block_type ) {
196                return preg_match( '#core/template-part/#', $block_type );
197            }
198        );
199        // If all of a patterns blockTypes are template-parts then limit the postTypes to just
200        // the template related types and to pages - this is to avoid the pattern appearing in
201        // the inserter for posts and other post types. Pages are included because it's not unusual
202        // to use a blank template and add a specific header and footer to a page.
203        if ( $block_types_count && count( $template_parts ) === $block_types_count ) {
204            $post_types = array( 'wp_template', 'wp_template_part', 'page' );
205        }
206        return $post_types;
207    }
208}