PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 11.2
Jetpack – WP Security, Backup, Speed, & Growth v11.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 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 11.2, at modules/widgets/gallery.php

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