PluginProbe
Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! / 3.8.0
Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! v3.8.0
3.8.0 3.7.5 3.7.4 3.7.3 3.7.2 1-final 3.7.1 3.7.0 3.6.8 3.6.7 3.6.6 3.6.5 3.6.4 3.6.3 3.6.2 3.6.1 3.0.3 3.0.4 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.1 All 112 releases
templately / modules / gutenberg-integration / REST / Visibility.php

Visibility.php in Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! 3.8.0, at modules/gutenberg-integration/REST/Visibility.php

110 lines 4.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Templately\Modules\GutenbergIntegration\REST;
4
5 use Templately\API\API;
6 use WP_Error;
7 use WP_REST_Request;
8 use WP_REST_Server;
9
10 /**
11 * REST replacement for the `wp_ajax_update_gutenberg_hide_buttons` admin-ajax action
12 * (FR-003 / FR-020, specs/033-gutenberg-integration/spec.md). Toggles the visibility of
13 * the "Templately" / "Save in Templately" buttons in the Gutenberg editor toolbar and
14 * persists the preference to the SITE-WIDE WordPress option
15 * `templately-gutenberg-hide-buttons` (via `update_option()`/`get_option()` — NOT
16 * per-user meta; the AJAX handler stored it site-wide and this route preserves that).
17 *
18 * The old ajax action (`Gutenberg::update_gutenberg_hide_buttons()`) is kept running as
19 * a deprecated shim (see `Platform/Gutenberg.php::hooks()`) — the caller lives in the
20 * browser-cached editor bundle (`assets/js/gutenberg.js`, enqueued on
21 * `enqueue_block_editor_assets`); an already-open editor tab, or a soft reload served
22 * stale JS from the HTTP cache, would still POST to admin-ajax with the old action name
23 * after this route ships, so removing the handler would break the toggle for those tabs.
24 *
25 * Transport: the route is registered for `EDITABLE` methods (PUT/PATCH/POST) so an
26 * external/API consumer can `PUT` per the constitution III target
27 * (`PUT /templately/v1/gutenberg/visibility`, body `{ visibility: 'visible' | 'hidden' }`).
28 * The plugin's own frontend calls it via POST because the shared `templatelyApi` wrapper
29 * only attaches a JSON request body on POST (and query args on GET); EDITABLE accepts
30 * both, so a single route serves both callers.
31 */
32 class Visibility extends API {
33
34 /**
35 * The ajax handler's authorization gate was `check_ajax_referer('templately_nonce',
36 * 'nonce')` + `current_user_can('edit_posts')`. The REST equivalent is at least as
37 * strict on every axis, never weaker:
38 *
39 * - Nonce: WP core verifies the `X-WP-Nonce` (wp_rest) header before any
40 * permission_callback runs — the CSRF protection the ajax path got from
41 * `templately_nonce`.
42 * - Capability: the base `API::_permission_check()` ALREADY requires
43 * `current_user_can('delete_posts')` before this method is reached; this override
44 * adds the ajax handler's own `edit_posts` check on top. Net gate:
45 * `delete_posts && edit_posts`. For every standard WP role `edit_posts` implies
46 * `delete_posts`, so the allow-set equals the ajax path's; for an exotic custom role
47 * with `edit_posts` but not `delete_posts`, REST is STRICTER (denies where ajax
48 * allowed) — the desired direction.
49 * - Connected account: this override deliberately does NOT call
50 * `parent::permission_check()` (which would require a non-empty `api_key`). Showing
51 * or hiding the LOCAL editor toolbar is a per-site editor preference, not a cloud
52 * operation; the ajax handler never required a connected Templately account, and
53 * requiring one here would regress the toggle for users editing before they connect.
54 */
55 public function permission_check( WP_REST_Request $request ) {
56 $this->request = $request;
57
58 if ( ! current_user_can( 'edit_posts' ) ) {
59 return new WP_Error(
60 'rest_forbidden',
61 __( 'Sorry, you are not allowed to change the Templately toolbar visibility.', 'templately' ),
62 [ 'status' => rest_authorization_required_code() ]
63 );
64 }
65
66 return true;
67 }
68
69 public function register_routes() {
70 $this->register_endpoint(
71 'gutenberg/visibility',
72 [ $this, 'update_visibility' ],
73 [
74 'visibility' => [
75 'required' => true,
76 'type' => 'string',
77 'description' => __( 'Desired visibility of the Templately editor toolbar buttons: "visible" or "hidden".', 'templately' ),
78 ],
79 ],
80 WP_REST_Server::EDITABLE
81 );
82 }
83
84 public function update_visibility() {
85 $visibility = $this->get_param( 'visibility', '', 'sanitize_key' );
86
87 if ( ! in_array( $visibility, [ 'visible', 'hidden' ], true ) ) {
88 return $this->error(
89 'invalid_visibility',
90 __( 'The visibility value must be either "visible" or "hidden".', 'templately' ),
91 'gutenberg/visibility',
92 400
93 );
94 }
95
96 // Same site-wide option key the ajax handler wrote to. 'hidden' => 'yes'.
97 $hide_buttons = 'hidden' === $visibility ? 'yes' : 'no';
98 update_option( 'templately-gutenberg-hide-buttons', $hide_buttons );
99
100 // Re-read and normalize exactly as the ajax handler did (any non-'yes' => 'no').
101 $stored = get_option( 'templately-gutenberg-hide-buttons', 'no' );
102 $hide_buttons = 'yes' === $stored ? 'yes' : 'no';
103
104 return $this->success( [
105 'visibility' => 'yes' === $hide_buttons ? 'hidden' : 'visible',
106 'hide_buttons' => $hide_buttons,
107 ] );
108 }
109 }
110