Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
95.00% covered (success)
95.00%
38 / 40
83.33% covered (warning)
83.33%
5 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
Podcast_Settings_Endpoint
95.00% covered (success)
95.00%
38 / 40
83.33% covered (warning)
83.33%
5 / 6
12
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 init
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
 register_routes
100.00% covered (success)
100.00%
17 / 17
100.00% covered (success)
100.00%
1 / 1
1
 permission_check
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
2
 get_item
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 update_item
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
5
1<?php
2/**
3 * Dedicated REST endpoint for `podcasting_*` site settings.
4 *
5 * @package automattic/jetpack-podcast
6 */
7
8namespace Automattic\Jetpack\Podcast;
9
10use WP_Error;
11use WP_REST_Controller;
12use WP_REST_Request;
13use WP_REST_Response;
14use WP_REST_Server;
15
16/**
17 * Reads and writes the `podcasting_*` options for the dashboard SPA over its own
18 * `wpcom/v2/podcast/settings` route. Schema and sanitizers live in {@see Settings}.
19 *
20 * Registered through the WPCOM REST API v2 plugin framework
21 * ({@see wpcom_rest_api_v2_load_plugin()}), so a single definition is reachable on
22 * Simple and WoA via the `public-api.wordpress.com` proxy and, once Podcast ships in
23 * the Jetpack plugin, same-origin on self-hosted sites — no per-platform relay.
24 */
25class Podcast_Settings_Endpoint extends WP_REST_Controller {
26
27    /**
28     * Wire the routes onto `rest_api_init`. The framework instantiates this once.
29     */
30    public function __construct() {
31        $this->namespace = 'wpcom/v2';
32        add_action( 'rest_api_init', array( $this, 'register_routes' ) );
33    }
34
35    /**
36     * Register the endpoint through the WPCOM REST API v2 framework. The loader
37     * ships with the Jetpack plugin core-api, present in every context Podcast runs
38     * in (Simple/WoA today, the Jetpack plugin once Podcast moves there); guarded so
39     * the package no-ops rather than fatals if it's somehow absent.
40     */
41    public static function init() {
42        if ( function_exists( 'wpcom_rest_api_v2_load_plugin' ) ) {
43            wpcom_rest_api_v2_load_plugin( self::class );
44        }
45    }
46
47    /**
48     * Register the GET (full record) + writable (partial patch) routes.
49     *
50     * Update args only coerce top-level types — the registered `sanitize_callback`s
51     * do the real validation on write, so one bad field can't 400 the whole patch.
52     */
53    public function register_routes() {
54        register_rest_route(
55            $this->namespace,
56            'podcast/settings',
57            array(
58                array(
59                    'methods'             => WP_REST_Server::READABLE,
60                    'callback'            => array( $this, 'get_item' ),
61                    'permission_callback' => array( $this, 'permission_check' ),
62                ),
63                array(
64                    'methods'             => WP_REST_Server::EDITABLE,
65                    'callback'            => array( $this, 'update_item' ),
66                    'permission_callback' => array( $this, 'permission_check' ),
67                    'args'                => Settings::rest_schema_properties(),
68                ),
69            )
70        );
71    }
72
73    /**
74     * Site admins only — same gate as the wp-admin Podcast dashboard.
75     *
76     * @return true|WP_Error
77     */
78    public function permission_check() {
79        if ( ! current_user_can( 'manage_options' ) ) {
80            return new WP_Error(
81                'rest_forbidden',
82                __( 'Sorry, you are not allowed to manage podcast settings for this site.', 'jetpack-podcast' ),
83                array( 'status' => rest_authorization_required_code() )
84            );
85        }
86        return true;
87    }
88
89    /**
90     * GET — the full, padded settings record.
91     *
92     * @param WP_REST_Request $request Unused.
93     * @return WP_REST_Response
94     */
95    public function get_item( $request ) {
96        unset( $request );
97        return rest_ensure_response( Settings::get_all() );
98    }
99
100    /**
101     * PUT/POST/PATCH — apply a partial patch and return the full merged record.
102     *
103     * Only keys actually present in the request are written, so absent keys can
104     * never clobber stored values. Array-shaped options merge on sanitize.
105     *
106     * @param WP_REST_Request $request Incoming request.
107     * @return WP_REST_Response
108     */
109    public function update_item( $request ) {
110        $saved = false;
111
112        foreach ( Settings::OPTION_NAMES as $name ) {
113            $value = $request->get_param( $name );
114            if ( null === $value ) {
115                continue;
116            }
117            if ( update_option( $name, $value ) ) {
118                $saved = true;
119            }
120        }
121
122        if ( $saved ) {
123            /**
124             * Fires after a podcast settings write changes at least one option.
125             *
126             * @since 1.1.1
127             */
128            do_action( 'jetpack_podcast_settings_saved' );
129        }
130
131        return rest_ensure_response( Settings::get_all() );
132    }
133}