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

  1. <?php 
  2.  
  3. class WPCOM_JSON_API_Site_Settings_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. 'lang' => '(string) Primary language code of the site',  
  11. 'settings' => '(array) An array of options/settings for the blog. Only viewable by users with post editing rights to the site.',  
  12. ); 
  13.  
  14. // GET /sites/%s/settings 
  15. // POST /sites/%s/settings 
  16. function callback( $path = '', $blog_id = 0 ) { 
  17. $blog_id = $this->api->switch_to_blog_and_validate_user( $this->api->get_blog_id( $blog_id ) ); 
  18. if ( is_wp_error( $blog_id ) ) { 
  19. return $blog_id; 
  20.  
  21. if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) { 
  22. $this->load_theme_functions(); 
  23.  
  24. if ( ! is_user_logged_in() ) { 
  25. return new WP_Error( 'Unauthorized', 'You must be logged-in to manage settings.', 401 ); 
  26. } else if ( ! current_user_can( 'manage_options' ) ) { 
  27. return new WP_Error( 'Forbidden', 'You do not have the capability to manage settings for this site.', 403 ); 
  28.  
  29. if ( 'GET' === $this->api->method ) { 
  30. /** 
  31. * Fires on each GET request to a specific endpoint. 
  32. * 
  33. * @module json-api 
  34. * 
  35. * @since 3.2.0 
  36. * 
  37. * @param string sites. 
  38. */ 
  39. do_action( 'wpcom_json_api_objects', 'sites' ); 
  40. return $this->get_settings_response(); 
  41. } else if ( 'POST' === $this->api->method ) { 
  42. return $this->update_settings(); 
  43. } else { 
  44. return new WP_Error( 'bad_request', 'An unsupported request method was used.' ); 
  45.  
  46.  
  47. /** 
  48. * Determines whether jetpack_relatedposts is supported 
  49. * 
  50. * @return (bool) 
  51. */ 
  52. public function jetpack_relatedposts_supported() { 
  53. $wpcom_related_posts_theme_blacklist = array( 
  54. 'Expound',  
  55. 'Traveler',  
  56. 'Opti',  
  57. 'Currents',  
  58. ); 
  59. return ( ! in_array( wp_get_theme()->get( 'Name' ), $wpcom_related_posts_theme_blacklist ) ); 
  60.  
  61. /** 
  62. * Returns category details 
  63. * 
  64. * @return (array) 
  65. */ 
  66. public function get_category_details( $category ) { 
  67. return array( 
  68. 'value' => $category->term_id,  
  69. 'name' => $category->name 
  70. ); 
  71.  
  72. /** 
  73. * Collects the necessary information to return for a get settings response. 
  74. * 
  75. * @return (array) 
  76. */ 
  77. public function get_settings_response() { 
  78.  
  79. $response_format = self::$site_format; 
  80. $blog_id = (int) $this->api->get_blog_id_for_output(); 
  81. /** This filter is documented in class.json-api-endpoints.php */ 
  82. $is_jetpack = true === apply_filters( 'is_jetpack_site', false, $blog_id ); 
  83.  
  84. foreach ( array_keys( $response_format ) as $key ) { 
  85. switch ( $key ) { 
  86. case 'ID' : 
  87. $response[$key] = $blog_id; 
  88. break; 
  89. case 'name' : 
  90. $response[$key] = (string) htmlspecialchars_decode( get_bloginfo( 'name' ), ENT_QUOTES ); 
  91. break; 
  92. case 'description' : 
  93. $response[$key] = (string) htmlspecialchars_decode( get_bloginfo( 'description' ), ENT_QUOTES ); 
  94. break; 
  95. case 'URL' : 
  96. $response[$key] = (string) home_url(); 
  97. break; 
  98. case 'lang' : 
  99. $response[$key] = (string) get_bloginfo( 'language' ); 
  100. break; 
  101. case 'settings': 
  102.  
  103. $jetpack_relatedposts_options = Jetpack_Options::get_option( 'relatedposts' ); 
  104.  
  105. if ( method_exists( 'Jetpack', 'is_module_active' ) ) { 
  106. $jetpack_relatedposts_options[ 'enabled' ] = Jetpack::is_module_active( 'related-posts' ); 
  107.  
  108. // array_values() is necessary to ensure the array starts at index 0. 
  109. $post_categories = array_values( 
  110. array_map( 
  111. array( $this, 'get_category_details' ),  
  112. get_categories( array( 'hide_empty' => false ) ) 
  113. ); 
  114.  
  115. $eventbrite_api_token = (int) get_option( 'eventbrite_api_token' ); 
  116. if ( 0 === $eventbrite_api_token ) { 
  117. $eventbrite_api_token = null; 
  118.  
  119. $response[$key] = array( 
  120.  
  121. // also exists as "options" 
  122. 'admin_url' => get_admin_url(),  
  123. 'default_ping_status' => (bool) ( 'closed' != get_option( 'default_ping_status' ) ),  
  124. 'default_comment_status' => (bool) ( 'closed' != get_option( 'default_comment_status' ) ),  
  125.  
  126. // new stuff starts here 
  127. 'blog_public' => (int) get_option( 'blog_public' ),  
  128. 'jetpack_sync_non_public_post_stati' => (bool) Jetpack_Options::get_option( 'sync_non_public_post_stati' ),  
  129. 'jetpack_relatedposts_allowed' => (bool) $this->jetpack_relatedposts_supported(),  
  130. 'jetpack_relatedposts_enabled' => (bool) $jetpack_relatedposts_options[ 'enabled' ],  
  131. 'jetpack_relatedposts_show_headline' => (bool) $jetpack_relatedposts_options[ 'show_headline' ],  
  132. 'jetpack_relatedposts_show_thumbnails' => (bool) $jetpack_relatedposts_options[ 'show_thumbnails' ],  
  133. 'default_category' => (int) get_option('default_category'),  
  134. 'post_categories' => (array) $post_categories,  
  135. 'default_post_format' => get_option( 'default_post_format' ),  
  136. 'default_pingback_flag' => (bool) get_option( 'default_pingback_flag' ),  
  137. 'require_name_email' => (bool) get_option( 'require_name_email' ),  
  138. 'comment_registration' => (bool) get_option( 'comment_registration' ),  
  139. 'close_comments_for_old_posts' => (bool) get_option( 'close_comments_for_old_posts' ),  
  140. 'close_comments_days_old' => (int) get_option( 'close_comments_days_old' ),  
  141. 'thread_comments' => (bool) get_option( 'thread_comments' ),  
  142. 'thread_comments_depth' => (int) get_option( 'thread_comments_depth' ),  
  143. 'page_comments' => (bool) get_option( 'page_comments' ),  
  144. 'comments_per_page' => (int) get_option( 'comments_per_page' ),  
  145. 'default_comments_page' => get_option( 'default_comments_page' ),  
  146. 'comment_order' => get_option( 'comment_order' ),  
  147. 'comments_notify' => (bool) get_option( 'comments_notify' ),  
  148. 'moderation_notify' => (bool) get_option( 'moderation_notify' ),  
  149. 'social_notifications_like' => ( "on" == get_option( 'social_notifications_like' ) ),  
  150. 'social_notifications_reblog' => ( "on" == get_option( 'social_notifications_reblog' ) ),  
  151. 'social_notifications_subscribe' => ( "on" == get_option( 'social_notifications_subscribe' ) ),  
  152. 'comment_moderation' => (bool) get_option( 'comment_moderation' ),  
  153. 'comment_whitelist' => (bool) get_option( 'comment_whitelist' ),  
  154. 'comment_max_links' => (int) get_option( 'comment_max_links' ),  
  155. 'moderation_keys' => get_option( 'moderation_keys' ),  
  156. 'blacklist_keys' => get_option( 'blacklist_keys' ),  
  157. 'lang_id' => get_option( 'lang_id' ),  
  158. 'wga' => get_option( 'wga' ),  
  159. 'disabled_likes' => (bool) get_option( 'disabled_likes' ),  
  160. 'disabled_reblogs' => (bool) get_option( 'disabled_reblogs' ),  
  161. 'jetpack_comment_likes_enabled' => (bool) get_option( 'jetpack_comment_likes_enabled', false ),  
  162. 'twitter_via' => (string) get_option( 'twitter_via' ),  
  163. 'jetpack-twitter-cards-site-tag' => (string) get_option( 'jetpack-twitter-cards-site-tag' ),  
  164. 'eventbrite_api_token' => $eventbrite_api_token,  
  165. ); 
  166.  
  167. if ( class_exists( 'Sharing_Service' ) ) { 
  168. $ss = new Sharing_Service(); 
  169. $sharing = $ss->get_global_options(); 
  170. $response[ $key ]['sharing_button_style'] = (string) $sharing['button_style']; 
  171. $response[ $key ]['sharing_label'] = (string) $sharing['sharing_label']; 
  172. $response[ $key ]['sharing_show'] = (array) $sharing['show']; 
  173. $response[ $key ]['sharing_open_links'] = (string) $sharing['open_links']; 
  174.  
  175. if ( function_exists( 'jetpack_protect_format_whitelist' ) ) { 
  176. $response[ $key ]['jetpack_protect_whitelist'] = jetpack_protect_format_whitelist(); 
  177.  
  178. if ( ! current_user_can( 'edit_posts' ) ) 
  179. unset( $response[$key] ); 
  180. break; 
  181.  
  182. return $response; 
  183.  
  184.  
  185. /** 
  186. * Updates site settings for authorized users 
  187. * 
  188. * @return (array) 
  189. */ 
  190. public function update_settings() { 
  191.  
  192. // $this->input() retrieves posted arguments whitelisted and casted to the $request_format 
  193. // specs that get passed in when this class is instantiated 
  194. /** 
  195. * Filters the settings to be updated on the site. 
  196. * 
  197. * @module json-api 
  198. * 
  199. * @since 3.6.0 
  200. * 
  201. * @param array $input Associative array of site settings to be updated. 
  202. */ 
  203. $input = apply_filters( 'rest_api_update_site_settings', $this->input() ); 
  204.  
  205. $jetpack_relatedposts_options = array(); 
  206. $sharing_options = array(); 
  207. $updated = array(); 
  208.  
  209. foreach ( $input as $key => $value ) { 
  210.  
  211. if ( ! is_array( $value ) ) { 
  212. $value = trim( $value ); 
  213. $value = wp_unslash( $value ); 
  214.  
  215. switch ( $key ) { 
  216.  
  217. case 'default_ping_status': 
  218. case 'default_comment_status': 
  219. // settings are stored as closed|open 
  220. $coerce_value = ( $value ) ? 'open' : 'closed'; 
  221. if ( update_option( $key, $coerce_value ) ) { 
  222. $updated[ $key ] = $value; 
  223. }; 
  224. break; 
  225. case 'jetpack_protect_whitelist': 
  226. if ( function_exists( 'jetpack_protect_save_whitelist' ) ) { 
  227. $result = jetpack_protect_save_whitelist( $value ); 
  228. if ( is_wp_error( $result ) ) { 
  229. return $result; 
  230. $updated[ $key ] = jetpack_protect_format_whitelist(); 
  231. break; 
  232. case 'jetpack_sync_non_public_post_stati': 
  233. Jetpack_Options::update_option( 'sync_non_public_post_stati', $value ); 
  234. break; 
  235. case 'jetpack_relatedposts_enabled': 
  236. case 'jetpack_relatedposts_show_thumbnails': 
  237. case 'jetpack_relatedposts_show_headline': 
  238. if ( ! $this->jetpack_relatedposts_supported() ) { 
  239. break; 
  240. if ( 'jetpack_relatedposts_enabled' === $key && method_exists( 'Jetpack', 'is_module_active' ) && $this->jetpack_relatedposts_supported() ) { 
  241. $before_action = Jetpack::is_module_active('related-posts'); 
  242. if ( $value ) { 
  243. Jetpack::activate_module( 'related-posts', false, false ); 
  244. } else { 
  245. Jetpack::deactivate_module( 'related-posts' ); 
  246. $after_action = Jetpack::is_module_active('related-posts'); 
  247. if ( $after_action == $before_action ) { 
  248. break; 
  249. $just_the_key = substr( $key, 21 ); 
  250. $jetpack_relatedposts_options[ $just_the_key ] = $value; 
  251. break; 
  252.  
  253. case 'social_notifications_like': 
  254. case 'social_notifications_reblog': 
  255. case 'social_notifications_subscribe': 
  256. // settings are stored as on|off 
  257. $coerce_value = ( $value ) ? 'on' : 'off'; 
  258. if ( update_option( $key, $coerce_value ) ) { 
  259. $updated[ $key ] = $value; 
  260. break; 
  261. case 'wga': 
  262. if ( ! isset( $value['code'] ) || ! preg_match( '/^$|^UA-[\d-]+$/i', $value['code'] ) ) { 
  263. return new WP_Error( 'invalid_code', 'Invalid UA ID' ); 
  264. $wga = get_option( 'wga', array() ); 
  265. $wga['code'] = $value['code']; // maintain compatibility with wp-google-analytics 
  266. if ( update_option( 'wga', $wga ) ) { 
  267. $updated[ $key ] = $value; 
  268.  
  269. $enabled_or_disabled = $wga['code'] ? 'enabled' : 'disabled'; 
  270.  
  271. /** This action is documented in modules/widgets/social-media-icons.php */ 
  272. do_action( 'jetpack_bump_stats_extras', 'google-analytics', $enabled_or_disabled ); 
  273.  
  274. $business_plugins = WPCOM_Business_Plugins::instance(); 
  275. $business_plugins->activate_plugin( 'wp-google-analytics' ); 
  276. break; 
  277.  
  278. case 'jetpack_comment_likes_enabled': 
  279. // settings are stored as 1|0 
  280. $coerce_value = (int) $value; 
  281. if ( update_option( $key, $coerce_value ) ) { 
  282. $updated[ $key ] = $value; 
  283. break; 
  284.  
  285. // Sharing options 
  286. case 'sharing_button_style': 
  287. case 'sharing_show': 
  288. case 'sharing_open_links': 
  289. $sharing_options[ preg_replace( '/^sharing_/', '', $key ) ] = $value; 
  290. break; 
  291. case 'sharing_label': 
  292. $sharing_options[ $key ] = $value; 
  293. break; 
  294.  
  295. // Keyring token option 
  296. case 'eventbrite_api_token': 
  297. // These options can only be updated for sites hosted on WordPress.com 
  298. if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) { 
  299. if ( empty( $value ) || WPCOM_JSON_API::is_falsy( $value ) ) { 
  300. if ( delete_option( $key ) ) { 
  301. $updated[ $key ] = null; 
  302. } else if ( update_option( $key, $value ) ) { 
  303. $updated[ $key ] = (int) $value; 
  304. break; 
  305.  
  306. // no worries, we've already whitelisted and casted arguments above 
  307. default: 
  308. if ( update_option( $key, $value ) ) { 
  309. $updated[ $key ] = $value; 
  310.  
  311.  
  312. if ( count( $jetpack_relatedposts_options ) ) { 
  313. // track new jetpack_relatedposts options against old 
  314. $old_relatedposts_options = Jetpack_Options::get_option( 'relatedposts' ); 
  315. if ( Jetpack_Options::update_option( 'relatedposts', $jetpack_relatedposts_options ) ) { 
  316. foreach( $jetpack_relatedposts_options as $key => $value ) { 
  317. if ( $value !== $old_relatedposts_options[ $key ] ) { 
  318. $updated[ 'jetpack_relatedposts_' . $key ] = $value; 
  319.  
  320. if ( ! empty( $sharing_options ) && class_exists( 'Sharing_Service' ) ) { 
  321. $ss = new Sharing_Service(); 
  322.  
  323. // Merge current values with updated, since Sharing_Service expects 
  324. // all values to be included when updating 
  325. $current_sharing_options = $ss->get_global_options(); 
  326. foreach ( $current_sharing_options as $key => $val ) { 
  327. if ( ! isset( $sharing_options[ $key ] ) ) { 
  328. $sharing_options[ $key ] = $val; 
  329.  
  330. $updated_social_options = $ss->set_global_options( $sharing_options ); 
  331.  
  332. if ( isset( $input['sharing_button_style'] ) ) { 
  333. $updated['sharing_button_style'] = (string) $updated_social_options['button_style']; 
  334. if ( isset( $input['sharing_label'] ) ) { 
  335. // Sharing_Service won't report label as updated if set to default 
  336. $updated['sharing_label'] = (string) $sharing_options['sharing_label']; 
  337. if ( isset( $input['sharing_show'] ) ) { 
  338. $updated['sharing_show'] = (array) $updated_social_options['show']; 
  339. if ( isset( $input['sharing_open_links'] ) ) { 
  340. $updated['sharing_open_links'] = (string) $updated_social_options['open_links']; 
  341.  
  342. return array( 
  343. 'updated' => $updated 
  344. ); 
  345.  
.