PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 12.1.3
Jetpack – WP Security, Backup, Speed, & Growth v12.1.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
1102 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 'wpcom_production_blog_id',
269 'wpcom_staging_blog_ids',
270 );
271
272 /**
273 * Site
274 *
275 * @var $site.
276 */
277 private $site;
278
279 /**
280 * Fields to include.
281 *
282 * @var $fields_to_include
283 */
284 protected $fields_to_include = '_all';
285
286 /**
287 * Options to include.
288 *
289 * @var $options_to_include
290 */
291 protected $options_to_include = '_all';
292
293 /**
294 *
295 * API callback.
296 *
297 * /sites/mine
298 * /sites/%s -> $blog_id\
299 *
300 * @param string $path - the path.
301 * @param int $blog_id - the blog ID.
302 */
303 public function callback( $path = '', $blog_id = 0 ) {
304 if ( 'mine' === $blog_id ) {
305 $api = WPCOM_JSON_API::init();
306 if ( ! $api->token_details || empty( $api->token_details['blog_id'] ) ) {
307 return new WP_Error( 'authorization_required', 'An active access token must be used to query information about the current blog.', 403 );
308 }
309 $blog_id = $api->token_details['blog_id'];
310 }
311
312 add_filter( 'wpcom_allow_jetpack_blog_token', '__return_true' );
313 $blog_id = $this->api->switch_to_blog_and_validate_user( $this->api->get_blog_id( $blog_id ) );
314 if ( is_wp_error( $blog_id ) ) {
315 return $blog_id;
316 }
317
318 $this->filter_fields_and_options();
319
320 $response = $this->build_current_site_response();
321
322 /** This action is documented in json-endpoints/class.wpcom-json-api-site-settings-endpoint.php */
323 do_action( 'wpcom_json_api_objects', 'sites' );
324
325 return $response;
326 }
327
328 /**
329 * Filter fields and options.
330 */
331 public function filter_fields_and_options() {
332 $query_args = $this->query_args();
333
334 $this->fields_to_include = empty( $query_args['fields'] ) ? '_all' : array_map( 'trim', explode( ',', $query_args['fields'] ) );
335 $this->options_to_include = empty( $query_args['options'] ) ? '_all' : array_map( 'trim', explode( ',', $query_args['options'] ) );
336 }
337
338 /**
339 * Collects the necessary information to return for a site's response.
340 *
341 * @return array
342 */
343 public function build_current_site_response() {
344
345 $blog_id = (int) $this->api->get_blog_id_for_output();
346
347 $this->site = $this->get_platform()->get_site( $blog_id );
348
349 /**
350 * Filter the structure of information about the site to return.
351 *
352 * @module json-api
353 *
354 * @since 3.9.3
355 *
356 * @param array $site_format Data structure.
357 */
358 $default_fields = array_keys( apply_filters( 'sites_site_format', self::$site_format ) );
359
360 $response_keys = is_array( $this->fields_to_include ) ?
361 array_intersect( $default_fields, $this->fields_to_include ) :
362 $default_fields;
363
364 $has_blog_access = $this->has_blog_access( $this->api->token_details );
365 $has_user_access = $this->has_user_access();
366
367 if ( ! $has_user_access && ! $has_blog_access ) {
368 // Public access without user or blog auth, only return `$no_member_fields`.
369 $response_keys = array_intersect( $response_keys, self::$no_member_fields );
370 } elseif ( $has_user_access && ! current_user_can( 'edit_posts' ) ) {
371 // Subscriber level user, don't return site options.
372 $response_keys = array_diff( $response_keys, array( 'options' ) );
373 }
374
375 return $this->render_response_keys( $response_keys );
376 }
377
378 /**
379 * Checks that the current user has access to the current blog.
380 *
381 * @return bool Whether or not the current user can access the current blog.
382 */
383 private function has_user_access() {
384 return is_user_member_of_blog( get_current_user_id(), get_current_blog_id() );
385 }
386
387 /**
388 * Checks if the request has a valid blog token for the current blog.
389 *
390 * @param array $token_details Access token for the api request.
391 * @return bool
392 */
393 private function has_blog_access( $token_details ) {
394 $token_details = (array) $token_details;
395 if ( ! isset( $token_details['access'], $token_details['auth'], $token_details['blog_id'] ) ) {
396 return false;
397 }
398
399 return 'jetpack' === $token_details['auth'] &&
400 'blog' === $token_details['access'] &&
401 get_current_blog_id() === $token_details['blog_id'];
402 }
403
404 /**
405 * Render response keys.
406 *
407 * @param array $response_keys - the response keys.
408 */
409 private function render_response_keys( &$response_keys ) {
410 $response = array();
411
412 $is_user_logged_in = is_user_logged_in();
413
414 $this->site->before_render();
415
416 foreach ( $response_keys as $key ) {
417 $this->render_response_key( $key, $response, $is_user_logged_in );
418 }
419
420 $this->site->after_render( $response );
421
422 return $response;
423 }
424
425 /**
426 * Render response key.
427 *
428 * @param string $key - the key.
429 * @param array $response - the response.
430 * @param boolean $is_user_logged_in - if the user is logged in.
431 */
432 protected function render_response_key( $key, &$response, $is_user_logged_in ) {
433 do_action( 'pre_render_site_response_key', $key );
434
435 switch ( $key ) {
436 case 'ID':
437 $response[ $key ] = $this->site->blog_id;
438 break;
439 case 'name':
440 $response[ $key ] = $this->site->get_name();
441 break;
442 case 'description':
443 $response[ $key ] = $this->site->get_description();
444 break;
445 case 'URL':
446 $response[ $key ] = $this->site->get_url();
447 break;
448 case 'user_can_manage':
449 $response[ $key ] = $this->site->user_can_manage();
450 // fall through is intentional.
451 case 'is_private':
452 $response[ $key ] = $this->site->is_private();
453 break;
454 case 'is_coming_soon':
455 // This option is stored on wp.com for both simple and atomic sites. @see mu-plugins/private-blog.php.
456 $response[ $key ] = $this->site->is_coming_soon();
457
458 break;
459 case 'launch_status':
460 $response[ $key ] = $this->site->get_launch_status();
461 break;
462 case 'visible':
463 $response[ $key ] = $this->site->is_visible();
464 break;
465 case 'subscribers_count':
466 $response[ $key ] = $this->site->get_subscribers_count();
467 break;
468 case 'post_count':
469 if ( $is_user_logged_in ) {
470 $response[ $key ] = $this->site->get_post_count();
471 }
472 break;
473 case 'icon':
474 $icon = $this->site->get_icon();
475
476 if ( $icon !== null ) {
477 $response[ $key ] = $icon;
478 }
479 break;
480 case 'logo':
481 $response[ $key ] = $this->site->get_logo();
482 break;
483 case 'is_following':
484 $response[ $key ] = $this->site->is_following();
485 break;
486 case 'options':
487 // small optimisation - don't recalculate.
488 $all_options = apply_filters( 'sites_site_options_format', self::$site_options_format );
489
490 $options_response_keys = is_array( $this->options_to_include ) ?
491 array_intersect( $all_options, $this->options_to_include ) :
492 $all_options;
493
494 $options = $this->render_option_keys( $options_response_keys );
495
496 $this->site->after_render_options( $options );
497
498 $response[ $key ] = (object) $options;
499 break;
500 case 'meta':
501 $this->build_meta_response( $response );
502 break;
503 case 'lang':
504 $response[ $key ] = $is_user_logged_in ? $this->site->get_locale() : false;
505 break;
506 case 'locale':
507 $response[ $key ] = $is_user_logged_in ? $this->site->get_locale() : false;
508 break;
509 case 'jetpack':
510 $response[ $key ] = $this->site->is_jetpack();
511 break;
512 case 'jetpack_connection':
513 $response[ $key ] = $this->site->is_jetpack_connection();
514 break;
515 case 'single_user_site':
516 $response[ $key ] = $this->site->is_single_user_site();
517 break;
518 case 'is_vip':
519 $response[ $key ] = $this->site->is_vip();
520 break;
521 case 'is_multisite':
522 $response[ $key ] = $this->site->is_multisite();
523 break;
524 case 'site_owner':
525 $response[ $key ] = $this->site->get_site_owner();
526 break;
527 case 'organization_id':
528 $response[ $key ] = $this->site->get_p2_organization_id();
529 break;
530
531 case 'capabilities':
532 $response[ $key ] = $this->site->get_capabilities();
533 break;
534 case 'jetpack_modules':
535 if ( is_user_member_of_blog() ) {
536 $response[ $key ] = $this->site->get_jetpack_modules();
537 }
538 break;
539 case 'plan':
540 $response[ $key ] = $this->site->get_plan();
541 break;
542 case 'products':
543 $response[ $key ] = $this->site->get_products();
544 break;
545 case 'zendesk_site_meta':
546 // D59613-code only added this function to the wpcom SAL subclasses. Absent any better idea,
547 // we'll just omit the key entirely in Jetpack.
548 if ( is_callable( array( $this->site, 'get_zendesk_site_meta' ) ) ) {
549 $response[ $key ] = $this->site->get_zendesk_site_meta();
550 }
551 break;
552 case 'quota':
553 $response[ $key ] = $this->site->get_quota();
554 break;
555 case 'site_migration':
556 $response[ $key ] = $this->site->get_migration_meta();
557 break;
558 case 'is_fse_active':
559 $response[ $key ] = $this->site->is_fse_active();
560 break;
561 case 'is_fse_eligible':
562 $response[ $key ] = $this->site->is_fse_eligible();
563 break;
564 case 'is_core_site_editor_enabled':
565 $response[ $key ] = $this->site->is_core_site_editor_enabled();
566 break;
567 case 'is_wpcom_atomic':
568 $response[ $key ] = $this->site->is_wpcom_atomic();
569 break;
570 case 'is_wpcom_staging_site':
571 $response[ $key ] = $this->site->is_wpcom_staging_site();
572 break;
573 case 'user_interactions':
574 $response[ $key ] = $this->site->get_user_interactions();
575 break;
576 case 'p2_thumbnail_elements':
577 $response[ $key ] = $this->site->get_p2_thumbnail_elements();
578 break;
579 case 'was_ecommerce_trial':
580 $response[ $key ] = $this->site->was_ecommerce_trial();
581 break;
582 }
583
584 do_action( 'post_render_site_response_key', $key );
585 }
586
587 /**
588 * Render option keys.
589 *
590 * @param array $options_response_keys - the response keys.
591 */
592 protected function render_option_keys( &$options_response_keys ) {
593 $options = array();
594 $site = $this->site;
595
596 $custom_front_page = $site->is_custom_front_page();
597
598 foreach ( $options_response_keys as $key ) {
599 switch ( $key ) {
600 case 'timezone':
601 $options[ $key ] = $site->get_timezone();
602 break;
603 case 'gmt_offset':
604 $options[ $key ] = $site->get_gmt_offset();
605 break;
606 case 'videopress_enabled':
607 $options[ $key ] = $site->has_videopress();
608 break;
609 case 'upgraded_filetypes_enabled':
610 $options[ $key ] = $site->upgraded_filetypes_enabled();
611 break;
612 case 'login_url':
613 $options[ $key ] = $site->get_login_url();
614 break;
615 case 'admin_url':
616 $options[ $key ] = $site->get_admin_url();
617 break;
618 case 'is_mapped_domain':
619 $options[ $key ] = $site->is_mapped_domain();
620 break;
621 case 'is_redirect':
622 $options[ $key ] = $site->is_redirect();
623 break;
624 case 'unmapped_url':
625 $options[ $key ] = $site->get_unmapped_url();
626 break;
627 case 'featured_images_enabled':
628 $options[ $key ] = $site->featured_images_enabled();
629 break;
630 case 'theme_slug':
631 $options[ $key ] = $site->get_theme_slug();
632 break;
633 case 'header_image':
634 $options[ $key ] = $site->get_header_image();
635 break;
636 case 'background_color':
637 $options[ $key ] = $site->get_background_color();
638 break;
639 case 'image_default_link_type':
640 $options[ $key ] = $site->get_image_default_link_type();
641 break;
642 case 'image_thumbnail_width':
643 $options[ $key ] = $site->get_image_thumbnail_width();
644 break;
645 case 'image_thumbnail_height':
646 $options[ $key ] = $site->get_image_thumbnail_height();
647 break;
648 case 'image_thumbnail_crop':
649 $options[ $key ] = $site->get_image_thumbnail_crop();
650 break;
651 case 'image_medium_width':
652 $options[ $key ] = $site->get_image_medium_width();
653 break;
654 case 'image_medium_height':
655 $options[ $key ] = $site->get_image_medium_height();
656 break;
657 case 'image_large_width':
658 $options[ $key ] = $site->get_image_large_width();
659 break;
660 case 'image_large_height':
661 $options[ $key ] = $site->get_image_large_height();
662 break;
663 case 'permalink_structure':
664 $options[ $key ] = $site->get_permalink_structure();
665 break;
666 case 'post_formats':
667 $options[ $key ] = $site->get_post_formats();
668 break;
669 case 'default_post_format':
670 $options[ $key ] = $site->get_default_post_format();
671 break;
672 case 'default_category':
673 $options[ $key ] = $site->get_default_category();
674 break;
675 case 'allowed_file_types':
676 $options[ $key ] = $site->allowed_file_types();
677 break;
678 case 'show_on_front':
679 $options[ $key ] = $site->get_show_on_front();
680 break;
681 /** This filter is documented in modules/likes.php */
682 case 'default_likes_enabled':
683 $options[ $key ] = $site->get_default_likes_enabled();
684 break;
685 case 'default_sharing_status':
686 $options[ $key ] = $site->get_default_sharing_status();
687 break;
688 case 'default_comment_status':
689 $options[ $key ] = $site->get_default_comment_status();
690 break;
691 case 'default_ping_status':
692 $options[ $key ] = $site->default_ping_status();
693 break;
694 case 'software_version':
695 $options[ $key ] = $site->get_wordpress_version();
696 break;
697 case 'created_at':
698 $options[ $key ] = $site->get_registered_date();
699 break;
700 case 'updated_at':
701 $options[ $key ] = $site->get_last_update_date();
702 break;
703 case 'wordads':
704 $options[ $key ] = $site->has_wordads();
705 break;
706 case 'publicize_permanently_disabled':
707 $options[ $key ] = $site->is_publicize_permanently_disabled();
708 break;
709 case 'frame_nonce':
710 $options[ $key ] = $site->get_frame_nonce();
711 break;
712 case 'jetpack_frame_nonce':
713 $options[ $key ] = $site->get_jetpack_frame_nonce();
714 break;
715 case 'page_on_front':
716 if ( $custom_front_page ) {
717 $options[ $key ] = $site->get_page_on_front();
718 }
719 break;
720 case 'page_for_posts':
721 if ( $custom_front_page ) {
722 $options[ $key ] = $site->get_page_for_posts();
723 }
724 break;
725 case 'headstart':
726 $options[ $key ] = $site->is_headstart();
727 break;
728 case 'headstart_is_fresh':
729 $options[ $key ] = $site->is_headstart_fresh();
730 break;
731 case 'ak_vp_bundle_enabled':
732 $options[ $key ] = $site->get_ak_vp_bundle_enabled();
733 break;
734 case Jetpack_SEO_Utils::FRONT_PAGE_META_OPTION:
735 $options[ $key ] = $site->get_jetpack_seo_front_page_description();
736 break;
737 case Jetpack_SEO_Titles::TITLE_FORMATS_OPTION:
738 $options[ $key ] = $site->get_jetpack_seo_title_formats();
739 break;
740 case 'verification_services_codes':
741 $options[ $key ] = $site->get_verification_services_codes();
742 break;
743 case 'podcasting_archive':
744 $options[ $key ] = $site->get_podcasting_archive();
745 break;
746 case 'is_domain_only':
747 $options[ $key ] = $site->is_domain_only();
748 break;
749 case 'is_automated_transfer':
750 $options[ $key ] = $site->is_automated_transfer();
751 break;
752 case 'blog_public':
753 $options[ $key ] = $site->get_blog_public();
754 break;
755 case 'is_wpcom_atomic':
756 $options[ $key ] = $site->is_wpcom_atomic();
757 break;
758 case 'is_wpcom_store':
759 $options[ $key ] = $site->is_wpcom_store();
760 break;
761 case 'signup_is_store':
762 $signup_is_store = $site->signup_is_store();
763
764 if ( $signup_is_store ) {
765 $options[ $key ] = $site->signup_is_store();
766 }
767
768 break;
769 case 'has_pending_automated_transfer':
770 $has_pending_automated_transfer = $site->has_pending_automated_transfer();
771
772 if ( $has_pending_automated_transfer ) {
773 $options[ $key ] = true;
774 }
775
776 break;
777 case 'woocommerce_is_active':
778 $options[ $key ] = $site->woocommerce_is_active();
779 break;
780 case 'editing_toolkit_is_active':
781 $options[ $key ] = $site->editing_toolkit_is_active();
782 break;
783 case 'design_type':
784 $options[ $key ] = $site->get_design_type();
785 break;
786 case 'site_segment':
787 $options[ $key ] = $site->get_site_segment();
788 break;
789 case 'import_engine':
790 $options[ $key ] = $site->get_import_engine();
791 break;
792 case 'is_pending_plan':
793 // D40032-code only added this function to the wpcom SAL subclasses. Absent any better idea,
794 // we'll just omit the key entirely in Jetpack.
795 if ( is_callable( array( $site, 'is_pending_plan' ) ) ) {
796 $options[ $key ] = $site->is_pending_plan();
797 }
798 break;
799
800 case 'is_wpforteams_site':
801 $options[ $key ] = $site->is_wpforteams_site();
802 break;
803 case 'p2_hub_blog_id':
804 $options[ $key ] = $site->get_p2_hub_blog_id();
805 break;
806
807 case 'site_creation_flow':
808 $site_creation_flow = $site->get_site_creation_flow();
809 if ( $site_creation_flow ) {
810 $options[ $key ] = $site_creation_flow;
811 }
812 break;
813 case 'site_source_slug':
814 $site_source_slug = $site->get_site_source_slug();
815 if ( $site_source_slug ) {
816 $options[ $key ] = $site_source_slug;
817 }
818 break;
819 case 'is_cloud_eligible':
820 $options[ $key ] = $site->is_cloud_eligible();
821 break;
822 case 'selected_features':
823 $selected_features = $site->get_selected_features();
824 if ( $selected_features ) {
825 $options[ $key ] = $selected_features;
826 }
827 break;
828 case 'anchor_podcast':
829 $options[ $key ] = $site->get_anchor_podcast();
830 break;
831 case 'was_created_with_blank_canvas_design':
832 $options[ $key ] = $site->was_created_with_blank_canvas_design();
833 break;
834 case 'videopress_storage_used':
835 $options[ $key ] = $this->site->get_videopress_storage_used();
836 break;
837 case 'is_difm_lite_in_progress':
838 $options[ $key ] = $site->is_difm_lite_in_progress();
839 break;
840 case 'difm_lite_site_options':
841 $difm_lite_options = $site->get_difm_lite_site_options();
842 $visible_options = self::$displayed_difm_lite_site_options;
843 $filtered_difm_lite_options = new stdClass();
844 if ( $difm_lite_options ) {
845 $filtered_difm_lite_options = array_filter(
846 $difm_lite_options,
847 function ( $key ) use ( $visible_options ) {
848 return in_array( $key, $visible_options, true );
849 },
850 ARRAY_FILTER_USE_KEY
851 );
852 }
853 $options[ $key ] = $filtered_difm_lite_options;
854 break;
855 case 'site_intent':
856 $options[ $key ] = $site->get_site_intent();
857 break;
858 case 'site_vertical_id':
859 $options[ $key ] = $site->get_site_vertical_id();
860 break;
861 case 'blogging_prompts_settings':
862 if ( current_user_can( 'edit_posts' ) ) {
863 $options[ $key ] = $site->get_blogging_prompts_settings( get_current_user_id(), $site->blog_id );
864 }
865 break;
866 case 'launchpad_screen':
867 $options[ $key ] = $site->get_launchpad_screen();
868 break;
869 case 'launchpad_checklist_tasks_statuses':
870 $options[ $key ] = $site->get_launchpad_checklist_tasks_statuses();
871 break;
872 case 'wpcom_production_blog_id':
873 $options[ $key ] = $site->get_wpcom_production_blog_id();
874 break;
875 case 'wpcom_staging_blog_ids':
876 $options[ $key ] = $site->get_wpcom_staging_blog_ids();
877 break;
878 case 'can_blaze':
879 $options[ $key ] = $site->can_blaze();
880 break;
881 }
882 }
883
884 return $options;
885 }
886
887 /**
888 * Build meta response.
889 *
890 * @param array $response - the response.
891 */
892 protected function build_meta_response( &$response ) {
893 $links = array(
894 'self' => (string) $this->links->get_site_link( $this->site->blog_id ),
895 'help' => (string) $this->links->get_site_link( $this->site->blog_id, 'help' ),
896 'posts' => (string) $this->links->get_site_link( $this->site->blog_id, 'posts/' ),
897 'comments' => (string) $this->links->get_site_link( $this->site->blog_id, 'comments/' ),
898 'xmlrpc' => (string) $this->site->get_xmlrpc_url(),
899 );
900
901 $icon = $this->site->get_icon();
902 if ( ! empty( $icon ) && ! empty( $icon['media_id'] ) ) {
903 $links['site_icon'] = (string) $this->links->get_site_link( $this->site->blog_id, 'media/' . $icon['media_id'] );
904 }
905
906 $response['meta'] = (object) array(
907 'links' => (object) $links,
908 );
909 }
910
911 /**
912 * Apply any WPCOM-only response components to a Jetpack site response.
913 *
914 * @param array $response - the response.
915 */
916 public function decorate_jetpack_response( &$response ) {
917 $this->site = $this->get_platform()->get_site( $response->ID );
918 switch_to_blog( $this->site->get_id() );
919
920 $wpcom_response = $this->render_response_keys( self::$jetpack_response_field_additions );
921
922 foreach ( $wpcom_response as $key => $value ) {
923 $response->{ $key } = $value;
924 }
925
926 if ( $this->has_user_access() || $this->has_blog_access( $this->api->token_details ) ) {
927 $wpcom_member_response = $this->render_response_keys( self::$jetpack_response_field_member_additions );
928
929 foreach ( $wpcom_member_response as $key => $value ) {
930 $response->{ $key } = $value;
931 }
932 } else {
933 // ensure private data is not rendered for non members of the site.
934 unset( $response->options );
935 unset( $response->is_vip );
936 unset( $response->single_user_site );
937 unset( $response->is_private );
938 unset( $response->is_coming_soon );
939 unset( $response->capabilities );
940 unset( $response->lang );
941 unset( $response->user_can_manage );
942 unset( $response->is_multisite );
943 unset( $response->site_owner );
944 unset( $response->plan );
945 unset( $response->products );
946 unset( $response->zendesk_site_meta );
947 }
948
949 // render additional options.
950 if ( $response->options ) {
951 $wpcom_options_response = $this->render_option_keys( self::$jetpack_response_option_additions );
952
953 // Remove heic from jetpack (and atomic) sites so that the iOS app know to convert the file format into a JPEG.
954 // heic fromat is currently not supported by for uploading.
955 // See https://jetpackp2.wordpress.com/2020/08/19/image-uploads-in-the-wp-ios-app-broken
956 if ( $this->site->is_jetpack() && isset( $response->options['allowed_file_types'] ) ) {
957 $remove_file_types = array(
958 'heic',
959 );
960 $response->options['allowed_file_types'] = array_values( array_diff( $response->options['allowed_file_types'], $remove_file_types ) );
961 }
962
963 foreach ( $wpcom_options_response as $key => $value ) {
964 $response->options[ $key ] = $value;
965 }
966 }
967
968 restore_current_blog();
969 return $response; // possibly no need since it's modified in place.
970 }
971 }
972
973 new WPCOM_JSON_API_List_Post_Formats_Endpoint(
974 array(
975 'description' => 'Get a list of post formats supported by a site.',
976 'group' => '__do_not_document',
977 'stat' => 'sites:X:post-formats',
978
979 'method' => 'GET',
980 'path' => '/sites/%s/post-formats',
981 'path_labels' => array(
982 '$site' => '(int|string) Site ID or domain',
983 ),
984
985 'query_parameters' => array(
986 'context' => false,
987 ),
988
989 'allow_fallback_to_jetpack_blog_token' => true,
990
991 'response_format' => array(
992 'formats' => '(object) An object of supported post formats, each key a supported format slug mapped to its display string.',
993 ),
994 )
995 );
996
997 /**
998 * List Post Formates endpoint class.
999 */
1000 class WPCOM_JSON_API_List_Post_Formats_Endpoint extends WPCOM_JSON_API_Endpoint { // phpcs:ignore
1001 /**
1002 *
1003 * API callback.
1004 *
1005 * /sites/%s/post-formats -> $blog_id
1006 *
1007 * @param string $path - the path.
1008 * @param int $blog_id - the blog ID.
1009 */
1010 public function callback( $path = '', $blog_id = 0 ) {
1011 $blog_id = $this->api->switch_to_blog_and_validate_user( $this->api->get_blog_id( $blog_id ) );
1012 if ( is_wp_error( $blog_id ) ) {
1013 return $blog_id;
1014 }
1015
1016 if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
1017 $this->load_theme_functions();
1018 }
1019
1020 // Get a list of supported post formats.
1021 $all_formats = get_post_format_strings();
1022 $supported = get_theme_support( 'post-formats' );
1023
1024 $response = array(
1025 'formats' => array(),
1026 );
1027 $supported_formats = $response['formats'];
1028
1029 if ( isset( $supported[0] ) ) {
1030 foreach ( $supported[0] as $format ) {
1031 $supported_formats[ $format ] = $all_formats[ $format ];
1032 }
1033 }
1034
1035 $response['formats'] = (object) $supported_formats;
1036
1037 return $response;
1038 }
1039 }
1040
1041 new WPCOM_JSON_API_List_Page_Templates_Endpoint(
1042 array(
1043 'description' => 'Get a list of page templates supported by a site.',
1044 'group' => 'sites',
1045 'stat' => 'sites:X:post-templates',
1046
1047 'method' => 'GET',
1048 'path' => '/sites/%s/page-templates',
1049 'path_labels' => array(
1050 '$site' => '(int|string) Site ID or domain',
1051 ),
1052 'query_parameters' => array(
1053 'context' => false,
1054 ),
1055 'response_format' => array(
1056 'templates' => '(array) A list of supported page templates. Contains label and file.',
1057 ),
1058 'example_request' => 'https://public-api.wordpress.com/rest/v1.1/sites/33534099/page-templates',
1059 )
1060 );
1061
1062 /**
1063 * List page templates endpoint class.
1064 */
1065 class WPCOM_JSON_API_List_Page_Templates_Endpoint extends WPCOM_JSON_API_Endpoint { // phpcs:ignore
1066 /**
1067 *
1068 * API callback.
1069 * /sites/%s/page-templates -> $blog_id
1070 *
1071 * @param string $path - the path.
1072 * @param int $blog_id - the blog ID.
1073 */
1074 public function callback( $path = '', $blog_id = 0 ) {
1075 $blog_id = $this->api->switch_to_blog_and_validate_user( $this->api->get_blog_id( $blog_id ) );
1076 if ( is_wp_error( $blog_id ) ) {
1077 return $blog_id;
1078 }
1079
1080 if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
1081 $this->load_theme_functions();
1082 }
1083
1084 $response = array();
1085 $page_templates = array();
1086
1087 $templates = get_page_templates();
1088 ksort( $templates );
1089
1090 foreach ( array_keys( $templates ) as $label ) {
1091 $page_templates[] = array(
1092 'label' => $label,
1093 'file' => $templates[ $label ],
1094 );
1095 }
1096
1097 $response['templates'] = $page_templates;
1098
1099 return $response;
1100 }
1101 }
1102