PluginProbe
Sharing Image / 2.0.13
Sharing Image v2.0.13
3.10 trunk 2.0 2.0.0 2.0.1 2.0.10 2.0.11 2.0.12 2.0.13 2.0.14 2.0.15 2.0.16 2.0.17 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8 2.0.9 3.0 3.1 3.2 3.3 All 29 releases
sharing-image / classes / class-widget.php

class-widget.php in Sharing Image 2.0.13, at classes/class-widget.php

584 lines 13.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Widget class
4 *
5 * @package sharing-image
6 * @author Anton Lukin
7 */
8
9 namespace Sharing_Image;
10
11 if ( ! defined( 'ABSPATH' ) ) {
12 die;
13 }
14
15 /**
16 * Widget class
17 *
18 * @class Widget
19 */
20 class Widget {
21 /**
22 * Post meta key to store poster image.
23 *
24 * @var string
25 */
26 const WIDGET_META = '_sharing_image';
27
28 /**
29 * The instance of Settings class.
30 *
31 * @var instance
32 */
33 private $settings;
34
35 /**
36 * Widget constructor.
37 */
38 public function __construct() {
39 $this->settings = new Settings();
40 }
41
42 /**
43 * Init class actions and filters.
44 */
45 public function init() {
46 // Init taxonomy term widget.
47 add_action( 'admin_init', array( $this, 'init_taxonomy_widget' ) );
48
49 // Init post metabox widget.
50 add_action( 'admin_init', array( $this, 'init_metabox_widget' ) );
51
52 // Handle metabox AJAX requests.
53 add_action( 'admin_init', array( $this, 'handle_ajax_requests' ) );
54
55 // Try to autogenerate poster if it is needed.
56 add_action( 'wp_insert_post', array( $this, 'autogenerate_poster' ) );
57 }
58
59 /**
60 * Init metabox on post editing page.
61 */
62 public function init_metabox_widget() {
63 /**
64 * Easy way to hide metabox.
65 *
66 * @param bool $hide_metabox Set true to hide metabox.
67 */
68 $hide_metabox = apply_filters( 'sharing_image_hide_metabox', false );
69
70 if ( $hide_metabox ) {
71 return;
72 }
73
74 add_action( 'add_meta_boxes', array( $this, 'add_metabox' ) );
75
76 // Handle actions on post save.
77 add_action( 'save_post', array( $this, 'save_metabox' ), 10, 2 );
78
79 // Add required assets and objects.
80 add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_metabox_assets' ) );
81 }
82
83 /**
84 * Init widget on taxonomy term editing page.
85 */
86 public function init_taxonomy_widget() {
87 // Skip if the Premium is not active.
88 if ( ! $this->settings->is_premium_features() ) {
89 return;
90 }
91
92 $taxonomies = $this->get_widget_taxonomies();
93
94 foreach ( $taxonomies as $taxonomy ) {
95 // Display taxonomy term widget.
96 add_action( $taxonomy . '_edit_form', array( $this, 'display_widget' ), 10, 2 );
97
98 // Save taxonomy term meta.
99 add_action( 'edited_' . $taxonomy, array( $this, 'save_taxonomy' ) );
100
101 // Enqueue term assets.
102 add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_taxonomy_assets' ) );
103 }
104 }
105
106 /**
107 * Add metabox to post editing page.
108 */
109 public function add_metabox() {
110 add_meta_box(
111 'sharing-image-metabox',
112 esc_html__( 'Sharing Image', 'sharing image' ),
113 array( $this, 'display_widget' ),
114 $this->get_metabox_post_types(),
115 'side'
116 );
117 }
118
119 /**
120 * Add metabox scripts and styles to admin page.
121 *
122 * @param string $hook_suffix The current admin page.
123 */
124 public function enqueue_metabox_assets( $hook_suffix ) {
125 if ( ! in_array( $hook_suffix, array( 'post.php', 'post-new.php' ), true ) ) {
126 return;
127 }
128
129 $screen = get_current_screen();
130
131 if ( ! in_array( $screen->post_type, $this->get_metabox_post_types(), true ) ) {
132 return;
133 }
134
135 $post = get_post();
136
137 // Get post meta for current post ID.
138 $meta = get_post_meta( $post->ID, self::WIDGET_META, true );
139
140 $this->enqueue_scripts( $this->create_script_object( $meta, 'metabox' ) );
141 $this->enqueue_styles();
142 }
143
144 /**
145 * Add widget scripts and styles to admin page.
146 *
147 * @param string $hook_suffix The current admin page.
148 */
149 public function enqueue_taxonomy_assets( $hook_suffix ) {
150 if ( 'term.php' !== $hook_suffix ) {
151 return;
152 }
153
154 $screen = get_current_screen();
155
156 if ( ! in_array( $screen->taxonomy, $this->get_widget_taxonomies(), true ) ) {
157 return;
158 }
159
160 // phpcs:disable WordPress.Security.NonceVerification
161 if ( ! isset( $_REQUEST['tag_ID'] ) ) {
162 return;
163 }
164
165 $term_id = absint( $_REQUEST['tag_ID'] );
166 // phpcs:enable WordPress.Security.NonceVerification
167
168 // Get term meta for current term ID.
169 $meta = get_term_meta( $term_id, self::WIDGET_META, true );
170
171 $this->enqueue_scripts( $this->create_script_object( $meta, 'taxonomy' ) );
172 $this->enqueue_styles();
173 }
174
175 /**
176 * Save metabox data.
177 *
178 * @param int $post_id Post ID.
179 * @param WP_Post $post Post object.
180 */
181 public function save_metabox( $post_id, $post ) {
182 if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
183 return;
184 }
185
186 if ( wp_is_post_revision( $post_id ) ) {
187 return;
188 }
189
190 if ( ! current_user_can( 'edit_post', $post_id ) ) {
191 return;
192 }
193
194 if ( ! isset( $_POST['sharing_image_nonce'] ) ) {
195 return;
196 }
197
198 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
199 if ( ! wp_verify_nonce( $_POST['sharing_image_nonce'], basename( __FILE__ ) ) ) {
200 return;
201 }
202
203 if ( ! isset( $_POST['sharing_image_picker'] ) ) {
204 return;
205 }
206
207 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
208 $meta = $this->sanitize_picker( wp_unslash( $_POST['sharing_image_picker'] ) );
209
210 /**
211 * Filters updated post meta.
212 *
213 * @param string $meta Updated post meta.
214 * @param string $post_id Post ID.
215 */
216 $meta = apply_filters( 'sharing_image_update_post_meta', $meta, $post_id );
217
218 // Update post meta.
219 update_post_meta( $post_id, self::WIDGET_META, $meta );
220 }
221
222 /**
223 * Save taxonomy fields.
224 *
225 * @param int $term_id Term ID.
226 */
227 public function save_taxonomy( $term_id ) {
228 if ( ! isset( $_POST['sharing_image_nonce'] ) ) {
229 return;
230 }
231
232 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
233 if ( ! wp_verify_nonce( $_POST['sharing_image_nonce'], basename( __FILE__ ) ) ) {
234 return;
235 }
236
237 if ( ! current_user_can( 'edit_term', $term_id ) ) {
238 return;
239 }
240
241 if ( ! isset( $_POST['sharing_image_picker'] ) ) {
242 return;
243 }
244
245 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
246 $meta = $this->sanitize_picker( wp_unslash( $_POST['sharing_image_picker'] ) );
247
248 /**
249 * Filters term meta on update.
250 *
251 * @param string $meta Updated term meta.
252 * @param string $term_id Term ID.
253 */
254 $meta = apply_filters( 'sharing_image_update_term_meta', $meta, $term_id );
255
256 update_term_meta( $term_id, self::WIDGET_META, $meta );
257 }
258
259 /**
260 * Display widget.
261 */
262 public function display_widget() {
263 include_once SHARING_IMAGE_DIR . 'templates/widget.php';
264
265 /**
266 * Fires on widget template including.
267 */
268 do_action( 'sharing_image_widget' );
269 }
270
271 /**
272 * Handle widget AJAX requests.
273 */
274 public function handle_ajax_requests() {
275 $actions = array(
276 'generate' => 'generate_poster',
277 'rebuild' => 'rebuild_metabox',
278 );
279
280 foreach ( $actions as $key => $method ) {
281 $action = 'sharing_image_' . $key;
282
283 if ( method_exists( $this, $method ) ) {
284 add_action( 'wp_ajax_' . $action, array( $this, $method ) );
285 }
286 }
287 }
288
289 /**
290 * Generate poster by AJAX request.
291 */
292 public function generate_poster() {
293 $check = check_ajax_referer( basename( __FILE__ ), 'sharing_image_nonce', false );
294
295 if ( false === $check ) {
296 wp_send_json_error( __( 'Invalid security token. Reload the page and retry.', 'sharing-image' ), 403 );
297 }
298
299 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
300 $picker = $this->sanitize_picker( wp_unslash( $_POST['sharing_image_picker'] ) );
301
302 // Compose new poster data.
303 $source = ( new Generator() )->compose( $picker );
304
305 if ( is_wp_error( $source ) ) {
306 wp_send_json_error( $source->get_error_message(), 400 );
307 }
308
309 wp_send_json_success( $source );
310 }
311
312 /**
313 * Send metabox config object to rebuild it on frontend.
314 */
315 public function rebuild_metabox() {
316 $check = check_ajax_referer( basename( __FILE__ ), 'sharing_image_nonce', false );
317
318 if ( false === $check ) {
319 wp_send_json_error( __( 'Invalid security token. Reload the page and retry.', 'sharing-image' ), 403 );
320 }
321
322 if ( empty( $_POST['post'] ) ) {
323 return;
324 }
325
326 $post_id = absint( $_POST['post'] );
327
328 // Get post meta for current post ID.
329 $meta = get_post_meta( $post_id, self::WIDGET_META, true );
330
331 wp_send_json_success( $this->create_script_object( $meta, 'metabox' ) );
332 }
333
334 /**
335 * Try to autogenerate poster on post insert or update.
336 *
337 * @param integer $post_id Updated post_id.
338 */
339 public function autogenerate_poster( $post_id ) {
340 /**
341 * Easy way disable autogeneration.
342 *
343 * @since 2.0.12
344 *
345 * @param bool $disable_autogeneration Set true to disable autogeneration.
346 * @param int $post_id Post ID.
347 */
348 $disable_autogeneration = apply_filters( 'sharing_image_disable_autogeneration', false, $post_id );
349
350 if ( $disable_autogeneration ) {
351 return;
352 }
353
354 $status = get_post_status( $post_id );
355
356 if ( 'auto-draft' === $status ) {
357 return;
358 }
359
360 $meta = get_post_meta( $post_id, self::WIDGET_META, true );
361
362 if ( empty( $meta ) ) {
363 $meta = array();
364 }
365
366 if ( ! empty( $meta['poster'] ) ) {
367 return;
368 }
369
370 $config = $this->settings->get_config();
371
372 if ( ! isset( $config['autogenerate'] ) ) {
373 return;
374 }
375
376 if ( 'manual' === $config['autogenerate'] ) {
377 return;
378 }
379
380 $meta['template'] = absint( $config['autogenerate'] );
381
382 // Generate new poster data using post data.
383 $source = ( new Generator() )->autogenerate( $meta['template'], $post_id );
384
385 /**
386 * Filters autogenerated poster data.
387 *
388 * @since 2.0.11
389 *
390 * @param array|false $poster Poster image, width and height data or false if undefined.
391 * @param integer $post_id Post ID.
392 */
393 $source = apply_filters( 'sharing_image_autogenerated_poster', $source, $post_id );
394
395 if ( empty( $source ) ) {
396 return;
397 }
398
399 $meta = wp_parse_args( $source, $meta );
400
401 // Update post meta with new poster link.
402 update_post_meta( $post_id, self::WIDGET_META, $meta );
403 }
404
405 /**
406 * Enqueue widget styles.
407 */
408 private function enqueue_styles() {
409 wp_enqueue_style(
410 'sharing-image-widget',
411 SHARING_IMAGE_URL . 'assets/styles/widget.css',
412 array(),
413 SHARING_IMAGE_VERSION,
414 'all'
415 );
416 }
417
418 /**
419 * Enqueue widget scripts.
420 *
421 * @param array $object Widget data object.
422 */
423 private function enqueue_scripts( $object ) {
424 wp_enqueue_media();
425
426 wp_enqueue_script(
427 'sharing-image-widget',
428 SHARING_IMAGE_URL . 'assets/scripts/widget.js',
429 array( 'wp-i18n', 'wp-polyfill-formdata' ),
430 SHARING_IMAGE_VERSION,
431 true
432 );
433
434 wp_set_script_translations( 'sharing-image-settings', 'sharing-image' );
435
436 // Add widget script object.
437 wp_localize_script( 'sharing-image-widget', 'sharingImageWidget', $object );
438 }
439
440 /**
441 * Sanitize picker widget data before saving.
442 *
443 * @param array $picker Widget POST data.
444
445 * @return array Sanitized picker fields.
446 */
447 private function sanitize_picker( $picker ) {
448 $sanitized = array();
449
450 if ( isset( $picker['poster'] ) ) {
451 $sanitized['poster'] = sanitize_text_field( $picker['poster'] );
452 }
453
454 if ( ! empty( $picker['width'] ) ) {
455 $sanitized['width'] = absint( $picker['width'] );
456 }
457
458 if ( ! empty( $picker['height'] ) ) {
459 $sanitized['height'] = absint( $picker['height'] );
460 }
461
462 $template = 0;
463
464 if ( isset( $picker['template'] ) ) {
465 $template = absint( $picker['template'] );
466
467 if ( count( $this->settings->get_templates() ) <= $template ) {
468 $template = 0;
469 }
470 }
471
472 $sanitized['template'] = $template;
473
474 if ( isset( $picker['fieldset'] ) ) {
475 $fieldset = $picker['fieldset'];
476
477 foreach ( $fieldset as $key => $fields ) {
478 $sanitized['fieldset'][ $key ] = $this->sanitize_fieldset( $fields );
479 }
480 }
481
482 /**
483 * Filters widget picker sanitized fields.
484 *
485 * @param array $sanitized List of sanitized picker fields.
486 * @param array $picker List of picker fields before sanitization.
487 */
488 return apply_filters( 'sharing_image_sanitize_picker', $sanitized, $picker );
489 }
490
491 /**
492 * Sanitize picker widget fieldset list.
493 *
494 * @param array $fields Fieldset widget list.
495 *
496 * @return array Sanitized fieldset data.
497 */
498 public function sanitize_fieldset( $fields ) {
499 $sanitized = array();
500
501 if ( ! empty( $fields['captions'] ) && is_array( $fields['captions'] ) ) {
502 $sanitized['captions'] = array_map( 'sanitize_textarea_field', $fields['captions'] );
503 }
504
505 if ( ! empty( $fields['attachment'] ) ) {
506 $sanitized['attachment'] = absint( $fields['attachment'] );
507 }
508
509 return $sanitized;
510 }
511
512 /**
513 * Create script object to inject with widget.
514 *
515 * @param array $meta Term or Post meta data.
516 * @param string $context Widget context. For example: metabox or taxonomy.
517
518 * @return array Filtered widget script object.
519 */
520 private function create_script_object( $meta, $context ) {
521 $object = array(
522 'meta' => $meta,
523 'nonce' => wp_create_nonce( basename( __FILE__ ) ),
524 'context' => $context,
525
526 'links' => array(
527 'uploads' => esc_url( admin_url( 'upload.php' ) ),
528 ),
529
530 'templates' => $this->settings->get_templates(),
531 );
532
533 /**
534 * Filter widget script object.
535 *
536 * @param array $object Array of widget script object.
537 */
538 return apply_filters( 'sharing_image_widget_object', $object );
539 }
540
541 /**
542 * Get an array of post types where the metabox is displayed.
543 *
544 * @return array Array of post types.
545 */
546 private function get_metabox_post_types() {
547 $post_types = get_post_types(
548 array(
549 'public' => true,
550 )
551 );
552
553 unset( $post_types['attachment'] );
554
555 /**
556 * Filter widget post types.
557 *
558 * @param array $post_types Array of post types for which the metabox is displayed.
559 */
560 return apply_filters( 'sharing_image_metabox_post_types', array_values( $post_types ) );
561 }
562
563 /**
564 * Get an array of taxonomeis where the widget is displayed.
565 *
566 * @return array Array of taxonomies.
567 */
568 private function get_widget_taxonomies() {
569 $taxonomies = get_taxonomies(
570 array(
571 'public' => true,
572 'show_ui' => true,
573 )
574 );
575
576 /**
577 * Filter the taxonomies where we need to show the poster settings.
578 *
579 * @param array $taxonomies List of taxonomies to show settings.
580 */
581 return apply_filters( 'sharing_image_widget_taxonomies', array_values( $taxonomies ) );
582 }
583 }
584