PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.3-beta
Jetpack – WP Security, Backup, Speed, & Growth v16.3-beta
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 13.7.2 All 507 releases
← All changes | jetpack_vendor/automattic/jetpack-publicize/src/rest-api/class-render-messages-controller.php +266 -0 16.2-beta → 16.3-beta View file →
@@ -1,0 +1,266 @@
1 +<?php
2 +/**
3 + * Publicize: Render Messages Controller
4 + *
5 + * @package automattic/jetpack-publicize
6 + */
7 +
8 +namespace Automattic\Jetpack\Publicize\REST_API;
9 +
10 +use Automattic\Jetpack\Connection\Traits\WPCOM_REST_API_Proxy_Request;
11 +use Automattic\Jetpack\Publicize\Publicize_Utils as Utils;
12 +use WP_Error;
13 +use WP_REST_Request;
14 +use WP_REST_Server;
15 +
16 +if ( ! defined( 'ABSPATH' ) ) {
17 + exit( 0 );
18 +}
19 +
20 +/**
21 + * Publicize: Render Messages Controller class.
22 + *
23 + * Renders Publicize message templates for a given post and a batch of
24 + * connection inputs in a single request, so the block-editor preview can
25 + * fetch all enabled connections' previews in one round-trip on sites with
26 + * social paid features.
27 + *
28 + * POST takes a JSON body of `{ post_id, items: [...], post_intent: {...} }`
29 + * and returns one record per input item, in input order, keyed by the
30 + * client-supplied `connection_id`. Body-based POST is used instead of a GET
31 + * collection so multi-connection / long-message batches don't hit
32 + * infrastructure URL caps.
33 + *
34 + * @phan-constructor-used-for-side-effects
35 + */
36 +class Render_Messages_Controller extends Base_Controller {
37 +
38 + use WPCOM_REST_API_Proxy_Request;
39 +
40 + /**
41 + * Constructor.
42 + */
43 + public function __construct() {
44 + parent::__construct();
45 +
46 + $this->base_api_path = 'wpcom';
47 + $this->version = 'v2';
48 +
49 + $this->namespace = "{$this->base_api_path}/{$this->version}";
50 + $this->rest_base = 'publicize/render-messages';
51 +
52 + $this->allow_requests_as_blog = true;
53 +
54 + add_action( 'rest_api_init', array( $this, 'register_routes' ) );
55 + }
56 +
57 + /**
58 + * Register the routes.
59 + */
60 + public function register_routes() {
61 + register_rest_route(
62 + $this->namespace,
63 + '/' . $this->rest_base,
64 + array(
65 + 'methods' => WP_REST_Server::CREATABLE,
66 + 'callback' => array( $this, 'render_messages' ),
67 + 'permission_callback' => array( $this, 'permissions_check' ),
68 + 'private_site_security_settings' => array(
69 + 'allow_blog_token_access' => true,
70 + ),
71 + 'args' => array(
72 + 'post_id' => array(
73 + 'description' => __( 'The ID of the post to render the messages for.', 'jetpack-publicize-pkg' ),
74 + 'type' => 'integer',
75 + 'required' => true,
76 + ),
77 + 'items' => array(
78 + 'description' => __( 'List of per-connection render inputs.', 'jetpack-publicize-pkg' ),
79 + 'type' => 'array',
80 + 'required' => true,
81 + 'minItems' => 1,
82 + 'items' => array(
83 + 'type' => 'object',
84 + 'additionalProperties' => false,
85 + 'required' => array( 'connection_id' ),
86 + 'properties' => array(
87 + 'connection_id' => array(
88 + 'description' => __( 'Publicize connection ID — used to dispatch the renderer and resolve the per-connection template.', 'jetpack-publicize-pkg' ),
89 + 'type' => 'string',
90 + ),
91 + 'message' => array(
92 + 'description' => __( 'Optional message override. Empty walks the per-connection / site / network-default chain.', 'jetpack-publicize-pkg' ),
93 + 'type' => 'string',
94 + 'default' => '',
95 + ),
96 + 'is_social_post' => array(
97 + 'description' => __( 'Whether the post will be shared as a social post (media attached) rather than a link share.', 'jetpack-publicize-pkg' ),
98 + 'type' => 'boolean',
99 + 'default' => false,
100 + ),
101 + ),
102 + ),
103 + ),
104 + 'post_intent' => array(
105 + 'description' => __( 'Edited post fields to use when rendering unsaved preview changes.', 'jetpack-publicize-pkg' ),
106 + 'type' => 'object',
107 + 'default' => array(),
108 + 'additionalProperties' => false,
109 + 'properties' => array(
110 + 'title' => array(
111 + 'description' => __( 'Edited post title.', 'jetpack-publicize-pkg' ),
112 + 'type' => 'string',
113 + 'default' => '',
114 + ),
115 + 'excerpt' => array(
116 + 'description' => __( 'Edited post excerpt.', 'jetpack-publicize-pkg' ),
117 + 'type' => 'string',
118 + 'default' => '',
119 + ),
120 + 'content' => array(
121 + 'description' => __( 'Edited post content.', 'jetpack-publicize-pkg' ),
122 + 'type' => 'string',
123 + 'default' => '',
124 + ),
125 + ),
126 + ),
127 + ),
128 + 'schema' => array( $this, 'get_public_item_schema' ),
129 + )
130 + );
131 + }
132 +
133 + /**
134 + * Retrieves the JSON schema for a single rendered-message item.
135 + *
136 + * @return array Schema data.
137 + */
138 + public function get_item_schema() {
139 + return array(
140 + '$schema' => 'http://json-schema.org/draft-04/schema#',
141 + 'title' => 'publicize-render-messages-item',
142 + 'type' => 'object',
143 + 'properties' => array(
144 + 'connection_id' => array(
145 + 'description' => __( 'Connection identifier echoed back from the request.', 'jetpack-publicize-pkg' ),
146 + 'type' => 'string',
147 + 'readonly' => true,
148 + 'context' => array( 'view', 'edit' ),
149 + ),
150 + 'rendered_message' => array(
151 + 'description' => __( 'The rendered message for this item. Absent when the item failed to render.', 'jetpack-publicize-pkg' ),
152 + 'type' => 'string',
153 + 'readonly' => true,
154 + 'context' => array( 'view', 'edit' ),
155 + ),
156 + 'hyperlinks' => array(
157 + 'description' => __( 'Editor hyperlinks preserved from content or excerpt placeholders.', 'jetpack-publicize-pkg' ),
158 + 'type' => 'array',
159 + 'readonly' => true,
160 + 'context' => array( 'view', 'edit' ),
161 + 'items' => array(
162 + 'type' => 'object',
163 + 'properties' => array(
164 + 'text' => array( 'type' => 'string' ),
165 + 'href' => array( 'type' => 'string' ),
166 + 'occurrence' => array( 'type' => 'integer' ),
167 + ),
168 + ),
169 + ),
170 + 'error' => array(
171 + 'description' => __( 'Per-item error. Present only when this item failed to render.', 'jetpack-publicize-pkg' ),
172 + 'type' => 'object',
173 + 'readonly' => true,
174 + 'context' => array( 'view', 'edit' ),
175 + 'properties' => array(
176 + 'code' => array( 'type' => 'string' ),
177 + 'message' => array( 'type' => 'string' ),
178 + ),
179 + ),
180 + ),
181 + );
182 + }
183 +
184 + /**
185 + * Permission check.
186 + *
187 + * Preserves the blog-token proxy path via Base_Controller::publicize_permissions_check()
188 + * (which returns true for authorized blog requests when allow_requests_as_blog is set),
189 + * and enforces post-level `edit_post` capability for regular user requests.
190 + *
191 + * @param WP_REST_Request $request Full details about the request.
192 + * @return true|WP_Error True if authorized, WP_Error otherwise.
193 + */
194 + public function permissions_check( $request ) {
195 + $base_check = $this->publicize_permissions_check();
196 +
197 + if ( is_wp_error( $base_check ) ) {
198 + return $base_check;
199 + }
200 +
201 + // Blog-token proxy requests don't have a user context; the publicize check
202 + // above already returned true for those.
203 + if ( self::is_authorized_blog_request() ) {
204 + return true;
205 + }
206 +
207 + $post_id = (int) $request->get_param( 'post_id' );
208 +
209 + if ( ! $post_id || ! current_user_can( 'edit_post', $post_id ) ) {
210 + return new WP_Error(
211 + 'invalid_user_permission_publicize',
212 + __( 'Sorry, you are not allowed to access Jetpack Social data for this post.', 'jetpack-publicize-pkg' ),
213 + array( 'status' => rest_authorization_required_code() )
214 + );
215 + }
216 +
217 + return true;
218 + }
219 +
220 + /**
221 + * Render the messages for the given post and items.
222 + *
223 + * Top-level errors (feature off, post not found) short-circuit the whole batch.
224 + * Per-item failures are returned as `{ id, error: { code, message } }` so a
225 + * single bad item never fails the batch.
226 + *
227 + * @param WP_REST_Request $request The request object.
228 + * @return mixed The rendered items array, or a WP_Error for top-level failures.
229 + */
230 + public function render_messages( $request ) {
231 + if ( Utils::is_wpcom() ) {
232 + if ( ! wpcom_site_has_feature( \WPCOM_Features::SOCIAL_ENHANCED_PUBLISHING ) ) {
233 + return new WP_Error(
234 + 'feature_not_enabled',
235 + __( 'Publicize message templates are not enabled for this site.', 'jetpack-publicize-pkg' ),
236 + array( 'status' => 403 )
237 + );
238 + }
239 +
240 + $post_id = (int) $request->get_param( 'post_id' );
241 + $items = (array) $request->get_param( 'items' );
242 + $intent = (array) $request->get_param( 'post_intent' );
243 +
244 + $post = get_post( $post_id );
245 +
246 + if ( ! $post ) {
247 + return new WP_Error(
248 + 'post_not_found',
249 + __( 'Post not found.', 'jetpack-publicize-pkg' ),
250 + array( 'status' => 404 )
251 + );
252 + }
253 +
254 + require_lib( 'publicize/util/message-templates' );
255 +
256 + return rest_ensure_response(
257 + \Publicize\render_messages( $post, $items, $intent )
258 + );
259 + }
260 +
261 + // Self-hosted Jetpack: proxy the request body to WPCOM.
262 + return rest_ensure_response(
263 + $this->proxy_request_to_wpcom_as_blog( $request )
264 + );
265 + }
266 +}