PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 12.7
Jetpack – WP Security, Backup, Speed, & Growth v12.7
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 13.9.2 14.0.1 14.1.1 14.2.2 14.3.1 All 501 releases
jetpack / modules / widgets / gallery.php

gallery.php in Jetpack – WP Security, Backup, Speed, & Growth 12.7, at modules/widgets/gallery.php

520 lines 16.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php // phpcs:ignore eWordPress.Files.FileName.InvalidClassFileName
2 /**
3 * Module Name: Gallery widget
4 *
5 * @package automattic/jetpack
6 */
7
8 // phpcs:disable Universal.Files.SeparateFunctionsFromOO.Mixed -- TODO: Move classes to appropriately-named class files.
9
10 use Automattic\Jetpack\Assets;
11 use Automattic\Jetpack\Image_CDN\Image_CDN_Core;
12
13 /**
14 * Jetpack_Gallery_Widget main class.
15 */
16 class Jetpack_Gallery_Widget extends WP_Widget {
17 const THUMB_SIZE = 45;
18 const DEFAULT_WIDTH = 265;
19
20 /**
21 * The width of the gallery widget.
22 * May be customized by the 'gallery_widget_content_width' filter.
23 *
24 * @var int
25 */
26 protected $instance_width;
27
28 /**
29 * Jetpack_Gallery_Widget constructor.
30 */
31 public function __construct() {
32 $widget_ops = array(
33 'classname' => 'widget-gallery',
34 'description' => __( 'Display a photo gallery or slideshow', 'jetpack' ),
35 'customize_selective_refresh' => true,
36 );
37
38 add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_scripts' ) );
39
40 parent::__construct(
41 'gallery',
42 /** This filter is documented in modules/widgets/facebook-likebox.php */
43 apply_filters( 'jetpack_widget_name', __( 'Gallery', 'jetpack' ) ),
44 $widget_ops
45 );
46
47 if ( is_customize_preview() ) {
48 add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_frontend_scripts' ) );
49
50 if ( class_exists( 'Jetpack_Tiled_Gallery' ) ) {
51 add_action( 'wp_enqueue_scripts', array( 'Jetpack_Tiled_Gallery', 'default_scripts_and_styles' ) );
52 }
53
54 if ( class_exists( 'Jetpack_Slideshow_Shortcode' ) ) {
55 $slideshow = new Jetpack_Slideshow_Shortcode();
56 add_action( 'wp_enqueue_scripts', array( $slideshow, 'enqueue_scripts' ) );
57 }
58
59 if ( class_exists( 'Jetpack_Carousel' ) ) {
60 $carousel = new Jetpack_Carousel();
61 add_action( 'wp_enqueue_scripts', array( $carousel, 'enqueue_assets' ) );
62 }
63 }
64 }
65
66 /**
67 * Display the widget.
68 *
69 * @param array $args Display arguments including before_title, after_title, before_widget, and after_widget.
70 * @param array $instance The settings for the particular instance of the widget.
71 */
72 public function widget( $args, $instance ) {
73 $instance = wp_parse_args( (array) $instance, $this->defaults() );
74
75 $this->enqueue_frontend_scripts();
76
77 $before_widget = isset( $args['before_widget'] ) ? $args['before_widget'] : '';
78 $before_title = isset( $args['before_title'] ) ? $args['before_title'] : '';
79 $after_title = isset( $args['after_title'] ) ? $args['after_title'] : '';
80 $after_widget = isset( $args['after_widget'] ) ? $args['after_widget'] : '';
81
82 $instance['attachments'] = $this->get_attachments( $instance );
83
84 $classes = array();
85
86 $classes[] = 'widget-gallery-' . $instance['type'];
87
88 /*
89 * Due to a bug in the carousel plugin,
90 * carousels will be triggered for all tiled galleries that exist on a page with other tiled galleries,
91 * regardless of whether or not the widget was set to Carousel mode.
92 * The onClick selector is simply too broad, since it was not written with widgets in mind.
93 * This special class prevents that behavior, via an override handler in gallery.js.
94 */
95 if ( 'carousel' !== $instance['link'] && 'slideshow' !== $instance['type'] ) {
96 $classes[] = 'no-carousel';
97 } else {
98 $classes[] = 'carousel';
99 }
100
101 $classes = implode( ' ', $classes );
102
103 if ( 'carousel' === $instance['link'] ) {
104 require_once plugin_dir_path( realpath( __DIR__ . '/../carousel/jetpack-carousel.php' ) ) . 'jetpack-carousel.php';
105
106 if ( class_exists( 'Jetpack_Carousel' ) ) {
107 // Create new carousel so we can use the enqueue_assets() method. Not ideal, but there is a decent amount
108 // of logic in that method that shouldn't be duplicated.
109 $carousel = new Jetpack_Carousel();
110
111 // First parameter is $output, which comes from filters, and causes bypass of the asset enqueuing. Passing null is correct.
112 $carousel->enqueue_assets( null );
113 }
114 }
115
116 echo $before_widget . "\n"; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
117
118 /** This filter is documented in core/src/wp-includes/default-widgets.php */
119 $title = apply_filters( 'widget_title', $instance['title'] );
120
121 if ( $title ) {
122 echo $before_title . $title . $after_title . "\n"; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
123 }
124
125 echo '<div class="' . esc_attr( $classes ) . '">' . "\n";
126
127 $method = $instance['type'] . '_widget';
128
129 /**
130 * Allow the width of a gallery to be altered by themes or other code.
131 *
132 * @module widgets
133 *
134 * @since 2.5.0
135 *
136 * @param int self::DEFAULT_WIDTH Default gallery width. Default is 265.
137 * @param string $args Display arguments including before_title, after_title, before_widget, and after_widget.
138 * @param array $instance The settings for the particular instance of the widget.
139 */
140 $this->instance_width = apply_filters( 'gallery_widget_content_width', self::DEFAULT_WIDTH, $args, $instance );
141
142 // Register a filter to modify the tiled_gallery_content_width, so Jetpack_Tiled_Gallery
143 // can appropriately size the tiles.
144 add_filter( 'tiled_gallery_content_width', array( $this, 'tiled_gallery_content_width' ) );
145
146 if ( method_exists( $this, $method ) ) {
147 echo $this->$method( $args, $instance ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
148 }
149
150 // Remove the stored $instance_width, as it is no longer needed.
151 $this->instance_width = null;
152
153 // Remove the filter, so any Jetpack_Tiled_Gallery in a post is not affected.
154 remove_filter( 'tiled_gallery_content_width', array( $this, 'tiled_gallery_content_width' ) );
155
156 echo "\n" . '</div>'; // .widget-gallery-$type
157
158 echo "\n" . $after_widget; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
159
160 /** This action is documented in modules/widgets/gravatar-profile.php */
161 do_action( 'jetpack_stats_extra', 'widget_view', 'gallery' );
162 }
163
164 /**
165 * Fetch the images attached to the gallery Widget
166 *
167 * @param array $instance The Widget instance for which you'd like attachments.
168 * @return array Array of attachment objects for the Widget in $instance
169 */
170 public function get_attachments( $instance ) {
171 $ids = explode( ',', $instance['ids'] );
172
173 if ( isset( $instance['random'] ) && 'on' === $instance['random'] ) {
174 shuffle( $ids );
175 }
176
177 $attachments_query = new WP_Query(
178 array(
179 'post__in' => $ids,
180 'post_status' => 'inherit',
181 'post_type' => 'attachment',
182 'post_mime_type' => 'image',
183 'posts_per_page' => -1,
184 'orderby' => 'post__in',
185 )
186 );
187
188 $attachments = $attachments_query->get_posts();
189
190 wp_reset_postdata();
191
192 return $attachments;
193 }
194
195 /**
196 * Generate HTML for a rectangular, tiled Widget
197 *
198 * @param array $args Display arguments including before_title, after_title, before_widget, and after_widget.
199 * @param array $instance The Widget instance to generate HTML for.
200 * @return string String of HTML representing a rectangular gallery
201 */
202 public function rectangular_widget( $args, $instance ) {
203 if ( ! class_exists( 'Jetpack_Tiled_Gallery' )
204 && ! class_exists( 'Jetpack_Tiled_Gallery_Layout_Rectangular' ) ) {
205 return;
206 }
207
208 Jetpack_Tiled_Gallery::default_scripts_and_styles();
209
210 $layout = new Jetpack_Tiled_Gallery_Layout_Rectangular( $instance['attachments'], $instance['link'], false, 3 );
211 return $layout->HTML();
212 }
213
214 /**
215 * Generate HTML for a square (grid style) Widget
216 *
217 * @param array $args Display arguments including before_title, after_title, before_widget, and after_widget.
218 * @param array $instance The Widget instance to generate HTML for.
219 * @return string String of HTML representing a square gallery
220 */
221 public function square_widget( $args, $instance ) {
222 if ( ! class_exists( 'Jetpack_Tiled_Gallery' )
223 && ! class_exists( 'Jetpack_Tiled_Gallery_Layout_Square' ) ) {
224 return;
225 }
226
227 Jetpack_Tiled_Gallery::default_scripts_and_styles();
228
229 $layout = new Jetpack_Tiled_Gallery_Layout_Square( $instance['attachments'], $instance['link'], false, 3 );
230 return $layout->HTML();
231 }
232
233 /**
234 * Generate HTML for a circular (grid style) Widget
235 *
236 * @param array $args Display arguments including before_title, after_title, before_widget, and after_widget.
237 * @param array $instance The Widget instance to generate HTML for.
238 * @return string String of HTML representing a circular gallery
239 */
240 public function circle_widget( $args, $instance ) {
241 if ( ! class_exists( 'Jetpack_Tiled_Gallery' )
242 && ! class_exists( 'Jetpack_Tiled_Gallery_Layout_Circle' ) ) {
243 return;
244 }
245
246 Jetpack_Tiled_Gallery::default_scripts_and_styles();
247
248 $layout = new Jetpack_Tiled_Gallery_Layout_Circle( $instance['attachments'], $instance['link'], false, 3 );
249 return $layout->HTML();
250 }
251
252 /**
253 * Generate HTML for a slideshow Widget
254 *
255 * @todo Is slideshow_widget() still used?
256 *
257 * @param array $args Display arguments including before_title, after_title, before_widget, and after_widget.
258 * @param array $instance The Widget instance to generate HTML for.
259 * @return string String of HTML representing a slideshow gallery
260 */
261 public function slideshow_widget( $args, $instance ) {
262 global $content_width;
263
264 require_once plugin_dir_path( realpath( __DIR__ . '/../shortcodes/slideshow.php' ) ) . 'slideshow.php';
265
266 if ( ! class_exists( 'Jetpack_Slideshow_Shortcode' ) ) {
267 return;
268 }
269
270 if ( count( $instance['attachments'] ) < 1 ) {
271 return;
272 }
273
274 $slideshow = new Jetpack_Slideshow_Shortcode();
275
276 $slideshow->enqueue_scripts();
277
278 $gallery_instance = 'widget-' . $args['widget_id'];
279
280 $gallery = array();
281
282 foreach ( $instance['attachments'] as $attachment ) {
283 $attachment_image_src = wp_get_attachment_image_src( $attachment->ID, 'full' );
284 $attachment_image_src = Image_CDN_Core::cdn_url( $attachment_image_src[0], array( 'w' => $this->instance_width ) ); /** [url, width, height] */
285
286 $caption = wptexturize( wp_strip_all_tags( $attachment->post_excerpt ) );
287
288 $gallery[] = (object) array(
289 'src' => (string) esc_url_raw( $attachment_image_src ),
290 'id' => (string) $attachment->ID,
291 'caption' => (string) $caption,
292 );
293 }
294
295 $max_width = (int) get_option( 'large_size_w' );
296 $max_height = 175;
297
298 if ( (int) $content_width > 0 ) {
299 $max_width = min( (int) $content_width, $max_width );
300 }
301
302 $color = Jetpack_Options::get_option( 'slideshow_background_color', 'black' );
303 $js_attr = array(
304 'gallery' => $gallery,
305 'selector' => $gallery_instance,
306 'width' => $max_width,
307 'height' => $max_height,
308 'trans' => 'fade',
309 'color' => $color,
310 'autostart' => true,
311 );
312
313 $html = $slideshow->slideshow_js( $js_attr );
314
315 return $html;
316 }
317
318 /**
319 * Used to adjust the content width of Jetpack_Tiled_Gallery's in sidebars
320 *
321 * $this->instance_width is filtered in widget() and this filter is added then removed in widget()
322 *
323 * @return int The filtered width
324 */
325 public function tiled_gallery_content_width() {
326 return $this->instance_width;
327 }
328
329 /**
330 * Outputs the widget settings form.
331 *
332 * @param array $instance Current settings.
333 */
334 public function form( $instance ) {
335 $defaults = $this->defaults();
336 $allowed_values = $this->allowed_values(); // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- Used in included form template.
337
338 $instance = wp_parse_args( (array) $instance, $defaults );
339
340 include __DIR__ . '/gallery/templates/form.php';
341 }
342
343 /**
344 * Save the widget options.
345 *
346 * @param array $new_instance The new instance options.
347 * @param array $old_instance The old instance options.
348 * @return array The saved options.
349 */
350 public function update( $new_instance, $old_instance ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
351 $instance = $this->sanitize( $new_instance );
352
353 return $instance;
354 }
355
356 /**
357 * Sanitize the $instance's values to the set of allowed values. If a value is not acceptable,
358 * it is set to its default.
359 *
360 * Helps keep things nice and secure by listing only allowed values.
361 *
362 * @param array $instance The Widget instance to sanitize values for.
363 * @return array $instance The Widget instance with values sanitized
364 */
365 public function sanitize( $instance ) {
366 $allowed_values = $this->allowed_values();
367 $defaults = $this->defaults();
368
369 foreach ( $instance as $key => $value ) {
370 if ( ! is_scalar( $value ) ) {
371 // $instance may hold an Array value type for the Jetpack widget visibility feature.
372 continue;
373 }
374
375 $value = trim( $value );
376
377 if ( isset( $allowed_values[ $key ] ) && $allowed_values[ $key ] && ! array_key_exists( $value, $allowed_values[ $key ] ) ) {
378 $instance[ $key ] = $defaults[ $key ];
379 } else {
380 $instance[ $key ] = sanitize_text_field( $value );
381 }
382 }
383
384 return $instance;
385 }
386
387 /**
388 * Return a multi-dimensional array of allowed values (and their labels) for all widget form
389 * elements
390 *
391 * To allow all values on an input, omit it from the returned array
392 *
393 * @return array Array of allowed values for each option
394 */
395 public function allowed_values() {
396 $max_columns = 5;
397
398 // Create an associative array of allowed column values. This just automates the generation of
399 // column <option>s, from 1 to $max_columns.
400 $allowed_columns = array_combine( range( 1, $max_columns ), range( 1, $max_columns ) );
401
402 return array(
403 'type' => array(
404 'rectangular' => __( 'Tiles', 'jetpack' ),
405 'square' => __( 'Square Tiles', 'jetpack' ),
406 'circle' => __( 'Circles', 'jetpack' ),
407 'slideshow' => __( 'Slideshow', 'jetpack' ),
408 ),
409 'columns' => $allowed_columns,
410 'link' => array(
411 'carousel' => __( 'Carousel', 'jetpack' ),
412 'post' => __( 'Attachment Page', 'jetpack' ),
413 'file' => __( 'Media File', 'jetpack' ),
414 ),
415 );
416 }
417
418 /**
419 * Return an associative array of default values
420 *
421 * These values are used in new widgets as well as when sanitizing input. If a given value is not allowed,
422 * as defined in allowed_values(), that input is set to the default value defined here.
423 *
424 * @return array Array of default values for the Widget's options
425 */
426 public function defaults() {
427 return array(
428 'title' => '',
429 'type' => 'rectangular',
430 'ids' => '',
431 'columns' => 3,
432 'link' => 'carousel',
433 );
434 }
435
436 /**
437 * Enqueue frontend scripts.
438 */
439 public function enqueue_frontend_scripts() {
440 wp_register_script(
441 'gallery-widget',
442 Assets::get_file_url_for_environment(
443 '_inc/build/widgets/gallery/js/gallery.min.js',
444 'modules/widgets/gallery/js/gallery.js'
445 ),
446 array( 'jquery' ),
447 JETPACK__VERSION,
448 false
449 );
450
451 wp_enqueue_script( 'gallery-widget' );
452 }
453
454 /**
455 * Enqueue admin scripts and styles.
456 */
457 public function enqueue_admin_scripts() {
458 global $pagenow;
459
460 if ( 'widgets.php' === $pagenow || 'customize.php' === $pagenow ) {
461 wp_enqueue_media();
462
463 wp_enqueue_script(
464 'gallery-widget-admin',
465 Assets::get_file_url_for_environment(
466 '_inc/build/widgets/gallery/js/admin.min.js',
467 'modules/widgets/gallery/js/admin.js'
468 ),
469 array(
470 'jquery',
471 'media-models',
472 'media-views',
473 ),
474 '20150501',
475 false
476 );
477
478 $js_settings = array(
479 'thumbSize' => self::THUMB_SIZE,
480 );
481
482 wp_localize_script( 'gallery-widget-admin', '_wpGalleryWidgetAdminSettings', $js_settings );
483 wp_enqueue_style(
484 'gallery-widget-admin',
485 plugins_url( '/gallery/css/admin.css', __FILE__ ),
486 array(),
487 JETPACK__VERSION
488 );
489 wp_style_add_data( 'gallery-widget-admin', 'rtl', 'replace' );
490 }
491 }
492 }
493
494 add_action( 'widgets_init', 'jetpack_gallery_widget_init' );
495
496 /**
497 * Jetpack Gallery widget init; the widget is conditionally registered.
498 */
499 function jetpack_gallery_widget_init() {
500 /**
501 * Allow the Gallery Widget to be enabled even when Core supports the Media Gallery Widget
502 *
503 * @module widgets
504 *
505 * @since 5.5.0
506 *
507 * @param bool false Whether to force-enable the gallery widget
508 */
509 if (
510 ! apply_filters( 'jetpack_force_enable_gallery_widget', false )
511 && class_exists( 'WP_Widget_Media_Gallery' )
512 && Jetpack_Options::get_option( 'gallery_widget_migration' )
513 ) {
514 return;
515 }
516 if ( ! method_exists( 'Jetpack', 'is_module_active' ) || Jetpack::is_module_active( 'tiled-gallery' ) ) {
517 register_widget( 'Jetpack_Gallery_Widget' );
518 }
519 }
520