PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 12.0.3
Jetpack – WP Security, Backup, Speed, & Growth v12.0.3
12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 13.8.3 13.9.2 14.0.1 14.1.1 14.2.2 14.3.1 14.4.2 14.5.1 14.6.1 14.7.1 14.8.1 14.9.2 15.0.3 15.1.2 15.2.1 15.3.2 15.4.1 15.5.1 15.6.1 15.7.2 15.8.1 15.9.2 16.0.2 16.1.3 16.2-a.5 16.2-a.3 16.1.2 16.2-a.1 16.1.1 16.1 16.1-beta 16.1-beta.2 16.1-beta.3 16.1-a.5 16.1-a.3 16.0.1 16.1-a.1 16.0 16.0-beta 16.0-a.7 16.0-a.5 15.9.1 16.0-a.3 16.0-a.1 15.9 15.9-beta 15.9-a.7 15.9-a.5 15.9-a.3 15.9-a.1 15.8 15.8-beta 15.8-a.7 15.8-a.5 5.2.5 5.3.4 5.4.4 5.5.5 5.6.5 5.7.5 5.8.4 5.9.4 6.0.4 6.1 6.1.1 6.1.2 6.1.3 6.1.4 6.1.5 6.2 6.2.1 6.2.2 6.2.3 6.2.4 6.2.5 6.3 6.3.1 6.3.2 6.3.3 6.3.4 6.3.5 6.3.6 6.3.7 6.4 6.4.1 6.4.2 6.4.3 6.4.4 6.4.5 6.4.6 6.5 6.5.1 6.5.2 6.5.3 6.5.4 6.6 6.6.1 6.6.2 6.6.3 6.6.4 6.6.5 6.7 6.7.1 6.7.2 6.7.3 6.7.4 6.8 6.8.1 6.8.2 6.8.3 6.8.4 6.8.5 6.9 6.9.1 6.9.2 6.9.3 6.9.4 7.0 7.0.1 7.0.2 7.0.3 7.0.4 7.0.5 7.1 7.1.1 7.1.2 7.1.3 7.1.4 7.1.5 7.2 7.2.1 7.2.1.1 7.2.2 7.2.3 7.2.4 7.2.5 7.3 7.3.0.1 7.3.1 7.3.1.1 7.3.2 7.3.3 7.3.4 7.3.5 7.4 7.4.1 7.4.2 7.4.3 7.4.4 7.4.5 7.5 7.5.0.1 7.5.1 7.5.2 7.5.3 7.5.4 7.5.5 7.5.6 7.5.7 7.6 7.6.1 7.6.2 7.6.3 7.6.4 7.7 7.7.1 7.7.2 7.7.3 7.7.4 7.7.5 7.7.6 7.8 7.8.1 7.8.2 7.8.3 7.8.4 7.9 7.9.1 7.9.2 7.9.3 7.9.4 8.0 8.0.1 8.0.2 8.0.3 8.1 8.1.1 8.1.2 8.1.3 8.1.4 8.2 8.2.0.1 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.2.6 8.3 8.3.1 8.3.2 8.3.3 8.4 8.4.1 8.4.2 8.4.3 8.4.4 8.4.5 8.5 8.5.1 8.5.2 8.5.3 8.6 8.6.1 8.6.2 8.6.3 8.6.4 8.7 8.7.0.1 8.7.1 8.7.2 8.7.3 8.7.4 8.8 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.9 8.9.1 8.9.2 8.9.3 8.9.4 9.0 9.0.1 9.0.2 9.0.3 9.0.4 9.0.5 9.1 9.1.1 9.1.2 9.1.3 9.2 9.2.1 9.2.2 9.2.3 9.2.4 9.3 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.4 9.4.1 9.4.2 9.4.3 9.4.4 9.5 9.5.1 9.5.2 9.5.3 9.5.4 9.5.5 9.6 9.6.1 9.6.2 9.6.3 9.6.4 9.7 9.7.1 9.7.2 15.7-beta.2 9.7.3 15.7.1 9.8 15.8-a.1 9.8.1 15.8-a.3 9.8.2 2.0.9 9.8.3 2.1.7 9.9 2.2.10 9.9.1 2.3.10 9.9.2 2.4.7 9.9.3 2.5.5 2.6.6 2.7.5 2.8.5 2.9.6 3.0.6 3.1.5 3.2.5 3.3.6 3.4.6 3.5.6 3.6.4 3.7.5 3.8.5 3.9.10 4.0.7 4.1.4 4.2.5 4.3.5 4.4.5 4.5.3 4.6.3 4.7.4 4.8.5 4.9.3 5.0.3 5.1.4 trunk 10.0 10.0.1 10.0.2 10.1 10.1.1 10.1.2 10.2 10.2.1 10.2.2 10.2.3 10.3 10.3.1 10.3.2 10.4 10.4.1 10.4.2 10.5 10.5.1 10.5.2 10.5.3 10.6 10.6.1 10.6.2 10.7 10.7.1 10.7.2 10.8 10.8.1 10.8.2 10.9 10.9.1 10.9.2 10.9.3 11.0 11.0.1 11.0.2 11.1 11.1.1 11.1.2 11.1.3 11.1.4 11.2 11.2.1 11.2.2 11.3 11.3.1 11.3.2 11.3.3 11.3.4 11.4 11.4.1 11.4.2 11.5 11.5.1 11.5.2 11.5.3 11.6 11.6.1 11.6.2 11.7 11.7.1 11.7.2 11.7.3 11.8 11.8.3 11.8.4 11.8.5 11.8.6 11.9 11.9.1 11.9.2 11.9.3 12.0 12.0.1 12.0.2 12.1 12.1.1 12.1.2 12.2 12.2.1 12.2.2 12.3 12.3.1 12.4 12.4.1 12.5 12.5.1 12.6 12.6.1 12.6.2 12.6.3 12.7 12.7.1 12.7.2 12.8 12.8.1 12.8.2 12.9 12.9.1 12.9.2 12.9.3 12.9.4 13.0 13.0.1 13.1 13.1.1 13.1.2 13.1.3 13.1.4 13.2 13.2.1 13.2.2 13.2.3 13.3 13.3.1 13.3.2 13.4 13.4.1 13.4.2 13.4.3 13.4.4 13.5 13.5.1 13.6 13.6.1 13.7 13.7.1 13.8 13.8.1 13.8.2 13.9 13.9.1 14.0 14.1 14.2 14.2.1 14.3 14.4 14.4.1 14.5 14.6 14.7 14.8 14.9 14.9.1 15.0 15.0.1 15.0.2 15.1 15.1.1 15.2 15.3 15.3.1 15.4 15.5 15.6 15.7 15.7-a.1 15.7-a.3 15.7-a.5 15.7-a.7 15.7-beta
jetpack / json-endpoints / class.wpcom-json-api-get-site-endpoint.php
jetpack / json-endpoints Last commit date
jetpack 3 years ago class.wpcom-json-api-add-widget-endpoint.php 3 years ago class.wpcom-json-api-autosave-post-v1-1-endpoint.php 5 years ago class.wpcom-json-api-bulk-delete-post-endpoint.php 4 years ago class.wpcom-json-api-bulk-restore-post-endpoint.php 4 years ago class.wpcom-json-api-bulk-update-comments-endpoint.php 4 years ago class.wpcom-json-api-comment-endpoint.php 4 years ago class.wpcom-json-api-delete-media-endpoint.php 4 years ago class.wpcom-json-api-delete-media-v1-1-endpoint.php 4 years ago class.wpcom-json-api-edit-media-v1-2-endpoint.php 3 years ago class.wpcom-json-api-get-autosave-v1-1-endpoint.php 5 years ago class.wpcom-json-api-get-comment-counts-endpoint.php 4 years ago class.wpcom-json-api-get-comment-endpoint.php 4 years ago class.wpcom-json-api-get-comment-history-endpoint.php 4 years ago class.wpcom-json-api-get-comments-tree-endpoint.php 4 years ago class.wpcom-json-api-get-comments-tree-v1-1-endpoint.php 4 years ago class.wpcom-json-api-get-comments-tree-v1-2-endpoint.php 4 years ago class.wpcom-json-api-get-customcss.php 4 years ago class.wpcom-json-api-get-media-endpoint.php 4 years ago class.wpcom-json-api-get-media-v1-1-endpoint.php 4 years ago class.wpcom-json-api-get-media-v1-2-endpoint.php 3 years ago class.wpcom-json-api-get-post-counts-v1-1-endpoint.php 4 years ago class.wpcom-json-api-get-post-endpoint.php 4 years ago class.wpcom-json-api-get-post-v1-1-endpoint.php 4 years ago class.wpcom-json-api-get-site-endpoint.php 3 years ago class.wpcom-json-api-get-site-v1-2-endpoint.php 3 years ago class.wpcom-json-api-get-taxonomies-endpoint.php 4 years ago class.wpcom-json-api-get-taxonomy-endpoint.php 4 years ago class.wpcom-json-api-get-term-endpoint.php 4 years ago class.wpcom-json-api-list-comments-endpoint.php 3 years ago class.wpcom-json-api-list-dropdown-pages-endpoint.php 3 years ago class.wpcom-json-api-list-embeds-endpoint.php 4 years ago class.wpcom-json-api-list-media-endpoint.php 4 years ago class.wpcom-json-api-list-media-v1-1-endpoint.php 4 years ago class.wpcom-json-api-list-media-v1-2-endpoint.php 3 years ago class.wpcom-json-api-list-post-type-taxonomies-endpoint.php 4 years ago class.wpcom-json-api-list-post-types-endpoint.php 3 years ago class.wpcom-json-api-list-posts-endpoint.php 3 years ago class.wpcom-json-api-list-posts-v1-1-endpoint.php 3 years ago class.wpcom-json-api-list-posts-v1-2-endpoint.php 3 years ago class.wpcom-json-api-list-roles-endpoint.php 4 years ago class.wpcom-json-api-list-shortcodes-endpoint.php 4 years ago class.wpcom-json-api-list-terms-endpoint.php 4 years ago class.wpcom-json-api-list-users-endpoint.php 3 years ago class.wpcom-json-api-menus-v1-1-endpoint.php 4 years ago class.wpcom-json-api-post-endpoint.php 3 years ago class.wpcom-json-api-post-v1-1-endpoint.php 3 years ago class.wpcom-json-api-render-embed-endpoint.php 4 years ago class.wpcom-json-api-render-embed-reversal-endpoint.php 4 years ago class.wpcom-json-api-render-endpoint.php 3 years ago class.wpcom-json-api-render-shortcode-endpoint.php 4 years ago class.wpcom-json-api-sharing-buttons-endpoint.php 3 years ago class.wpcom-json-api-site-settings-endpoint.php 3 years ago class.wpcom-json-api-site-settings-v1-2-endpoint.php 3 years ago class.wpcom-json-api-site-settings-v1-3-endpoint.php 3 years ago class.wpcom-json-api-site-settings-v1-4-endpoint.php 3 years ago class.wpcom-json-api-site-user-endpoint.php 4 years ago class.wpcom-json-api-taxonomy-endpoint.php 4 years ago class.wpcom-json-api-update-comment-endpoint.php 3 years ago class.wpcom-json-api-update-customcss.php 4 years ago class.wpcom-json-api-update-media-endpoint.php 4 years ago class.wpcom-json-api-update-media-v1-1-endpoint.php 4 years ago class.wpcom-json-api-update-post-endpoint.php 3 years ago class.wpcom-json-api-update-post-v1-1-endpoint.php 3 years ago class.wpcom-json-api-update-post-v1-2-endpoint.php 3 years ago class.wpcom-json-api-update-site-homepage-endpoint.php 4 years ago class.wpcom-json-api-update-site-logo-endpoint.php 4 years ago class.wpcom-json-api-update-taxonomy-endpoint.php 4 years ago class.wpcom-json-api-update-term-endpoint.php 4 years ago class.wpcom-json-api-update-user-endpoint.php 4 years ago class.wpcom-json-api-upload-media-endpoint.php 4 years ago class.wpcom-json-api-upload-media-v1-1-endpoint.php 3 years ago
class.wpcom-json-api-get-site-endpoint.php
1100 lines
1 <?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
2
3 new WPCOM_JSON_API_GET_Site_Endpoint(
4 array(
5 'description' => 'Get information about a site.',
6 'group' => 'sites',
7 'stat' => 'sites:X',
8 'allowed_if_flagged' => true,
9 'method' => 'GET',
10 'max_version' => '1.1',
11 'new_version' => '1.2',
12 'path' => '/sites/%s',
13 'path_labels' => array(
14 '$site' => '(int|string) Site ID or domain',
15 ),
16 'allow_jetpack_site_auth' => true,
17
18 'allow_fallback_to_jetpack_blog_token' => true,
19
20 'query_parameters' => array(
21 'context' => false,
22 'options' => '(string) Optional. Returns specified options only. Comma-separated list. Example: options=login_url,timezone',
23 ),
24
25 'response_format' => WPCOM_JSON_API_GET_Site_Endpoint::$site_format,
26
27 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/en.blog.wordpress.com/',
28 )
29 );
30
31 /**
32 * GET Site endpoint class.
33 */
34 class WPCOM_JSON_API_GET_Site_Endpoint extends WPCOM_JSON_API_Endpoint {
35
36 /**
37 * Site meta data.
38 *
39 * @var array $site_format
40 */
41 public static $site_format = array(
42 'ID' => '(int) Site ID',
43 'name' => '(string) Title of site',
44 'description' => '(string) Tagline or description of site',
45 'URL' => '(string) Full URL to the site',
46 'user_can_manage' => '(bool) The current user can manage this site', // deprecated.
47 'capabilities' => '(array) Array of capabilities for the current user on this site.',
48 'jetpack' => '(bool) Whether the site is a Jetpack site or not',
49 'jetpack_connection' => '(bool) Whether the site is connected to WP.com via `jetpack-connection`',
50 'is_multisite' => '(bool) Whether the site is a Multisite site or not. Always true for WP.com sites.',
51 'site_owner' => '(int) User ID of the site owner',
52 'post_count' => '(int) The number of posts the site has',
53 'subscribers_count' => '(int) The number of subscribers the site has',
54 'lang' => '(string) Primary language code of the site',
55 'icon' => '(array) An array of icon formats for the site',
56 'logo' => '(array) The site logo, set in the Customizer',
57 'visible' => '(bool) If this site is visible in the user\'s site list',
58 'is_private' => '(bool) If the site is a private site or not',
59 'is_coming_soon' => '(bool) If the site is marked as "coming soon" or not',
60 'single_user_site' => '(bool) Whether the site is single user. Only returned for WP.com sites and for Jetpack sites with version 3.4 or higher.',
61 'is_vip' => '(bool) If the site is a VIP site or not.',
62 'is_following' => '(bool) If the current user is subscribed to this site in the reader',
63 'organization_id' => '(int) P2 Organization identifier.',
64 'options' => '(array) An array of options/settings for the blog. Only viewable by users with post editing rights to the site. Note: Post formats is deprecated, please see /sites/$id/post-formats/',
65 'p2_thumbnail_elements' => '(array) Details used to render a thumbnail of the site. P2020 themed sites only.',
66 'plan' => '(array) Details of the current plan for this site.',
67 'products' => '(array) Details of the current products for this site.',
68 'zendesk_site_meta' => '(array) Site meta data for Zendesk.',
69 'updates' => '(array) An array of available updates for plugins, themes, wordpress, and languages.',
70 'jetpack_modules' => '(array) A list of active Jetpack modules.',
71 'meta' => '(object) Meta data',
72 'quota' => '(array) An array describing how much space a user has left for uploads',
73 'launch_status' => '(string) A string describing the launch status of a site',
74 'site_migration' => '(array) Data about any migration into the site.',
75 'is_fse_active' => '(bool) If the site has Full Site Editing active or not.',
76 'is_fse_eligible' => '(bool) If the site is capable of Full Site Editing or not',
77 'is_core_site_editor_enabled' => '(bool) If the site has the core site editor enabled.',
78 'is_wpcom_atomic' => '(bool) If the site is a WP.com Atomic one.',
79 'is_wpcom_staging_site' => '(bool) If the site is a WP.com staging site.',
80 'user_interactions' => '(array) An array of user interactions with a site.',
81 'was_ecommerce_trial' => '(bool) If the site ever used an eCommerce trial.',
82 );
83
84 /**
85 * No member fields.
86 *
87 * @var array $no_member_fields
88 */
89 protected static $no_member_fields = array(
90 'ID',
91 'name',
92 'description',
93 'URL',
94 'jetpack',
95 'jetpack_connection',
96 'post_count',
97 'subscribers_count',
98 'lang',
99 'locale',
100 'icon',
101 'logo',
102 'visible',
103 'is_private',
104 'is_coming_soon',
105 'is_following',
106 'organization_id',
107 'meta',
108 'launch_status',
109 'site_migration',
110 'is_fse_active',
111 'is_fse_eligible',
112 'is_core_site_editor_enabled',
113 'is_wpcom_atomic',
114 'is_wpcom_staging_site',
115 );
116
117 /**
118 * Site options.
119 *
120 * @var array $site_options_format
121 */
122 protected static $site_options_format = array(
123 'timezone',
124 'gmt_offset',
125 'blog_public',
126 'videopress_enabled',
127 'upgraded_filetypes_enabled',
128 'login_url',
129 'admin_url',
130 'is_mapped_domain',
131 'is_redirect',
132 'unmapped_url',
133 'featured_images_enabled',
134 'theme_slug',
135 'header_image',
136 'background_color',
137 'image_default_link_type',
138 'image_thumbnail_width',
139 'image_thumbnail_height',
140 'image_thumbnail_crop',
141 'image_medium_width',
142 'image_medium_height',
143 'image_large_width',
144 'image_large_height',
145 'permalink_structure',
146 'post_formats',
147 'default_post_format',
148 'default_category',
149 'allowed_file_types',
150 'show_on_front',
151 /** This filter is documented in modules/likes.php */
152 'default_likes_enabled',
153 'default_sharing_status',
154 'default_comment_status',
155 'default_ping_status',
156 'software_version',
157 'created_at',
158 'updated_at',
159 'wordads',
160 'publicize_permanently_disabled',
161 'frame_nonce',
162 'jetpack_frame_nonce',
163 'page_on_front',
164 'page_for_posts',
165 'headstart',
166 'headstart_is_fresh',
167 'ak_vp_bundle_enabled',
168 Jetpack_SEO_Utils::FRONT_PAGE_META_OPTION,
169 Jetpack_SEO_Titles::TITLE_FORMATS_OPTION,
170 'verification_services_codes',
171 'podcasting_archive',
172 'is_domain_only',
173 'is_automated_transfer',
174 'is_wpcom_atomic',
175 'is_wpcom_store',
176 'signup_is_store',
177 'has_pending_automated_transfer',
178 'woocommerce_is_active',
179 'editing_toolkit_is_active',
180 'design_type',
181 'site_goals',
182 'site_segment',
183 'site_source_slug',
184 'import_engine',
185 'is_pending_plan',
186 'is_wpforteams_site',
187 'p2_hub_blog_id',
188 'site_creation_flow',
189 'is_cloud_eligible',
190 'selected_features',
191 'anchor_podcast',
192 'was_created_with_blank_canvas_design',
193 'videopress_storage_used',
194 'is_difm_lite_in_progress',
195 'difm_lite_site_options',
196 'site_intent',
197 'site_vertical_id',
198 'blogging_prompts_settings',
199 'launchpad_screen',
200 'launchpad_checklist_tasks_statuses',
201 'wpcom_production_blog_id',
202 'wpcom_staging_blog_ids',
203 'can_blaze',
204 );
205
206 /**
207 * List of DIFM Lite options to be displayed
208 *
209 * @var array $displayed_difm_lite_site_options
210 */
211 protected static $displayed_difm_lite_site_options = array(
212 'site_category',
213 'is_website_content_submitted',
214 'selected_page_titles',
215 );
216
217 /**
218 * Jetpack response fields.
219 *
220 * @var array $jetpack_response_field_additions
221 */
222 protected static $jetpack_response_field_additions = array(
223 'subscribers_count',
224 'site_migration',
225 'site_owner',
226 'is_wpcom_staging_site',
227 'was_ecommerce_trial',
228 );
229
230 /**
231 * Jetpack response field member additions.
232 *
233 * @var array $jetpack_response_field_member_additions
234 */
235 protected static $jetpack_response_field_member_additions = array(
236 'capabilities',
237 'plan',
238 'products',
239 'zendesk_site_meta',
240 );
241
242 /**
243 * Jetpack response option additions.
244 *
245 * @var array $jetpack_response_field_member_additions
246 */
247 protected static $jetpack_response_option_additions = array(
248 'publicize_permanently_disabled',
249 'ak_vp_bundle_enabled',
250 'is_automated_transfer',
251 'is_wpcom_atomic',
252 'is_wpcom_store',
253 'woocommerce_is_active',
254 'editing_toolkit_is_active',
255 'frame_nonce',
256 'jetpack_frame_nonce',
257 'design_type',
258 'wordads',
259 // Use the site registered date from wpcom, since it is only available in a multisite context
260 // and defaults to `0000-00-00T00:00:00+00:00` from the Jetpack site.
261 // See https://github.com/Automattic/jetpack/blob/58638f46094b36f5df9cbc4570006544f0ad300c/sal/class.json-api-site-base.php#L387.
262 'created_at',
263 'updated_at',
264 'is_pending_plan',
265 'is_cloud_eligible',
266 'videopress_storage_used',
267 'blogging_prompts_settings',
268 );
269
270 /**
271 * Site
272 *
273 * @var $site.
274 */
275 private $site;
276
277 /**
278 * Fields to include.
279 *
280 * @var $fields_to_include
281 */
282 protected $fields_to_include = '_all';
283
284 /**
285 * Options to include.
286 *
287 * @var $options_to_include
288 */
289 protected $options_to_include = '_all';
290
291 /**
292 *
293 * API callback.
294 *
295 * /sites/mine
296 * /sites/%s -> $blog_id\
297 *
298 * @param string $path - the path.
299 * @param int $blog_id - the blog ID.
300 */
301 public function callback( $path = '', $blog_id = 0 ) {
302 if ( 'mine' === $blog_id ) {
303 $api = WPCOM_JSON_API::init();
304 if ( ! $api->token_details || empty( $api->token_details['blog_id'] ) ) {
305 return new WP_Error( 'authorization_required', 'An active access token must be used to query information about the current blog.', 403 );
306 }
307 $blog_id = $api->token_details['blog_id'];
308 }
309
310 add_filter( 'wpcom_allow_jetpack_blog_token', '__return_true' );
311 $blog_id = $this->api->switch_to_blog_and_validate_user( $this->api->get_blog_id( $blog_id ) );
312 if ( is_wp_error( $blog_id ) ) {
313 return $blog_id;
314 }
315
316 $this->filter_fields_and_options();
317
318 $response = $this->build_current_site_response();
319
320 /** This action is documented in json-endpoints/class.wpcom-json-api-site-settings-endpoint.php */
321 do_action( 'wpcom_json_api_objects', 'sites' );
322
323 return $response;
324 }
325
326 /**
327 * Filter fields and options.
328 */
329 public function filter_fields_and_options() {
330 $query_args = $this->query_args();
331
332 $this->fields_to_include = empty( $query_args['fields'] ) ? '_all' : array_map( 'trim', explode( ',', $query_args['fields'] ) );
333 $this->options_to_include = empty( $query_args['options'] ) ? '_all' : array_map( 'trim', explode( ',', $query_args['options'] ) );
334 }
335
336 /**
337 * Collects the necessary information to return for a site's response.
338 *
339 * @return array
340 */
341 public function build_current_site_response() {
342
343 $blog_id = (int) $this->api->get_blog_id_for_output();
344
345 $this->site = $this->get_platform()->get_site( $blog_id );
346
347 /**
348 * Filter the structure of information about the site to return.
349 *
350 * @module json-api
351 *
352 * @since 3.9.3
353 *
354 * @param array $site_format Data structure.
355 */
356 $default_fields = array_keys( apply_filters( 'sites_site_format', self::$site_format ) );
357
358 $response_keys = is_array( $this->fields_to_include ) ?
359 array_intersect( $default_fields, $this->fields_to_include ) :
360 $default_fields;
361
362 $has_blog_access = $this->has_blog_access( $this->api->token_details );
363 $has_user_access = $this->has_user_access();
364
365 if ( ! $has_user_access && ! $has_blog_access ) {
366 // Public access without user or blog auth, only return `$no_member_fields`.
367 $response_keys = array_intersect( $response_keys, self::$no_member_fields );
368 } elseif ( $has_user_access && ! current_user_can( 'edit_posts' ) ) {
369 // Subscriber level user, don't return site options.
370 $response_keys = array_diff( $response_keys, array( 'options' ) );
371 }
372
373 return $this->render_response_keys( $response_keys );
374 }
375
376 /**
377 * Checks that the current user has access to the current blog.
378 *
379 * @return bool Whether or not the current user can access the current blog.
380 */
381 private function has_user_access() {
382 return is_user_member_of_blog( get_current_user_id(), get_current_blog_id() );
383 }
384
385 /**
386 * Checks if the request has a valid blog token for the current blog.
387 *
388 * @param array $token_details Access token for the api request.
389 * @return bool
390 */
391 private function has_blog_access( $token_details ) {
392 $token_details = (array) $token_details;
393 if ( ! isset( $token_details['access'], $token_details['auth'], $token_details['blog_id'] ) ) {
394 return false;
395 }
396
397 return 'jetpack' === $token_details['auth'] &&
398 'blog' === $token_details['access'] &&
399 get_current_blog_id() === $token_details['blog_id'];
400 }
401
402 /**
403 * Render response keys.
404 *
405 * @param array $response_keys - the response keys.
406 */
407 private function render_response_keys( &$response_keys ) {
408 $response = array();
409
410 $is_user_logged_in = is_user_logged_in();
411
412 $this->site->before_render();
413
414 foreach ( $response_keys as $key ) {
415 $this->render_response_key( $key, $response, $is_user_logged_in );
416 }
417
418 $this->site->after_render( $response );
419
420 return $response;
421 }
422
423 /**
424 * Render response key.
425 *
426 * @param string $key - the key.
427 * @param array $response - the response.
428 * @param boolean $is_user_logged_in - if the user is logged in.
429 */
430 protected function render_response_key( $key, &$response, $is_user_logged_in ) {
431 do_action( 'pre_render_site_response_key', $key );
432
433 switch ( $key ) {
434 case 'ID':
435 $response[ $key ] = $this->site->blog_id;
436 break;
437 case 'name':
438 $response[ $key ] = $this->site->get_name();
439 break;
440 case 'description':
441 $response[ $key ] = $this->site->get_description();
442 break;
443 case 'URL':
444 $response[ $key ] = $this->site->get_url();
445 break;
446 case 'user_can_manage':
447 $response[ $key ] = $this->site->user_can_manage();
448 // fall through is intentional.
449 case 'is_private':
450 $response[ $key ] = $this->site->is_private();
451 break;
452 case 'is_coming_soon':
453 // This option is stored on wp.com for both simple and atomic sites. @see mu-plugins/private-blog.php.
454 $response[ $key ] = $this->site->is_coming_soon();
455
456 break;
457 case 'launch_status':
458 $response[ $key ] = $this->site->get_launch_status();
459 break;
460 case 'visible':
461 $response[ $key ] = $this->site->is_visible();
462 break;
463 case 'subscribers_count':
464 $response[ $key ] = $this->site->get_subscribers_count();
465 break;
466 case 'post_count':
467 if ( $is_user_logged_in ) {
468 $response[ $key ] = $this->site->get_post_count();
469 }
470 break;
471 case 'icon':
472 $icon = $this->site->get_icon();
473
474 if ( $icon !== null ) {
475 $response[ $key ] = $icon;
476 }
477 break;
478 case 'logo':
479 $response[ $key ] = $this->site->get_logo();
480 break;
481 case 'is_following':
482 $response[ $key ] = $this->site->is_following();
483 break;
484 case 'options':
485 // small optimisation - don't recalculate.
486 $all_options = apply_filters( 'sites_site_options_format', self::$site_options_format );
487
488 $options_response_keys = is_array( $this->options_to_include ) ?
489 array_intersect( $all_options, $this->options_to_include ) :
490 $all_options;
491
492 $options = $this->render_option_keys( $options_response_keys );
493
494 $this->site->after_render_options( $options );
495
496 $response[ $key ] = (object) $options;
497 break;
498 case 'meta':
499 $this->build_meta_response( $response );
500 break;
501 case 'lang':
502 $response[ $key ] = $is_user_logged_in ? $this->site->get_locale() : false;
503 break;
504 case 'locale':
505 $response[ $key ] = $is_user_logged_in ? $this->site->get_locale() : false;
506 break;
507 case 'jetpack':
508 $response[ $key ] = $this->site->is_jetpack();
509 break;
510 case 'jetpack_connection':
511 $response[ $key ] = $this->site->is_jetpack_connection();
512 break;
513 case 'single_user_site':
514 $response[ $key ] = $this->site->is_single_user_site();
515 break;
516 case 'is_vip':
517 $response[ $key ] = $this->site->is_vip();
518 break;
519 case 'is_multisite':
520 $response[ $key ] = $this->site->is_multisite();
521 break;
522 case 'site_owner':
523 $response[ $key ] = $this->site->get_site_owner();
524 break;
525 case 'organization_id':
526 $response[ $key ] = $this->site->get_p2_organization_id();
527 break;
528
529 case 'capabilities':
530 $response[ $key ] = $this->site->get_capabilities();
531 break;
532 case 'jetpack_modules':
533 if ( is_user_member_of_blog() ) {
534 $response[ $key ] = $this->site->get_jetpack_modules();
535 }
536 break;
537 case 'plan':
538 $response[ $key ] = $this->site->get_plan();
539 break;
540 case 'products':
541 $response[ $key ] = $this->site->get_products();
542 break;
543 case 'zendesk_site_meta':
544 // D59613-code only added this function to the wpcom SAL subclasses. Absent any better idea,
545 // we'll just omit the key entirely in Jetpack.
546 if ( is_callable( array( $this->site, 'get_zendesk_site_meta' ) ) ) {
547 $response[ $key ] = $this->site->get_zendesk_site_meta();
548 }
549 break;
550 case 'quota':
551 $response[ $key ] = $this->site->get_quota();
552 break;
553 case 'site_migration':
554 $response[ $key ] = $this->site->get_migration_meta();
555 break;
556 case 'is_fse_active':
557 $response[ $key ] = $this->site->is_fse_active();
558 break;
559 case 'is_fse_eligible':
560 $response[ $key ] = $this->site->is_fse_eligible();
561 break;
562 case 'is_core_site_editor_enabled':
563 $response[ $key ] = $this->site->is_core_site_editor_enabled();
564 break;
565 case 'is_wpcom_atomic':
566 $response[ $key ] = $this->site->is_wpcom_atomic();
567 break;
568 case 'is_wpcom_staging_site':
569 $response[ $key ] = $this->site->is_wpcom_staging_site();
570 break;
571 case 'user_interactions':
572 $response[ $key ] = $this->site->get_user_interactions();
573 break;
574 case 'p2_thumbnail_elements':
575 $response[ $key ] = $this->site->get_p2_thumbnail_elements();
576 break;
577 case 'was_ecommerce_trial':
578 $response[ $key ] = $this->site->was_ecommerce_trial();
579 break;
580 }
581
582 do_action( 'post_render_site_response_key', $key );
583 }
584
585 /**
586 * Render option keys.
587 *
588 * @param array $options_response_keys - the response keys.
589 */
590 protected function render_option_keys( &$options_response_keys ) {
591 $options = array();
592 $site = $this->site;
593
594 $custom_front_page = $site->is_custom_front_page();
595
596 foreach ( $options_response_keys as $key ) {
597 switch ( $key ) {
598 case 'timezone':
599 $options[ $key ] = $site->get_timezone();
600 break;
601 case 'gmt_offset':
602 $options[ $key ] = $site->get_gmt_offset();
603 break;
604 case 'videopress_enabled':
605 $options[ $key ] = $site->has_videopress();
606 break;
607 case 'upgraded_filetypes_enabled':
608 $options[ $key ] = $site->upgraded_filetypes_enabled();
609 break;
610 case 'login_url':
611 $options[ $key ] = $site->get_login_url();
612 break;
613 case 'admin_url':
614 $options[ $key ] = $site->get_admin_url();
615 break;
616 case 'is_mapped_domain':
617 $options[ $key ] = $site->is_mapped_domain();
618 break;
619 case 'is_redirect':
620 $options[ $key ] = $site->is_redirect();
621 break;
622 case 'unmapped_url':
623 $options[ $key ] = $site->get_unmapped_url();
624 break;
625 case 'featured_images_enabled':
626 $options[ $key ] = $site->featured_images_enabled();
627 break;
628 case 'theme_slug':
629 $options[ $key ] = $site->get_theme_slug();
630 break;
631 case 'header_image':
632 $options[ $key ] = $site->get_header_image();
633 break;
634 case 'background_color':
635 $options[ $key ] = $site->get_background_color();
636 break;
637 case 'image_default_link_type':
638 $options[ $key ] = $site->get_image_default_link_type();
639 break;
640 case 'image_thumbnail_width':
641 $options[ $key ] = $site->get_image_thumbnail_width();
642 break;
643 case 'image_thumbnail_height':
644 $options[ $key ] = $site->get_image_thumbnail_height();
645 break;
646 case 'image_thumbnail_crop':
647 $options[ $key ] = $site->get_image_thumbnail_crop();
648 break;
649 case 'image_medium_width':
650 $options[ $key ] = $site->get_image_medium_width();
651 break;
652 case 'image_medium_height':
653 $options[ $key ] = $site->get_image_medium_height();
654 break;
655 case 'image_large_width':
656 $options[ $key ] = $site->get_image_large_width();
657 break;
658 case 'image_large_height':
659 $options[ $key ] = $site->get_image_large_height();
660 break;
661 case 'permalink_structure':
662 $options[ $key ] = $site->get_permalink_structure();
663 break;
664 case 'post_formats':
665 $options[ $key ] = $site->get_post_formats();
666 break;
667 case 'default_post_format':
668 $options[ $key ] = $site->get_default_post_format();
669 break;
670 case 'default_category':
671 $options[ $key ] = $site->get_default_category();
672 break;
673 case 'allowed_file_types':
674 $options[ $key ] = $site->allowed_file_types();
675 break;
676 case 'show_on_front':
677 $options[ $key ] = $site->get_show_on_front();
678 break;
679 /** This filter is documented in modules/likes.php */
680 case 'default_likes_enabled':
681 $options[ $key ] = $site->get_default_likes_enabled();
682 break;
683 case 'default_sharing_status':
684 $options[ $key ] = $site->get_default_sharing_status();
685 break;
686 case 'default_comment_status':
687 $options[ $key ] = $site->get_default_comment_status();
688 break;
689 case 'default_ping_status':
690 $options[ $key ] = $site->default_ping_status();
691 break;
692 case 'software_version':
693 $options[ $key ] = $site->get_wordpress_version();
694 break;
695 case 'created_at':
696 $options[ $key ] = $site->get_registered_date();
697 break;
698 case 'updated_at':
699 $options[ $key ] = $site->get_last_update_date();
700 break;
701 case 'wordads':
702 $options[ $key ] = $site->has_wordads();
703 break;
704 case 'publicize_permanently_disabled':
705 $options[ $key ] = $site->is_publicize_permanently_disabled();
706 break;
707 case 'frame_nonce':
708 $options[ $key ] = $site->get_frame_nonce();
709 break;
710 case 'jetpack_frame_nonce':
711 $options[ $key ] = $site->get_jetpack_frame_nonce();
712 break;
713 case 'page_on_front':
714 if ( $custom_front_page ) {
715 $options[ $key ] = $site->get_page_on_front();
716 }
717 break;
718 case 'page_for_posts':
719 if ( $custom_front_page ) {
720 $options[ $key ] = $site->get_page_for_posts();
721 }
722 break;
723 case 'headstart':
724 $options[ $key ] = $site->is_headstart();
725 break;
726 case 'headstart_is_fresh':
727 $options[ $key ] = $site->is_headstart_fresh();
728 break;
729 case 'ak_vp_bundle_enabled':
730 $options[ $key ] = $site->get_ak_vp_bundle_enabled();
731 break;
732 case Jetpack_SEO_Utils::FRONT_PAGE_META_OPTION:
733 $options[ $key ] = $site->get_jetpack_seo_front_page_description();
734 break;
735 case Jetpack_SEO_Titles::TITLE_FORMATS_OPTION:
736 $options[ $key ] = $site->get_jetpack_seo_title_formats();
737 break;
738 case 'verification_services_codes':
739 $options[ $key ] = $site->get_verification_services_codes();
740 break;
741 case 'podcasting_archive':
742 $options[ $key ] = $site->get_podcasting_archive();
743 break;
744 case 'is_domain_only':
745 $options[ $key ] = $site->is_domain_only();
746 break;
747 case 'is_automated_transfer':
748 $options[ $key ] = $site->is_automated_transfer();
749 break;
750 case 'blog_public':
751 $options[ $key ] = $site->get_blog_public();
752 break;
753 case 'is_wpcom_atomic':
754 $options[ $key ] = $site->is_wpcom_atomic();
755 break;
756 case 'is_wpcom_store':
757 $options[ $key ] = $site->is_wpcom_store();
758 break;
759 case 'signup_is_store':
760 $signup_is_store = $site->signup_is_store();
761
762 if ( $signup_is_store ) {
763 $options[ $key ] = $site->signup_is_store();
764 }
765
766 break;
767 case 'has_pending_automated_transfer':
768 $has_pending_automated_transfer = $site->has_pending_automated_transfer();
769
770 if ( $has_pending_automated_transfer ) {
771 $options[ $key ] = true;
772 }
773
774 break;
775 case 'woocommerce_is_active':
776 $options[ $key ] = $site->woocommerce_is_active();
777 break;
778 case 'editing_toolkit_is_active':
779 $options[ $key ] = $site->editing_toolkit_is_active();
780 break;
781 case 'design_type':
782 $options[ $key ] = $site->get_design_type();
783 break;
784 case 'site_segment':
785 $options[ $key ] = $site->get_site_segment();
786 break;
787 case 'import_engine':
788 $options[ $key ] = $site->get_import_engine();
789 break;
790 case 'is_pending_plan':
791 // D40032-code only added this function to the wpcom SAL subclasses. Absent any better idea,
792 // we'll just omit the key entirely in Jetpack.
793 if ( is_callable( array( $site, 'is_pending_plan' ) ) ) {
794 $options[ $key ] = $site->is_pending_plan();
795 }
796 break;
797
798 case 'is_wpforteams_site':
799 $options[ $key ] = $site->is_wpforteams_site();
800 break;
801 case 'p2_hub_blog_id':
802 $options[ $key ] = $site->get_p2_hub_blog_id();
803 break;
804
805 case 'site_creation_flow':
806 $site_creation_flow = $site->get_site_creation_flow();
807 if ( $site_creation_flow ) {
808 $options[ $key ] = $site_creation_flow;
809 }
810 break;
811 case 'site_source_slug':
812 $site_source_slug = $site->get_site_source_slug();
813 if ( $site_source_slug ) {
814 $options[ $key ] = $site_source_slug;
815 }
816 break;
817 case 'is_cloud_eligible':
818 $options[ $key ] = $site->is_cloud_eligible();
819 break;
820 case 'selected_features':
821 $selected_features = $site->get_selected_features();
822 if ( $selected_features ) {
823 $options[ $key ] = $selected_features;
824 }
825 break;
826 case 'anchor_podcast':
827 $options[ $key ] = $site->get_anchor_podcast();
828 break;
829 case 'was_created_with_blank_canvas_design':
830 $options[ $key ] = $site->was_created_with_blank_canvas_design();
831 break;
832 case 'videopress_storage_used':
833 $options[ $key ] = $this->site->get_videopress_storage_used();
834 break;
835 case 'is_difm_lite_in_progress':
836 $options[ $key ] = $site->is_difm_lite_in_progress();
837 break;
838 case 'difm_lite_site_options':
839 $difm_lite_options = $site->get_difm_lite_site_options();
840 $visible_options = self::$displayed_difm_lite_site_options;
841 $filtered_difm_lite_options = new stdClass();
842 if ( $difm_lite_options ) {
843 $filtered_difm_lite_options = array_filter(
844 $difm_lite_options,
845 function ( $key ) use ( $visible_options ) {
846 return in_array( $key, $visible_options, true );
847 },
848 ARRAY_FILTER_USE_KEY
849 );
850 }
851 $options[ $key ] = $filtered_difm_lite_options;
852 break;
853 case 'site_intent':
854 $options[ $key ] = $site->get_site_intent();
855 break;
856 case 'site_vertical_id':
857 $options[ $key ] = $site->get_site_vertical_id();
858 break;
859 case 'blogging_prompts_settings':
860 if ( current_user_can( 'edit_posts' ) ) {
861 $options[ $key ] = $site->get_blogging_prompts_settings( get_current_user_id(), $site->blog_id );
862 }
863 break;
864 case 'launchpad_screen':
865 $options[ $key ] = $site->get_launchpad_screen();
866 break;
867 case 'launchpad_checklist_tasks_statuses':
868 $options[ $key ] = $site->get_launchpad_checklist_tasks_statuses();
869 break;
870 case 'wpcom_production_blog_id':
871 $options[ $key ] = $site->get_wpcom_production_blog_id();
872 break;
873 case 'wpcom_staging_blog_ids':
874 $options[ $key ] = $site->get_wpcom_staging_blog_ids();
875 break;
876 case 'can_blaze':
877 $options[ $key ] = $site->can_blaze();
878 break;
879 }
880 }
881
882 return $options;
883 }
884
885 /**
886 * Build meta response.
887 *
888 * @param array $response - the response.
889 */
890 protected function build_meta_response( &$response ) {
891 $links = array(
892 'self' => (string) $this->links->get_site_link( $this->site->blog_id ),
893 'help' => (string) $this->links->get_site_link( $this->site->blog_id, 'help' ),
894 'posts' => (string) $this->links->get_site_link( $this->site->blog_id, 'posts/' ),
895 'comments' => (string) $this->links->get_site_link( $this->site->blog_id, 'comments/' ),
896 'xmlrpc' => (string) $this->site->get_xmlrpc_url(),
897 );
898
899 $icon = $this->site->get_icon();
900 if ( ! empty( $icon ) && ! empty( $icon['media_id'] ) ) {
901 $links['site_icon'] = (string) $this->links->get_site_link( $this->site->blog_id, 'media/' . $icon['media_id'] );
902 }
903
904 $response['meta'] = (object) array(
905 'links' => (object) $links,
906 );
907 }
908
909 /**
910 * Apply any WPCOM-only response components to a Jetpack site response.
911 *
912 * @param array $response - the response.
913 */
914 public function decorate_jetpack_response( &$response ) {
915 $this->site = $this->get_platform()->get_site( $response->ID );
916 switch_to_blog( $this->site->get_id() );
917
918 $wpcom_response = $this->render_response_keys( self::$jetpack_response_field_additions );
919
920 foreach ( $wpcom_response as $key => $value ) {
921 $response->{ $key } = $value;
922 }
923
924 if ( $this->has_user_access() || $this->has_blog_access( $this->api->token_details ) ) {
925 $wpcom_member_response = $this->render_response_keys( self::$jetpack_response_field_member_additions );
926
927 foreach ( $wpcom_member_response as $key => $value ) {
928 $response->{ $key } = $value;
929 }
930 } else {
931 // ensure private data is not rendered for non members of the site.
932 unset( $response->options );
933 unset( $response->is_vip );
934 unset( $response->single_user_site );
935 unset( $response->is_private );
936 unset( $response->is_coming_soon );
937 unset( $response->capabilities );
938 unset( $response->lang );
939 unset( $response->user_can_manage );
940 unset( $response->is_multisite );
941 unset( $response->site_owner );
942 unset( $response->plan );
943 unset( $response->products );
944 unset( $response->zendesk_site_meta );
945 }
946
947 // render additional options.
948 if ( $response->options ) {
949 $wpcom_options_response = $this->render_option_keys( self::$jetpack_response_option_additions );
950
951 // Remove heic from jetpack (and atomic) sites so that the iOS app know to convert the file format into a JPEG.
952 // heic fromat is currently not supported by for uploading.
953 // See https://jetpackp2.wordpress.com/2020/08/19/image-uploads-in-the-wp-ios-app-broken
954 if ( $this->site->is_jetpack() && isset( $response->options['allowed_file_types'] ) ) {
955 $remove_file_types = array(
956 'heic',
957 );
958 $response->options['allowed_file_types'] = array_values( array_diff( $response->options['allowed_file_types'], $remove_file_types ) );
959 }
960
961 foreach ( $wpcom_options_response as $key => $value ) {
962 $response->options[ $key ] = $value;
963 }
964 }
965
966 restore_current_blog();
967 return $response; // possibly no need since it's modified in place.
968 }
969 }
970
971 new WPCOM_JSON_API_List_Post_Formats_Endpoint(
972 array(
973 'description' => 'Get a list of post formats supported by a site.',
974 'group' => '__do_not_document',
975 'stat' => 'sites:X:post-formats',
976
977 'method' => 'GET',
978 'path' => '/sites/%s/post-formats',
979 'path_labels' => array(
980 '$site' => '(int|string) Site ID or domain',
981 ),
982
983 'query_parameters' => array(
984 'context' => false,
985 ),
986
987 'allow_fallback_to_jetpack_blog_token' => true,
988
989 'response_format' => array(
990 'formats' => '(object) An object of supported post formats, each key a supported format slug mapped to its display string.',
991 ),
992 )
993 );
994
995 /**
996 * List Post Formates endpoint class.
997 */
998 class WPCOM_JSON_API_List_Post_Formats_Endpoint extends WPCOM_JSON_API_Endpoint { // phpcs:ignore
999 /**
1000 *
1001 * API callback.
1002 *
1003 * /sites/%s/post-formats -> $blog_id
1004 *
1005 * @param string $path - the path.
1006 * @param int $blog_id - the blog ID.
1007 */
1008 public function callback( $path = '', $blog_id = 0 ) {
1009 $blog_id = $this->api->switch_to_blog_and_validate_user( $this->api->get_blog_id( $blog_id ) );
1010 if ( is_wp_error( $blog_id ) ) {
1011 return $blog_id;
1012 }
1013
1014 if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
1015 $this->load_theme_functions();
1016 }
1017
1018 // Get a list of supported post formats.
1019 $all_formats = get_post_format_strings();
1020 $supported = get_theme_support( 'post-formats' );
1021
1022 $response = array(
1023 'formats' => array(),
1024 );
1025 $supported_formats = $response['formats'];
1026
1027 if ( isset( $supported[0] ) ) {
1028 foreach ( $supported[0] as $format ) {
1029 $supported_formats[ $format ] = $all_formats[ $format ];
1030 }
1031 }
1032
1033 $response['formats'] = (object) $supported_formats;
1034
1035 return $response;
1036 }
1037 }
1038
1039 new WPCOM_JSON_API_List_Page_Templates_Endpoint(
1040 array(
1041 'description' => 'Get a list of page templates supported by a site.',
1042 'group' => 'sites',
1043 'stat' => 'sites:X:post-templates',
1044
1045 'method' => 'GET',
1046 'path' => '/sites/%s/page-templates',
1047 'path_labels' => array(
1048 '$site' => '(int|string) Site ID or domain',
1049 ),
1050 'query_parameters' => array(
1051 'context' => false,
1052 ),
1053 'response_format' => array(
1054 'templates' => '(array) A list of supported page templates. Contains label and file.',
1055 ),
1056 'example_request' => 'https://public-api.wordpress.com/rest/v1.1/sites/33534099/page-templates',
1057 )
1058 );
1059
1060 /**
1061 * List page templates endpoint class.
1062 */
1063 class WPCOM_JSON_API_List_Page_Templates_Endpoint extends WPCOM_JSON_API_Endpoint { // phpcs:ignore
1064 /**
1065 *
1066 * API callback.
1067 * /sites/%s/page-templates -> $blog_id
1068 *
1069 * @param string $path - the path.
1070 * @param int $blog_id - the blog ID.
1071 */
1072 public function callback( $path = '', $blog_id = 0 ) {
1073 $blog_id = $this->api->switch_to_blog_and_validate_user( $this->api->get_blog_id( $blog_id ) );
1074 if ( is_wp_error( $blog_id ) ) {
1075 return $blog_id;
1076 }
1077
1078 if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
1079 $this->load_theme_functions();
1080 }
1081
1082 $response = array();
1083 $page_templates = array();
1084
1085 $templates = get_page_templates();
1086 ksort( $templates );
1087
1088 foreach ( array_keys( $templates ) as $label ) {
1089 $page_templates[] = array(
1090 'label' => $label,
1091 'file' => $templates[ $label ],
1092 );
1093 }
1094
1095 $response['templates'] = $page_templates;
1096
1097 return $response;
1098 }
1099 }
1100