PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.3-a.7
Jetpack – WP Security, Backup, Speed, & Growth v16.3-a.7
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 13.8.3 All 506 releases
jetpack / jetpack_vendor / automattic / jetpack-forms / src / contact-form / class-feedback-source.php

class-feedback-source.php in Jetpack – WP Security, Backup, Speed, & Growth 16.3-a.7, at jetpack_vendor/automattic/jetpack-forms/src/contact-form/class-feedback-source.php

367 lines 11.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Feedback Entry
4 *
5 * @package automattic/jetpack-forms
6 */
7
8 namespace Automattic\Jetpack\Forms\ContactForm;
9
10 /**
11 * Class Feedback_Source
12 *
13 * Represents where a feedback was created from, feedback entry with an ID, title, permalink, and page number.
14 */
15 class Feedback_Source {
16
17 /**
18 * Source types whose forms can only be placed by a user with the administrator-tier
19 * `edit_theme_options` capability. Destinations declared in these surfaces are trusted
20 * even though they have no numeric post author to check.
21 *
22 * @var string[]
23 */
24 const ADMIN_TIER_SOURCE_TYPES = array( 'block_template', 'block_template_part', 'widget' );
25
26 /**
27 * The ID of the post or page that the feedback was created on.
28 *
29 * @var string
30 */
31 private $id = '';
32
33 /**
34 * The title of the post or page that the feedback was created on.
35 *
36 * @var string
37 */
38 private $title = '';
39
40 /**
41 * The permalink of the feedback entry.
42 *
43 * @var string
44 */
45 private $permalink = '';
46
47 /**
48 * The page number of the feedback post or page that the feedback was created on.
49 * This is used to determine the page number in a paginated view of page or post.
50 *
51 * @var int
52 */
53 private $page_number = 1;
54
55 /**
56 * The source type of the feedback entry.
57 * Possible values: single, widget, block_template, block_template_part
58 *
59 * @var string
60 */
61 private $source_type = 'single';
62
63 /**
64 * The request URL of the feedback entry.
65 *
66 * @var string
67 */
68 private $request_url = '';
69
70 /**
71 * Whether this feedback was created from a form preview submission.
72 *
73 * Test feedback is stored normally in the inbox but is distinguished in the
74 * notification email, excluded from the default CSV export, and skips the
75 * spam/Akismet pipeline.
76 *
77 * @var bool
78 */
79 private $is_test = false;
80
81 /**
82 * Constructor for Feedback_Source.
83 *
84 * @param string|int $id The Source ID = post ID, widget ID, block template ID, or 0 for homepage or non-post/page.
85 * @param string $title The title of the feedback entry.
86 * @param int $page_number The page number of the feedback entry, default is 1.
87 * @param string $source_type The source type of the feedback entry, default is 'single'.
88 * @param string $request_url The request URL of the feedback entry.
89 * @param bool $is_test Whether the feedback was submitted from a form preview.
90 */
91 public function __construct( $id = 0, $title = '', $page_number = 1, $source_type = 'single', $request_url = '', $is_test = false ) {
92
93 if ( is_numeric( $id ) ) {
94 $this->id = $id > 0 ? $id : 0;
95 } else {
96 $this->id = $id;
97 }
98
99 if ( is_numeric( $page_number ) ) {
100 $this->page_number = $page_number > 0 ? $page_number : 1;
101 } else {
102 $this->page_number = 1;
103 }
104
105 $this->title = html_entity_decode( $title, ENT_QUOTES | ENT_HTML5, 'UTF-8' );
106 $this->permalink = empty( $request_url ) ? home_url() : $request_url;
107 $this->source_type = $source_type; // possible source types: single, widget, block_template, block_template_part
108 $this->request_url = $request_url;
109 $this->is_test = (bool) $is_test;
110
111 if ( is_numeric( $id ) && ! empty( $id ) ) {
112 $entry_post = get_post( (int) $id );
113 if ( $entry_post && $entry_post->post_status === 'publish' ) {
114 $this->permalink = get_permalink( $entry_post );
115 $this->title = html_entity_decode( get_the_title( $entry_post ), ENT_QUOTES | ENT_HTML5, 'UTF-8' );
116 } elseif ( $entry_post ) {
117 $this->permalink = '';
118
119 if ( $entry_post->post_status === 'trash' ) {
120 /* translators: %s is the post title */
121 $this->title = sprintf( __( '(trashed) %s', 'jetpack-forms' ), $this->title );
122 }
123 }
124 if ( empty( $entry_post ) ) {
125 /* translators: %s is the post title */
126 $this->title = sprintf( __( '(deleted) %s', 'jetpack-forms' ), $this->title );
127 $this->permalink = '';
128 }
129 }
130 }
131
132 /**
133 * Creates a Feedback_Source instance from a submission.
134 *
135 * @param \WP_Post|null $current_post The current post object.
136 * @param int $current_page_number The current page number, default is 1.
137 * @return Feedback_Source Returns an instance of Feedback_Source.
138 */
139 public static function from_submission( $current_post, int $current_page_number = 1 ) {
140 $id = isset( $current_post->ID ) ? (int) $current_post->ID : 0;
141
142 if ( ! $current_post instanceof \WP_Post || $id === 0 ) {
143 return new self( 0, '', $current_page_number );
144 }
145
146 $title = isset( $current_post->post_title ) ? html_entity_decode( $current_post->post_title, ENT_QUOTES | ENT_HTML5, 'UTF-8' ) : __( '(no title)', 'jetpack-forms' );
147
148 return new self( $id, $title, $current_page_number );
149 }
150
151 /**
152 * Get the title of the current page. That we can then use to display in the feedback entry.
153 *
154 * @return string The title of the current page. That we want to show to the user. To tell them where the feedback was left.
155 */
156 private static function get_source_title() {
157 if ( is_front_page() ) {
158 return get_bloginfo( 'name' );
159 }
160 if ( is_home() ) {
161 return get_the_title( get_option( 'page_for_posts', true ) );
162 }
163 if ( is_singular() ) {
164 return get_the_title();
165 }
166 if ( is_archive() ) {
167 return get_the_archive_title();
168 }
169 if ( is_search() ) {
170 /* translators: %s is the search term */
171 return sprintf( __( 'Search results for: %s', 'jetpack-forms' ), get_search_query() );
172 }
173 if ( is_404() ) {
174 return __( '404 Not Found', 'jetpack-forms' );
175 }
176 return get_bloginfo( 'name' );
177 }
178
179 /**
180 * Creates a Feedback_Source instance for a block template.
181 *
182 * @param array $attributes Form Shortcode attributes.
183 *
184 * @return Feedback_Source Returns an instance of Feedback_Source.
185 */
186 public static function get_current( $attributes ) {
187 global $wp, $page;
188 $current_url = home_url( add_query_arg( array(), $wp->request ) );
189
190 // When a form is rendered inside the server-side preview
191 // (Form_Preview::maybe_render_preview), flag the source as a test
192 // submission. The flag travels with the signed JWT and is read back
193 // at submission time to branch the response into the test pipeline.
194 $is_test = Form_Preview::is_preview_mode();
195
196 // The widget context is resolved server-side in Contact_Form::parse() (it overwrites the
197 // widget attribute before the form is built), so the value seen here is trustworthy.
198 if ( isset( $attributes['widget'] ) && ! empty( $attributes['widget'] ) ) {
199 return new self( $attributes['widget'], self::get_source_title(), 1, 'widget', $current_url, $is_test );
200 }
201
202 // Block template part and block template sources are determined from render-scoped
203 // globals that are set only while the actual template part / template renders — never
204 // from a content attribute. A content attribute can be supplied by a post author (who
205 // need not hold edit_theme_options), so trusting it would let post-content forms
206 // masquerade as admin-authored template sources. See Util for the globals' lifecycle.
207 if ( ! empty( $GLOBALS['grunion_block_template_part_id'] ) ) {
208 return new self( $GLOBALS['grunion_block_template_part_id'], self::get_source_title(), $page, 'block_template_part', $current_url, $is_test );
209 }
210
211 if ( ! empty( $GLOBALS['grunion_block_template_id'] ) ) {
212 return new self( $GLOBALS['grunion_block_template_id'], self::get_source_title(), $page, 'block_template', $current_url, $is_test );
213 }
214
215 return new Feedback_Source( \get_the_ID(), \get_the_title(), $page, 'single', $current_url, $is_test );
216 }
217
218 /**
219 * Creates a Feedback_Source instance from serialized data.
220 *
221 * @param array $data The serialized data.
222 * @return Feedback_Source Returns an instance of Feedback_Source.
223 */
224 public static function from_serialized( $data ) {
225 $id = $data['source_id'] ?? 0;
226 $title = $data['entry_title'] ?? '';
227 $page_number = $data['entry_page'] ?? 1;
228 $source_type = $data['source_type'] ?? 'single';
229 $request_url = $data['request_url'] ?? '';
230 $is_test = ! empty( $data['is_test'] );
231
232 return new self( $id, $title, $page_number, $source_type, $request_url, $is_test );
233 }
234
235 /**
236 * Get the permalink of the feedback entry.
237 *
238 * @return string The permalink of the feedback entry.
239 */
240 public function get_permalink() {
241 if ( $this->page_number > 1 && ! empty( $this->permalink ) ) {
242 return add_query_arg( 'page', $this->page_number, $this->permalink );
243 }
244 return wp_validate_redirect( $this->permalink, home_url() );
245 }
246
247 /**
248 * Get the edit URL of the form or page where the feedback was submitted from.
249 *
250 * @return string The edit URL of the form or page.
251 */
252 public function get_edit_form_url() {
253
254 if ( current_user_can( 'edit_theme_options' ) ) {
255 if ( $this->source_type === 'block_template' && \wp_is_block_theme() ) {
256 return admin_url( 'site-editor.php?p=' . esc_attr( '/wp_template/' . addslashes( $this->id ) ) . '&canvas=edit' );
257 }
258
259 if ( $this->source_type === 'block_template_part' && \wp_is_block_theme() ) {
260 return admin_url( 'site-editor.php?p=' . esc_attr( '/wp_template_part/' . addslashes( $this->id ) ) . '&canvas=edit' );
261 }
262
263 if ( $this->source_type === 'widget' && current_theme_supports( 'widgets' ) ) {
264 return admin_url( 'widgets.php' );
265 }
266 }
267
268 if ( $this->id && is_numeric( $this->id ) && $this->id > 0 && current_user_can( 'edit_post', (int) $this->id ) ) {
269 $entry_post = get_post( (int) $this->id );
270 if ( $entry_post && $entry_post->post_status === 'trash' ) {
271 return ''; // No edit link is possible for trashed posts. They need to be restored first.
272 }
273 return \get_edit_post_link( (int) $this->id, 'url' );
274 }
275
276 return '';
277 }
278
279 /**
280 * Get the relative permalink of the feedback entry.
281 *
282 * @return string The relative permalink of the feedback entry.
283 */
284 public function get_relative_permalink() {
285 if ( ! empty( $this->permalink ) ) {
286 return wp_make_link_relative( $this->get_permalink() );
287 }
288 return '';
289 }
290
291 /**
292 * Get the page number of the feedback entry.
293 *
294 * @return int The page number of the feedback entry.
295 */
296 public function get_page_number() {
297 return $this->page_number;
298 }
299 /**
300 * Get the title of the feedback entry.
301 *
302 * @return string The title of the feedback entry.
303 */
304 public function get_title() {
305 return $this->title;
306 }
307 /**
308 * Get the post id of the feedback entry.
309 *
310 * @return int|string The ID of the feedback entry.
311 */
312 public function get_id() {
313 return $this->id;
314 }
315
316 /**
317 * Get the source type of the feedback entry.
318 *
319 * Possible values: single, widget, block_template, block_template_part.
320 *
321 * @return string The source type.
322 */
323 public function get_source_type() {
324 return $this->source_type;
325 }
326
327 /**
328 * Whether this feedback was submitted from a form preview (test submission).
329 *
330 * @return bool
331 */
332 public function is_test() {
333 return $this->is_test;
334 }
335
336 /**
337 * Flag this feedback as a test submission coming from form preview.
338 *
339 * @param bool $is_test Whether the feedback is a test submission.
340 * @return void
341 */
342 public function set_is_test( $is_test ) {
343 $this->is_test = (bool) $is_test;
344 }
345
346 /**
347 * Get the page number of the entry title.
348 *
349 * @return array
350 */
351 public function serialize() {
352 $data = array(
353 'entry_title' => $this->title,
354 'entry_page' => $this->page_number,
355 'source_id' => $this->id,
356 'source_type' => $this->source_type,
357 'request_url' => $this->request_url,
358 );
359
360 if ( $this->is_test ) {
361 $data['is_test'] = true;
362 }
363
364 return $data;
365 }
366 }
367