PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.3-a.1
Jetpack – WP Security, Backup, Speed, & Growth v16.3-a.1
16.3 16.3-beta 16.3-a.5 16.3-a.7 16.3-a.3 16.3-a.1 16.2 16.2-beta 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 All 508 releases
← All changes | _inc/lib/class.core-rest-api-endpoints.php +395 -17 16.3 → 16.3-a.1 View file →
@@ -549,8 +549,103 @@
549 549 ),
550 550 )
551 551 );
552 552
553 + register_rest_route(
554 + 'jetpack/v4',
555 + '/recommendations/data',
556 + array(
557 + array(
558 + 'methods' => WP_REST_Server::READABLE,
559 + 'callback' => __CLASS__ . '::get_recommendations_data',
560 + 'permission_callback' => __CLASS__ . '::update_settings_permission_check',
561 + ),
562 + array(
563 + 'methods' => WP_REST_Server::EDITABLE,
564 + 'callback' => __CLASS__ . '::update_recommendations_data',
565 + 'permission_callback' => __CLASS__ . '::update_settings_permission_check',
566 + 'args' => array(
567 + 'data' => array(
568 + 'required' => true,
569 + 'type' => 'object',
570 + 'validate_callback' => __CLASS__ . '::validate_recommendations_data',
571 + ),
572 + ),
573 + ),
574 + )
575 + );
576 +
577 + register_rest_route(
578 + 'jetpack/v4',
579 + '/recommendations/step',
580 + array(
581 + array(
582 + 'methods' => WP_REST_Server::READABLE,
583 + 'callback' => __CLASS__ . '::get_recommendations_step',
584 + 'permission_callback' => __CLASS__ . '::update_settings_permission_check',
585 + ),
586 + array(
587 + 'methods' => WP_REST_Server::EDITABLE,
588 + 'callback' => __CLASS__ . '::update_recommendations_step',
589 + 'permission_callback' => __CLASS__ . '::update_settings_permission_check',
590 + 'args' => array(
591 + 'step' => array(
592 + 'required' => true,
593 + 'type' => 'string',
594 + 'validate_callback' => __CLASS__ . '::validate_string',
595 + ),
596 + ),
597 + ),
598 + )
599 + );
600 +
601 + register_rest_route(
602 + 'jetpack/v4',
603 + '/recommendations/product-suggestions',
604 + array(
605 + array(
606 + 'methods' => WP_REST_Server::READABLE,
607 + 'callback' => __CLASS__ . '::get_recommendations_product_suggestions',
608 + 'permission_callback' => __CLASS__ . '::view_admin_page_permission_check',
609 + ),
610 + )
611 + );
612 +
613 + register_rest_route(
614 + 'jetpack/v4',
615 + '/recommendations/upsell',
616 + array(
617 + array(
618 + 'methods' => WP_REST_Server::READABLE,
619 + 'callback' => __CLASS__ . '::get_recommendations_upsell',
620 + 'permission_callback' => __CLASS__ . '::view_admin_page_permission_check',
621 + ),
622 + )
623 + );
624 +
625 + register_rest_route(
626 + 'jetpack/v4',
627 + '/recommendations/conditional',
628 + array(
629 + array(
630 + 'methods' => WP_REST_Server::READABLE,
631 + 'callback' => __CLASS__ . '::get_conditional_recommendations',
632 + 'permission_callback' => __CLASS__ . '::view_admin_page_permission_check',
633 + ),
634 + )
635 + );
636 +
637 + // Get site discount.
638 + register_rest_route(
639 + 'jetpack/v4',
640 + '/site/discount',
641 + array(
642 + 'methods' => WP_REST_Server::READABLE,
643 + 'callback' => __CLASS__ . '::get_site_discount',
644 + 'permission_callback' => __CLASS__ . '::view_admin_page_permission_check',
645 + )
646 + );
647 +
553 648 /*
554 649 * Manage the Jetpack CRM plugin's integration with Jetpack contact forms.
555 650 */
556 651 register_rest_route(
@@ -605,8 +700,19 @@
605 700 'permission_callback' => __CLASS__ . '::manage_modules_permission_check',
606 701 )
607 702 );
608 703
704 + // Get Jetpack introduction offers
705 + register_rest_route(
706 + 'jetpack/v4',
707 + '/intro-offers',
708 + array(
709 + 'methods' => WP_REST_Server::READABLE,
710 + 'callback' => __CLASS__ . '::get_intro_offers',
711 + 'permission_callback' => __CLASS__ . '::view_admin_page_permission_check',
712 + )
713 + );
714 +
609 715 // Save subscriber token and redirect
610 716 register_rest_route(
611 717 'jetpack/v4',
612 718 '/subscribers/auth',
@@ -707,8 +813,181 @@
707 813 return new WP_REST_Response( null, 302, array( 'location' => $redirect_url ) );
708 814 }
709 815
710 816 /**
817 + * Get the data for the recommendations
818 + *
819 + * @return array Recommendations data
820 + */
821 + public static function get_recommendations_data() {
822 + return Jetpack_Recommendations::get_recommendations_data();
823 + }
824 +
825 + /**
826 + * Update the data for the recommendations
827 + *
828 + * @param WP_REST_Request $request The request.
829 + *
830 + * @return bool true
831 + */
832 + public static function update_recommendations_data( $request ) {
833 + $data = $request['data'];
834 + Jetpack_Recommendations::update_recommendations_data( $data );
835 +
836 + return true;
837 + }
838 +
839 + /**
840 + * Get the data for the recommendations
841 + *
842 + * @return array Recommendations data
843 + */
844 + public static function get_recommendations_step() {
845 + return Jetpack_Recommendations::get_recommendations_step();
846 + }
847 +
848 + /**
849 + * Update the step for the recommendations
850 + *
851 + * @param WP_REST_Request $request The request.
852 + *
853 + * @return bool true
854 + */
855 + public static function update_recommendations_step( $request ) {
856 + $step = $request['step'];
857 + Jetpack_Recommendations::update_recommendations_step( $step );
858 +
859 + return true;
860 + }
861 +
862 + /**
863 + * Get product suggestions for the recommendations
864 + *
865 + * @return string|WP_Error The response from the wpcom product suggestions endpoint as a JSON object.
866 + */
867 + public static function get_recommendations_product_suggestions() {
868 + $blog_id = Jetpack_Options::get_option( 'id' );
869 + if ( ! $blog_id ) {
870 + return new WP_Error( 'site_not_registered', esc_html__( 'Site not registered.', 'jetpack' ) );
871 + }
872 +
873 + $user_connected = ( new Connection_Manager( 'jetpack' ) )->is_user_connected( get_current_user_id() );
874 + if ( ! $user_connected ) {
875 + return wp_json_encode( array(), JSON_UNESCAPED_SLASHES );
876 + }
877 +
878 + $request_path = sprintf( '/sites/%s/jetpack-recommendations/product-suggestions?locale=' . get_user_locale(), $blog_id );
879 + $wpcom_request = Client::wpcom_json_api_request_as_user(
880 + $request_path,
881 + '2',
882 + array(
883 + 'method' => 'GET',
884 + 'headers' => array(
885 + 'X-Forwarded-For' => ( new Visitor() )->get_ip( true ),
886 + ),
887 + )
888 + );
889 +
890 + $response_code = wp_remote_retrieve_response_code( $wpcom_request );
891 + if ( 200 === $response_code ) {
892 + return json_decode( wp_remote_retrieve_body( $wpcom_request ) );
893 + } else {
894 + return new WP_Error(
895 + 'failed_to_fetch_data',
896 + esc_html__( 'Unable to fetch the requested data.', 'jetpack' ),
897 + array( 'status' => $response_code )
898 + );
899 + }
900 + }
901 +
902 + /**
903 + * Get the upsell for the recommendations
904 + *
905 + * @return string The response from the wpcom upsell endpoint as a JSON object
906 + */
907 + public static function get_recommendations_upsell() {
908 + $blog_id = Jetpack_Options::get_option( 'id' );
909 + if ( ! $blog_id ) {
910 + return new WP_Error( 'site_not_registered', esc_html__( 'Site not registered.', 'jetpack' ) );
911 + }
912 +
913 + $user_connected = ( new Connection_Manager( 'jetpack' ) )->is_user_connected( get_current_user_id() );
914 + if ( ! $user_connected ) {
915 + $response = array(
916 + 'hide_upsell' => true,
917 + );
918 +
919 + return $response;
920 + }
921 +
922 + $request_path = sprintf( '/sites/%s/jetpack-recommendations/upsell?locale=' . get_user_locale(), $blog_id );
923 + $wpcom_request = Client::wpcom_json_api_request_as_user(
924 + $request_path,
925 + '2',
926 + array(
927 + 'method' => 'GET',
928 + 'headers' => array(
929 + 'X-Forwarded-For' => ( new Visitor() )->get_ip( true ),
930 + ),
931 + )
932 + );
933 +
934 + $response_code = wp_remote_retrieve_response_code( $wpcom_request );
935 + if ( 200 === $response_code ) {
936 + return json_decode( wp_remote_retrieve_body( $wpcom_request ) );
937 + } else {
938 + return new WP_Error(
939 + 'failed_to_fetch_data',
940 + esc_html__( 'Unable to fetch the requested data.', 'jetpack' ),
941 + array( 'status' => $response_code )
942 + );
943 + }
944 + }
945 +
946 + /**
947 + * Get conditional recommendations data.
948 + *
949 + * @return array Conditional recommendations data.
950 + */
951 + public static function get_conditional_recommendations() {
952 + return Jetpack_Recommendations::get_conditional_recommendations();
953 + }
954 +
955 + /**
956 + * Validate the recommendations data
957 + *
958 + * @param array $value Value to check received by request.
959 + * @param WP_REST_Request $request The request sent to the WP REST API.
960 + * @param string $param Name of the parameter passed to endpoint holding $value.
961 + *
962 + * @return bool|WP_Error
963 + */
964 + public static function validate_recommendations_data( $value, $request, $param ) {
965 + if ( ! is_array( $value ) ) {
966 + /* translators: Name of a parameter that must be an object */
967 + return new WP_Error( 'invalid_param', sprintf( esc_html__( '%s must be an object.', 'jetpack' ), $param ) );
968 + }
969 +
970 + foreach ( $value as $answer ) {
971 + if ( is_array( $answer ) ) {
972 + $validate = self::validate_array_of_strings( $answer, $request, $param );
973 + } elseif ( is_string( $answer ) ) {
974 + $validate = self::validate_string( $answer, $request, $param );
975 + } elseif ( $answer === null ) {
976 + $validate = true;
977 + } else {
978 + $validate = self::validate_boolean( $answer, $request, $param );
979 + }
980 +
981 + if ( is_wp_error( $validate ) ) {
982 + return $validate;
983 + }
984 + }
985 +
986 + return true;
987 + }
988 +
989 + /**
711 990 * Return a purchase token used for site-connected (non user-authenticated) checkout.
712 991 *
713 992 * @return string|WP_Error The current purchase token or WP_Error with error details.
714 993 */
@@ -1372,9 +1651,9 @@
1372 1651 */
1373 1652 public static function get_user_connection_data() {
1374 1653 _deprecated_function( __METHOD__, 'jetpack-10.0.0', '\Automattic\Jetpack\Connection\REST_Connector::get_user_connection_data' );
1375 1654
1376 - require_once JETPACK__PLUGIN_DIR . '_inc/lib/admin-pages/class-jetpack-redux-state-helper.php';
1655 + require_once JETPACK__PLUGIN_DIR . '_inc/lib/admin-pages/class.jetpack-react-page.php';
1377 1656
1378 1657 $connection_owner = ( new Connection_Manager() )->get_connection_owner();
1379 1658 $owner_display_name = false === $connection_owner ? null : $connection_owner->data->display_name;
1380 1659
@@ -1557,8 +1836,64 @@
1557 1836 );
1558 1837 }
1559 1838
1560 1839 /**
1840 + * Fetch the discount for this site and return it.
1841 + *
1842 + * @since 10.8
1843 + *
1844 + * @return array|WP_Error
1845 + */
1846 + public static function get_site_discount() {
1847 + $site_id = Jetpack_Options::get_option( 'id' );
1848 +
1849 + if ( ! $site_id ) {
1850 + return new WP_Error(
1851 + 'site_id_missing',
1852 + esc_html__( 'Site ID is missing.', 'jetpack' ),
1853 + array( 'status' => 400 )
1854 + );
1855 + }
1856 +
1857 + $response = Client::wpcom_json_api_request_as_user(
1858 + "/sites/$site_id/discount",
1859 + '2',
1860 + array(
1861 + 'method' => 'GET',
1862 + 'headers' => array(
1863 + 'X-Forwarded-For' => ( new Visitor() )->get_ip( true ),
1864 + ),
1865 + )
1866 + );
1867 +
1868 + $response_code = wp_remote_retrieve_response_code( $response );
1869 + $data = json_decode( wp_remote_retrieve_body( $response ) );
1870 +
1871 + if ( 200 !== $response_code ) {
1872 + return new WP_Error(
1873 + 'discount_fetch_failed',
1874 + is_object( $data ) && property_exists( $data, 'error' ) ? $data->error : esc_html__( 'Could not retrieve site discount.', 'jetpack' ),
1875 + array( 'status' => $response_code )
1876 + );
1877 + }
1878 +
1879 + if ( ! isset( $data ) ) {
1880 + return new WP_Error(
1881 + 'discount_parse_error',
1882 + esc_html__( 'Could not parse discount', 'jetpack' ),
1883 + array( 'status' => 204 ) // no content.
1884 + );
1885 + }
1886 +
1887 + return rest_ensure_response(
1888 + array(
1889 + 'code' => 'success',
1890 + 'data' => $data,
1891 + )
1892 + );
1893 + }
1894 +
1895 + /**
1561 1896 * Reset Jetpack options
1562 1897 *
1563 1898 * @since 4.3.0
1564 1899 *
@@ -1728,15 +2063,8 @@
1728 2063 ),
1729 2064 'validate_callback' => __CLASS__ . '::validate_list_item',
1730 2065 'jp_group' => 'comments',
1731 2066 ),
1732 - 'enable_blocks_comments' => array(
1733 - 'description' => esc_html__( 'Enable blocks in comments', 'jetpack' ),
1734 - 'type' => 'boolean',
1735 - 'default' => 1,
1736 - 'validate_callback' => __CLASS__ . '::validate_boolean',
1737 - 'jp_group' => 'comments',
1738 - ),
1739 2067
1740 2068 // Custom Content Types.
1741 2069 'jetpack_portfolio' => array(
1742 2070 'description' => esc_html__( 'Enable or disable Jetpack portfolio post type.', 'jetpack' ),
@@ -2562,15 +2890,8 @@
2562 2890 'default' => 0,
2563 2891 'validate_callback' => __CLASS__ . '::validate_boolean',
2564 2892 'jp_group' => 'videopress',
2565 2893 ),
2566 - 'videopress_share_menu_disabled' => array(
2567 - 'description' => esc_html__( 'Hide the share menu on every video, overriding each video’s own setting', 'jetpack' ),
2568 - 'type' => 'boolean',
2569 - 'default' => 0,
2570 - 'validate_callback' => __CLASS__ . '::validate_boolean',
2571 - 'jp_group' => 'videopress',
2572 - ),
2573 2894 );
2574 2895
2575 2896 // SEO Tools - SEO Enhancer.
2576 2897 // TODO: move this to the main options array? The filter was there while developing the feature.
@@ -2838,14 +3159,14 @@
2838 3159 *
2839 3160 * @return bool|WP_Error
2840 3161 */
2841 3162 public static function validate_verification_service( $value, $request, $param ) {
2842 - if ( ! empty( $value ) && ( ! is_string( $value ) || false === jetpack_verification_validate_code( $value ) ) ) {
3163 + if ( ! empty( $value ) && ! ( is_string( $value ) && ( preg_match( '/^[a-z0-9_-]+$/i', $value ) || jetpack_verification_get_code( $value ) !== false ) ) ) {
2843 3164 return new WP_Error(
2844 3165 'invalid_param',
2845 3166 sprintf(
2846 3167 /* Translators: Placeholder is a verification string used to verify a service like Google Webmaster Console. */
2847 - esc_html__( '%s must be a valid verification code or verification tag.', 'jetpack' ),
3168 + esc_html__( '%s must be an alphanumeric string or a verification tag.', 'jetpack' ),
2848 3169 $param
2849 3170 )
2850 3171 );
2851 3172 }
@@ -3995,8 +4316,65 @@
3995 4316 public static function set_has_seen_wc_connection_modal() {
3996 4317 $updated_option = Jetpack_Options::update_option( 'has_seen_wc_connection_modal', true );
3997 4318
3998 4319 return rest_ensure_response( array( 'success' => $updated_option ) );
4320 + }
4321 +
4322 + /**
4323 + * Fetch introdution offers.
4324 + *
4325 + * @since 10.9
4326 + *
4327 + * @return array|WP_Error
4328 + */
4329 + public static function get_intro_offers() {
4330 + $site_id = Jetpack_Options::get_option( 'id' );
4331 +
4332 + if ( ! $site_id ) {
4333 + return new WP_Error(
4334 + 'site_id_missing',
4335 + esc_html__( 'Site ID is missing.', 'jetpack' ),
4336 + array( 'status' => 400 )
4337 + );
4338 + }
4339 +
4340 + $response = Client::wpcom_json_api_request_as_user(
4341 + '/introductory-offers',
4342 + '2',
4343 + array(
4344 + 'method' => 'GET',
4345 + 'headers' => array(
4346 + 'X-Forwarded-For' => ( new Visitor() )->get_ip( true ),
4347 + ),
4348 + )
4349 + );
4350 +
4351 + $response_code = wp_remote_retrieve_response_code( $response );
4352 +
4353 + if ( 200 !== $response_code ) {
4354 + return new WP_Error(
4355 + 'intro_offers_fetch_failed',
4356 + esc_html__( 'Could not retrieve intro offers.', 'jetpack' ),
4357 + array( 'status' => $response_code )
4358 + );
4359 + }
4360 +
4361 + $data = json_decode( wp_remote_retrieve_body( $response ) );
4362 +
4363 + if ( ! isset( $data ) ) {
4364 + return new WP_Error(
4365 + 'intro_offers_error',
4366 + esc_html__( 'Could not parse intro offers.', 'jetpack' ),
4367 + array( 'status' => 204 ) // no content.
4368 + );
4369 + }
4370 +
4371 + return rest_ensure_response(
4372 + array(
4373 + 'code' => 'success',
4374 + 'data' => $data,
4375 + )
4376 + );
3999 4377 }
4000 4378
4001 4379 /**
4002 4380 * Return the list of available features.