/json-endpoints/class.wpcom-json-api-get-site-endpoint.php

  1. <?php 
  2.  
  3. class WPCOM_JSON_API_GET_Site_Endpoint extends WPCOM_JSON_API_Endpoint { 
  4.  
  5. public static $site_format = array( 
  6. 'ID' => '(int) Site ID',  
  7. 'name' => '(string) Title of site',  
  8. 'description' => '(string) Tagline or description of site',  
  9. 'URL' => '(string) Full URL to the site',  
  10. 'jetpack' => '(bool) Whether the site is a Jetpack site or not',  
  11. 'post_count' => '(int) The number of posts the site has',  
  12. 'subscribers_count' => '(int) The number of subscribers the site has',  
  13. 'lang' => '(string) Primary language code of the site',  
  14. 'icon' => '(array) An array of icon formats for the site',  
  15. 'logo' => '(array) The site logo, set in the Customizer',  
  16. 'visible' => '(bool) If this site is visible in the user\'s site list',  
  17. 'is_private' => '(bool) If the site is a private site or not',  
  18. 'is_following' => '(bool) If the current user is subscribed to this site in the reader',  
  19. '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/',  
  20. 'updates' => '(array) An array of available updates for plugins, themes, wordpress, and languages.',  
  21. 'meta' => '(object) Meta data',  
  22. ); 
  23.  
  24. // /sites/mine 
  25. // /sites/%s -> $blog_id 
  26. function callback( $path = '', $blog_id = 0 ) { 
  27. global $wpdb; 
  28. if ( 'mine' === $blog_id ) { 
  29. $api = WPCOM_JSON_API::init(); 
  30. if ( !$api->token_details || empty( $api->token_details['blog_id'] ) ) { 
  31. return new WP_Error( 'authorization_required', 'An active access token must be used to query information about the current blog.', 403 ); 
  32. $blog_id = $api->token_details['blog_id']; 
  33.  
  34. $blog_id = $this->api->switch_to_blog_and_validate_user( $this->api->get_blog_id( $blog_id ) ); 
  35. if ( is_wp_error( $blog_id ) ) { 
  36. return $blog_id; 
  37.  
  38. $response = $this->build_current_site_response(); 
  39.  
  40. /** This action is documented in json-endpoints/class.wpcom-json-api-site-settings-endpoint.php */ 
  41. do_action( 'wpcom_json_api_objects', 'sites' ); 
  42.  
  43. return $response; 
  44.  
  45. /** 
  46. * Collects the necessary information to return for a site's response. 
  47. * 
  48. * @return (array) 
  49. */ 
  50. public function build_current_site_response( ) { 
  51.  
  52. global $wpdb, $wp_version; 
  53.  
  54. $response_format = self::$site_format; 
  55.  
  56. $is_user_logged_in = is_user_logged_in(); 
  57.  
  58. $visible = array(); 
  59.  
  60. if ( $is_user_logged_in ) { 
  61. $current_user = wp_get_current_user(); 
  62. $visible = get_user_meta( $current_user->ID, 'blog_visibility', true ); 
  63.  
  64. if ( !is_array( $visible ) ) 
  65. $visible = array(); 
  66.  
  67.  
  68. $blog_id = (int) $this->api->get_blog_id_for_output(); 
  69.  
  70. /** This filter is documented in class.json-api-endpoints.php */ 
  71. $is_jetpack = true === apply_filters( 'is_jetpack_site', false, $blog_id ); 
  72. $site_url = get_option( 'siteurl' ); 
  73.  
  74. if ( $is_jetpack ) { 
  75. remove_filter( 'option_stylesheet', 'fix_theme_location' ); 
  76. if ( 'https' !== parse_url( $site_url, PHP_URL_SCHEME ) ) { 
  77. add_filter( 'set_url_scheme', array( $this, 'force_http' ), 10, 3 ); 
  78. foreach ( array_keys( $response_format ) as $key ) { 
  79. switch ( $key ) { 
  80. case 'ID' : 
  81. $response[$key] = $blog_id; 
  82. break; 
  83. case 'name' : 
  84. $response[$key] = (string) htmlspecialchars_decode( get_bloginfo( 'name' ), ENT_QUOTES ); 
  85. break; 
  86. case 'description' : 
  87. $response[$key] = (string) htmlspecialchars_decode( get_bloginfo( 'description' ), ENT_QUOTES ); 
  88. break; 
  89. case 'URL' : 
  90. $response[$key] = (string) home_url(); 
  91. break; 
  92. case 'jetpack' : 
  93. $response[$key] = $is_jetpack; // jetpack magic affects this value 
  94. break; 
  95. case 'is_private' : 
  96. if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) { 
  97. $public_setting = get_option( 'blog_public' ); 
  98. if ( -1 == $public_setting ) 
  99. $response[$key] = true; 
  100. else 
  101. $response[$key] = false; 
  102. } else { 
  103. $response[$key] = false; // magic 
  104. break; 
  105. case 'visible' : 
  106. if ( $is_user_logged_in ) { 
  107. $is_visible = true; 
  108. if ( isset( $visible[$blog_id] ) ) { 
  109. $is_visible = (bool) $visible[$blog_id]; 
  110. // null and true are visible 
  111. $response[$key] = $is_visible; 
  112. break; 
  113. case 'post_count' : 
  114. if ( $is_user_logged_in ) 
  115. $response[$key] = (int) $wpdb->get_var("SELECT COUNT(*) FROM $wpdb->posts WHERE post_status = 'publish'"); 
  116. break; 
  117. case 'lang' : 
  118. if ( $is_user_logged_in ) 
  119. $response[$key] = (string) get_bloginfo( 'language' ); 
  120. break; 
  121. case 'icon' : 
  122. if ( function_exists( 'blavatar_domain' ) && function_exists( 'blavatar_exists' ) && function_exists( 'blavatar_url' ) ) { 
  123. $domain = blavatar_domain( home_url() ); 
  124. if ( blavatar_exists( $domain ) ) { 
  125. $response[ $key ] = array( 
  126. 'img' => (string) remove_query_arg( 's', blavatar_url( $domain, 'img' ) ),  
  127. 'ico' => (string) remove_query_arg( 's', blavatar_url( $domain, 'ico' ) ),  
  128. ); 
  129. } else { 
  130. // This is done so that we can access the updated blavatar on .com via the /me/sites endpoint 
  131. if( is_jetpack_site() ) { 
  132.  
  133. $site_icon_url = get_option( 'jetpack_site_icon_url' ); 
  134. if( $site_icon_url ) { 
  135. $response[ $key ] = array( 
  136. 'img' => (string) jetpack_photon_url( $site_icon_url, array() , 'https' ),  
  137. 'ico' => (string) jetpack_photon_url( $site_icon_url, array( 'w' => 16 ), 'https' ) 
  138. ); 
  139. } elseif ( function_exists( 'jetpack_site_icon_url' ) && function_exists( 'jetpack_photon_url' ) ) { 
  140. $response[ $key ] = array( 
  141. 'img' => (string) jetpack_photon_url( jetpack_site_icon_url( get_current_blog_id() , 80 ), array( 'w' => 80 ), 'https' ),  
  142. 'ico' => (string) jetpack_photon_url( jetpack_site_icon_url( get_current_blog_id() , 16 ), array( 'w' => 16 ), 'https' ),  
  143. ); 
  144. break; 
  145. case 'logo' : 
  146. // Set an empty response array. 
  147. $response[$key] = array( 
  148. 'id' => (int) 0,  
  149. 'sizes' => array(),  
  150. 'url' => '',  
  151. ); 
  152.  
  153. // Get current site logo values. 
  154. $logo = get_option( 'site_logo' ); 
  155.  
  156. // Update the response array if there's a site logo currenty active. 
  157. if ( $logo && 0 != $logo['id'] ) { 
  158. $response[$key]['id'] = $logo['id']; 
  159. $response[$key]['url'] = $logo['url']; 
  160.  
  161. foreach ( $logo['sizes'] as $size => $properties ) { 
  162. $response[$key]['sizes'][$size] = $properties; 
  163. break; 
  164. case 'subscribers_count' : 
  165.  
  166. if ( function_exists( 'wpcom_subs_total_wpcom_subscribers' ) ) { 
  167. $total_wpcom_subs = wpcom_subs_total_wpcom_subscribers( 
  168. array( 
  169. 'blog_id' => $blog_id,  
  170. ); 
  171. $response[$key] = $total_wpcom_subs; 
  172. } else { 
  173. $response[$key] = 0; // magic 
  174. break; 
  175. case 'is_following': 
  176. $response[$key] = (bool) $this->api->is_following( $blog_id ); 
  177. break; 
  178. case 'options': 
  179. // Figure out if the blog supports VideoPress, have to do some extra checking for JP blogs 
  180. $has_videopress = false; 
  181. if ( get_option( 'video_upgrade' ) == '1' ) { 
  182. $has_videopress = true; 
  183. } else { 
  184. if ( class_exists( 'Jetpack_Options' ) ) { 
  185. $videopress = Jetpack_Options::get_option( 'videopress', array() ); 
  186. if ( isset( $videopress['blog_id'] ) && $videopress['blog_id'] > 0 ) { 
  187. $has_videopress = true; 
  188.  
  189. // deprecated - see separate endpoint. get a list of supported post formats 
  190. $all_formats = get_post_format_strings(); 
  191. $supported = get_theme_support( 'post-formats' ); 
  192.  
  193. $supported_formats = array(); 
  194.  
  195. if ( isset( $supported[0] ) ) { 
  196. foreach ( $supported[0] as $format ) { 
  197. $supported_formats[ $format ] = $all_formats[ $format ]; 
  198.  
  199. // determine if sharing buttons should be visible by default 
  200. $default_sharing_status = false; 
  201. if ( class_exists( 'Sharing_Service' ) ) { 
  202. $ss = new Sharing_Service(); 
  203. $blog_services = $ss->get_blog_services(); 
  204. $default_sharing_status = ! empty( $blog_services['visible'] ); 
  205.  
  206. $is_mapped_domain = false; 
  207.  
  208. if ( function_exists( 'get_primary_redirect' ) ) { 
  209. $primary_redirect = strtolower( get_primary_redirect() ); 
  210. if ( false === strpos( $primary_redirect, '.wordpress.com' ) ) { 
  211. $is_mapped_domain = true; 
  212.  
  213. $is_redirect = false; 
  214.  
  215. if ( function_exists( 'get_primary_domain_mapping_record' ) ) { 
  216. if ( get_primary_domain_mapping_record()->type == 1 ) { 
  217. $is_redirect = true; 
  218.  
  219. if ( function_exists( 'get_mime_types' ) ) { 
  220. $allowed_file_types = get_mime_types(); 
  221. } else { 
  222. // http://codex.wordpress.org/Uploading_Files 
  223. $mime_types = get_allowed_mime_types(); 
  224. foreach ( $mime_types as $type => $mime_type ) { 
  225. $extras = explode( '|', $type ); 
  226. foreach ( $extras as $extra ) { 
  227. $allowed_file_types[] = $extra; 
  228.  
  229. if ( function_exists( 'get_blog_details' ) ) { 
  230. $blog_details = get_blog_details(); 
  231. if ( ! empty( $blog_details->registered ) ) { 
  232. $registered_date = $blog_details->registered; 
  233.  
  234. $upgraded_filetypes_enabled = false; 
  235. if ( $is_jetpack || get_option( 'use_upgraded_upload_filetypes' ) ) { 
  236. $upgraded_filetypes_enabled = true; 
  237.  
  238. $wordads = false; 
  239. if ( function_exists( 'has_any_blog_stickers' ) ) { 
  240. $wordads = has_any_blog_stickers( array( 'wordads-approved', 'wordads-approved-misfits' ), $blog_id ); 
  241.  
  242. $response[$key] = array( 
  243. 'timezone' => (string) get_option( 'timezone_string' ),  
  244. 'gmt_offset' => (float) get_option( 'gmt_offset' ),  
  245. 'videopress_enabled' => $has_videopress,  
  246. 'upgraded_filetypes_enabled' => $upgraded_filetypes_enabled,  
  247. 'login_url' => wp_login_url(),  
  248. 'admin_url' => get_admin_url(),  
  249. 'is_mapped_domain' => $is_mapped_domain,  
  250. 'is_redirect' => $is_redirect,  
  251. 'unmapped_url' => get_site_url( $blog_id ),  
  252. 'featured_images_enabled' => current_theme_supports( 'post-thumbnails' ),  
  253. 'theme_slug' => get_option( 'stylesheet' ),  
  254. 'header_image' => get_theme_mod( 'header_image_data' ),  
  255. 'background_color' => get_theme_mod( 'background_color' ),  
  256. 'image_default_link_type' => get_option( 'image_default_link_type' ),  
  257. 'image_thumbnail_width' => (int) get_option( 'thumbnail_size_w' ),  
  258. 'image_thumbnail_height' => (int) get_option( 'thumbnail_size_h' ),  
  259. 'image_thumbnail_crop' => get_option( 'thumbnail_crop' ),  
  260. 'image_medium_width' => (int) get_option( 'medium_size_w' ),  
  261. 'image_medium_height' => (int) get_option( 'medium_size_h' ),  
  262. 'image_large_width' => (int) get_option( 'large_size_w' ),  
  263. 'image_large_height' => (int) get_option( 'large_size_h' ),  
  264. 'permalink_structure' => get_option( 'permalink_structure' ),  
  265. 'post_formats' => $supported_formats,  
  266. 'default_post_format' => get_option( 'default_post_format' ),  
  267. 'default_category' => (int) get_option( 'default_category' ),  
  268. 'allowed_file_types' => $allowed_file_types,  
  269. 'show_on_front' => get_option( 'show_on_front' ),  
  270. /** This filter is documented in modules/likes.php */ 
  271. 'default_likes_enabled' => (bool) apply_filters( 'wpl_is_enabled_sitewide', ! get_option( 'disabled_likes' ) ),  
  272. 'default_sharing_status' => (bool) $default_sharing_status,  
  273. 'default_comment_status' => ( 'closed' == get_option( 'default_comment_status' ) ? false : true ),  
  274. 'default_ping_status' => ( 'closed' == get_option( 'default_ping_status' ) ? false : true ),  
  275. 'software_version' => $wp_version,  
  276. 'created_at' => ! empty( $registered_date ) ? $this->format_date( $registered_date ) : '0000-00-00T00:00:00+00:00',  
  277. 'wordads' => $wordads,  
  278. ); 
  279.  
  280. if ( 'page' === get_option( 'show_on_front' ) ) { 
  281. $response['options']['page_on_front'] = (int) get_option( 'page_on_front' ); 
  282. $response['options']['page_for_posts'] = (int) get_option( 'page_for_posts' ); 
  283.  
  284. if ( $is_jetpack ) { 
  285. $response['options']['jetpack_version'] = get_option( 'jetpack_version' ); 
  286.  
  287. if ( get_option( 'jetpack_main_network_site' ) ) { 
  288. $response['options']['main_network_site'] = (string) rtrim( get_option( 'jetpack_main_network_site' ), '/' ); 
  289.  
  290. if ( is_array( Jetpack_Options::get_option( 'active_modules' ) ) ) { 
  291. $response['options']['active_modules'] = (array) array_values( Jetpack_Options::get_option( 'active_modules' ) ); 
  292.  
  293. if ( $jetpack_wp_version = get_option( 'jetpack_wp_version' ) ) { 
  294. $response['options']['software_version'] = (string) $jetpack_wp_version; 
  295. } else if ( $jetpack_update = get_option( 'jetpack_updates' ) ) { 
  296. if ( is_array( $jetpack_update ) && isset( $jetpack_update['wp_version'] ) ) { 
  297. $response['options']['software_version'] = (string) $jetpack_update['wp_version']; 
  298. } else { 
  299. $response[ 'options' ][ 'software_version' ] = null; 
  300. } else { 
  301. $response['options']['software_version'] = null; 
  302.  
  303. $response['options']['max_upload_size'] = get_option( 'jetpack_max_upload_size', false ); 
  304.  
  305. // Sites have to prove that they are not main_network site. 
  306. // If the sync happends right then we should be able to see that we are not dealing with a network site 
  307. $response['options']['is_multi_network'] = (bool) get_option( 'jetpack_is_main_network', true ); 
  308. $response['options']['is_multi_site'] = (bool) get_option( 'jetpack_is_multi_site', true ); 
  309.  
  310.  
  311. if ( ! current_user_can( 'edit_posts' ) ) 
  312. unset( $response[$key] ); 
  313. break; 
  314. case 'meta' : 
  315. /** 
  316. * Filters the URL scheme used when querying your site's REST API endpoint. 
  317. * 
  318. * @module json-api 
  319. * 
  320. * @since 3.2.0 
  321. * 
  322. * @param string parse_url( get_option( 'home' ), PHP_URL_SCHEME ) URL scheme parsed from home URL. 
  323. */ 
  324. $xmlrpc_scheme = apply_filters( 'wpcom_json_api_xmlrpc_scheme', parse_url( get_option( 'home' ), PHP_URL_SCHEME ) ); 
  325. $xmlrpc_url = site_url( 'xmlrpc.php', $xmlrpc_scheme ); 
  326. $response[$key] = (object) array( 
  327. 'links' => (object) array( 
  328. 'self' => (string) $this->get_site_link( $blog_id ),  
  329. 'help' => (string) $this->get_site_link( $blog_id, 'help' ),  
  330. 'posts' => (string) $this->get_site_link( $blog_id, 'posts/' ),  
  331. 'comments' => (string) $this->get_site_link( $blog_id, 'comments/' ),  
  332. 'xmlrpc' => (string) $xmlrpc_url,  
  333. ),  
  334. ); 
  335. break; 
  336.  
  337. if ( $is_jetpack ) { 
  338.  
  339. // Add the updates only make them visible if the user has manage options permission. 
  340. $jetpack_update = (array) get_option( 'jetpack_updates' ); 
  341. if ( ! empty( $jetpack_update ) && current_user_can( 'manage_options' ) ) { 
  342.  
  343. if ( isset( $jetpack_update['wp_version'] ) ) { 
  344. // In previous version of Jetpack 3.4, 3.5, 3.6 we synced the wp_version into to jetpack_updates 
  345. unset( $jetpack_update['wp_version'] ); 
  346.  
  347. if ( isset( $jetpack_update['site_is_version_controlled'] ) ) { 
  348. // In previous version of Jetpack 3.4, 3.5, 3.6 we synced the site_is_version_controlled into to jetpack_updates 
  349. unset( $jetpack_update['site_is_version_controlled'] ); 
  350.  
  351. $response['updates'] = (array) $jetpack_update; 
  352.  
  353. add_filter( 'option_stylesheet', 'fix_theme_location' ); 
  354. if ( 'https' !== parse_url( $site_url, PHP_URL_SCHEME ) ) { 
  355. remove_filter( 'set_url_scheme', array( $this, 'force_http' ), 10, 3 ); 
  356.  
  357. return $response; 
  358.  
  359.  
  360. function force_http( $url, $scheme, $orig_scheme ) { 
  361. return preg_replace('/^https:\/\//', 'http://', $url, 1 ); 
  362.  
  363.  
  364. class WPCOM_JSON_API_List_Post_Formats_Endpoint extends WPCOM_JSON_API_Endpoint { 
  365. // /sites/%s/post-formats -> $blog_id 
  366. function callback( $path = '', $blog_id = 0 ) { 
  367. $blog_id = $this->api->switch_to_blog_and_validate_user( $this->api->get_blog_id( $blog_id ) ); 
  368. if ( is_wp_error( $blog_id ) ) { 
  369. return $blog_id; 
  370.  
  371. if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) { 
  372. $this->load_theme_functions(); 
  373.  
  374. // Get a list of supported post formats. 
  375. $all_formats = get_post_format_strings(); 
  376. $supported = get_theme_support( 'post-formats' ); 
  377.  
  378. $supported_formats = $response['formats'] = array(); 
  379.  
  380. if ( isset( $supported[0] ) ) { 
  381. foreach ( $supported[0] as $format ) { 
  382. $supported_formats[ $format ] = $all_formats[ $format ]; 
  383.  
  384. $response['formats'] = (object) $supported_formats; 
  385.  
  386. return $response; 
  387.  
  388. class WPCOM_JSON_API_List_Page_Templates_Endpoint extends WPCOM_JSON_API_Endpoint { 
  389. // /sites/%s/page-templates -> $blog_id 
  390. function callback( $path = '', $blog_id = 0 ) { 
  391. $blog_id = $this->api->switch_to_blog_and_validate_user( $this->api->get_blog_id( $blog_id ) ); 
  392. if ( is_wp_error( $blog_id ) ) { 
  393. return $blog_id; 
  394.  
  395. if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) { 
  396. $this->load_theme_functions(); 
  397.  
  398. $response = array(); 
  399. $page_templates = array(); 
  400.  
  401. $templates = get_page_templates(); 
  402. ksort( $templates ); 
  403.  
  404. foreach ( array_keys( $templates ) as $label ) { 
  405. $page_templates[] = array( 
  406. 'label' => $label,  
  407. 'file' => $templates[ $label ] 
  408. ); 
  409.  
  410. $response['templates'] = $page_templates; 
  411.  
  412. return $response; 
  413.  
  414. class WPCOM_JSON_API_List_Post_Types_Endpoint extends WPCOM_JSON_API_Endpoint { 
  415. static $post_type_keys_to_include = array( 
  416. 'name' => 'name',  
  417. 'label' => 'label',  
  418. 'labels' => 'labels',  
  419. 'description' => 'description',  
  420. 'map_meta_cap' => 'map_meta_cap',  
  421. 'cap' => 'capabilities',  
  422. ); 
  423.  
  424. // /sites/%s/post-types -> $blog_id 
  425. function callback( $path = '', $blog_id = 0 ) { 
  426. $blog_id = $this->api->switch_to_blog_and_validate_user( $this->api->get_blog_id( $blog_id ) ); 
  427. if ( is_wp_error( $blog_id ) ) { 
  428. return $blog_id; 
  429.  
  430. if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) { 
  431. $this->load_theme_functions(); 
  432.  
  433. $args = $this->query_args(); 
  434. $queryable_only = isset( $args['api_queryable'] ) && $args['api_queryable']; 
  435.  
  436. // Get a list of available post types 
  437. $post_types = get_post_types( array( 'public' => true ) ); 
  438. $formatted_post_type_objects = array(); 
  439.  
  440. // Retrieve post type object for each post type 
  441. foreach ( $post_types as $post_type ) { 
  442. // Skip non-queryable if filtering on queryable only 
  443. $is_queryable = $this->is_post_type_allowed( $post_type ); 
  444. if ( $queryable_only && ! $is_queryable ) { 
  445. continue; 
  446.  
  447. $post_type_object = get_post_type_object( $post_type ); 
  448. $formatted_post_type_object = array(); 
  449.  
  450. // Include only the desired keys in the response 
  451. foreach ( self::$post_type_keys_to_include as $key => $value ) { 
  452. $formatted_post_type_object[ $value ] = $post_type_object->{ $key }; 
  453. $formatted_post_type_object['api_queryable'] = $is_queryable; 
  454. $formatted_post_type_object['supports'] = get_all_post_type_supports( $post_type ); 
  455. $formatted_post_type_objects[] = $formatted_post_type_object; 
  456.  
  457. return array( 
  458. 'found' => count( $formatted_post_type_objects ),  
  459. 'post_types' => $formatted_post_type_objects 
  460. ); 
.