Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
86 / 86
100.00% covered (success)
100.00%
5 / 5
CRAP
100.00% covered (success)
100.00%
1 / 1
Status_Controller
100.00% covered (success)
100.00%
86 / 86
100.00% covered (success)
100.00%
5 / 5
12
100.00% covered (success)
100.00%
1 / 1
 register_routes
100.00% covered (success)
100.00%
38 / 38
100.00% covered (success)
100.00%
1 / 1
1
 get_status
100.00% covered (success)
100.00%
20 / 20
100.00% covered (success)
100.00%
1 / 1
1
 switch_to_block
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
2
 activate
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
3
 refuse_unless
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
5
1<?php
2/**
3 * The section states behind Settings > Sharing, and the actions that change them.
4 *
5 * @package automattic/jetpack-sharing-likes
6 */
7
8declare( strict_types = 1 );
9
10namespace Automattic\Jetpack\Sharing_Likes\REST;
11
12use Automattic\Jetpack\Sharing_Likes\Settings\Environment;
13use Automattic\Jetpack\Sharing_Likes\Settings\Feature_Actions;
14use Automattic\Jetpack\Sharing_Likes\Settings\Likes_Section;
15use Automattic\Jetpack\Sharing_Likes\Settings\Placement_Section;
16use Automattic\Jetpack\Sharing_Likes\Settings\Section_State;
17use Automattic\Jetpack\Sharing_Likes\Settings\Sharing_Section;
18use WP_Error;
19use WP_REST_Request;
20use WP_REST_Response;
21use WP_REST_Server;
22
23/**
24 * Which variant each section renders, plus "Switch to the … block" and "Turn on".
25 *
26 * Each action is only accepted from the variant that offers it, and answers with
27 * the new status so the screen can re-render without asking again.
28 */
29final class Status_Controller extends Controller {
30
31    /**
32     * Register the routes.
33     */
34    public function register_routes() {
35        $base     = '/' . Endpoints::BASE;
36        $features = array( Placement_Section::FEATURE_SHARING, Placement_Section::FEATURE_LIKES );
37        $feature  = '(?P<feature>' . implode( '|', $features ) . ')';
38        // Route matching ignores case, and a body or query `feature` would outrank the URL's.
39        $args = array(
40            'feature' => array(
41                'type' => 'string',
42                'enum' => $features,
43            ),
44        );
45
46        register_rest_route(
47            $this->namespace,
48            $base . '/status',
49            array(
50                'methods'             => WP_REST_Server::READABLE,
51                'callback'            => array( $this, 'get_status' ),
52                'permission_callback' => array( $this, 'permission_check' ),
53            )
54        );
55
56        register_rest_route(
57            $this->namespace,
58            $base . '/' . $feature . '/switch-to-block',
59            array(
60                'methods'             => WP_REST_Server::CREATABLE,
61                'callback'            => array( $this, 'switch_to_block' ),
62                'permission_callback' => array( $this, 'permission_check' ),
63                'args'                => $args,
64            )
65        );
66
67        register_rest_route(
68            $this->namespace,
69            $base . '/' . $feature . '/activate',
70            array(
71                'methods'             => WP_REST_Server::CREATABLE,
72                'callback'            => array( $this, 'activate' ),
73                'permission_callback' => array( $this, 'permission_check' ),
74                'args'                => $args,
75            )
76        );
77    }
78
79    /**
80     * The variant each section renders.
81     *
82     * @return WP_REST_Response
83     */
84    public function get_status() {
85        $sharing_state        = Sharing_Section::state();
86        $likes_state          = Likes_Section::state();
87        $comment_likes_follow = Environment::comment_likes_follow_likes_settings();
88
89        return rest_ensure_response(
90            array(
91                'sharing'         => array(
92                    'state' => $sharing_state,
93                ),
94                'likes'           => array(
95                    'state'     => $likes_state,
96                    'supported' => Environment::likes_supported(),
97                ),
98                // No variants: comments have no block to move to.
99                'comment_likes'   => array(
100                    'supported'              => Environment::likes_supported(),
101                    'follows_likes_settings' => $comment_likes_follow,
102                ),
103                'placement'       => Section_State::shows_placement( $sharing_state, $likes_state, $comment_likes_follow ),
104                'site_editor_url' => Environment::single_template_editor_url(),
105            )
106        );
107    }
108
109    /**
110     * Hand a feature over to its block.
111     *
112     * @param WP_REST_Request $request Request.
113     * @return WP_REST_Response|WP_Error
114     */
115    public function switch_to_block( $request ) {
116        $feature = $request->get_url_params()['feature'];
117        $refused = self::refuse_unless( $feature, Section_State::CONFIGURE_WITH_BLOCK_NUDGE );
118
119        if ( $refused ) {
120            return $refused;
121        }
122
123        Feature_Actions::switch_to_block( $feature );
124
125        return $this->get_status();
126    }
127
128    /**
129     * Turn a feature's module back on.
130     *
131     * @param WP_REST_Request $request Request.
132     * @return WP_REST_Response|WP_Error
133     */
134    public function activate( $request ) {
135        $feature = $request->get_url_params()['feature'];
136        $refused = self::refuse_unless( $feature, Section_State::OFF );
137
138        if ( $refused ) {
139            return $refused;
140        }
141
142        if ( ! Feature_Actions::activate( $feature ) ) {
143            return new WP_Error(
144                'rest_sharing_likes_activation_failed',
145                __( 'The feature could not be turned on.', 'jetpack-sharing-likes' ),
146                array( 'status' => 409 )
147            );
148        }
149
150        return $this->get_status();
151    }
152
153    /**
154     * An error unless the feature's section renders the variant that offers the action.
155     *
156     * @param string $feature One of the `Placement_Section::FEATURE_*` constants.
157     * @param string $state   The `Section_State` constant that offers the action.
158     * @return WP_Error|null
159     */
160    private static function refuse_unless( string $feature, string $state ): ?WP_Error {
161        $is_likes = Placement_Section::FEATURE_LIKES === $feature;
162
163        // Offline mode keeps the screen, but loads no Likes module for the section to act on.
164        if ( $is_likes && ! Environment::likes_supported() ) {
165            $current = null;
166        } else {
167            $current = $is_likes ? Likes_Section::state() : Sharing_Section::state();
168        }
169
170        if ( $state === $current ) {
171            return null;
172        }
173
174        return new WP_Error(
175            'rest_sharing_likes_action_unavailable',
176            __( 'This action is not available on this site right now.', 'jetpack-sharing-likes' ),
177            array( 'status' => 409 )
178        );
179    }
180}