PluginProbe
Automatic YouTube Gallery – Embed Auto-Updating YouTube Video Galleries, Feeds, Playlists & Channels / 2.7.2
Automatic YouTube Gallery – Embed Auto-Updating YouTube Video Galleries, Feeds, Playlists & Channels v2.7.2
2.9.1 2.9.0 trunk 1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 2.0.0 2.1.0 2.2.0 2.3.2 2.3.3 2.3.5 2.3.6 2.3.8 2.3.9 2.4.3 All 37 releases
automatic-youtube-gallery / includes / functions.php

functions.php in Automatic YouTube Gallery – Embed Auto-Updating YouTube Video Galleries, Feeds, Playlists & Channels 2.7.2, at includes/functions.php

1,288 lines 43.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Helper Functions.
5 *
6 * @link https://plugins360.com
7 * @since 1.0.0
8 *
9 * @package Automatic_YouTube_Gallery
10 */
11
12 // Exit if accessed directly
13 if ( ! defined( 'WPINC' ) ) {
14 die;
15 }
16
17 /**
18 * Build gallery HTML output.
19 *
20 * @since 1.0.0
21 * @param array $args An array of gallery options.
22 * @return mixed
23 */
24 function ayg_build_gallery( $args ) {
25 $general_settings = ayg_get_option( 'ayg_general_settings' );
26 $strings_settings = ayg_get_option( 'ayg_strings_settings' );
27
28 global $post;
29
30 // Vars
31 $fields = ayg_get_editor_fields();
32 $excluded_fields = array( 'popup' ); // Fields not part of attributes
33 $defaults = array();
34
35 foreach ( $fields as $key => $value ) {
36 foreach ( $value['fields'] as $field ) {
37 if ( in_array( $field['name'], $excluded_fields ) ) {
38 continue;
39 }
40
41 $defaults[ $field['name'] ] = $field['value'];
42 }
43 }
44
45 $defaults = array_merge( $defaults, (array) $strings_settings );
46 $attributes = shortcode_atts( $defaults, $args, 'automatic_youtube_gallery' );
47
48 $attributes['post_id'] = 0;
49 if ( isset( $post->ID ) ) {
50 $attributes['post_id'] = (int) $post->ID;
51 }
52
53 $attributes['columns'] = min( 12, (int) $attributes['columns'] );
54 if ( empty( $attributes['columns'] ) ) {
55 $attributes['columns'] = 3;
56 }
57
58 $attributes['limit'] = min( 500, (int) $attributes['limit'] );
59 if ( empty( $attributes['limit'] ) ) {
60 $attributes['limit'] = 500;
61 }
62
63 $attributes['per_page'] = min( 50, (int) $attributes['per_page'] );
64 if ( empty( $attributes['per_page'] ) ) {
65 $attributes['per_page'] = 50;
66 }
67
68 $source_type = sanitize_text_field( $attributes['type'] );
69 if ( 'livestream' == $source_type ) {
70 $attributes['livestream'] = $attributes['channel'];
71 }
72
73 $attributes['lazyload'] = 0;
74 if ( ! empty( $general_settings['lazyload'] ) ) {
75 $attributes['lazyload'] = 1;
76 }
77
78 $source_url = sanitize_text_field( $attributes[ $source_type ] );
79
80 if ( isset( $args['uid'] ) && ! empty( $args['uid'] ) ) {
81 $attributes['uid'] = sanitize_text_field( $args['uid'] );
82 } else {
83 $attributes['uid'] = md5( $source_type . $source_url );
84 }
85
86 $attributes['uid'] = apply_filters( 'ayg_gallery_id', $attributes['uid'], $args );
87
88 // Deprecated since v2.5.8. Retained for backward compatibility.
89 $deprecated_uid = md5( $source_type . $source_url . sanitize_text_field( $attributes['theme'] ) ); // Deprecated
90 if ( isset( $args['deprecated_uid'] ) && ! empty( $args['deprecated_uid'] ) ) {
91 $deprecated_uid = sanitize_text_field( $args['deprecated_uid'] );
92 }
93
94 // Get Videos
95 $api_params = array(
96 'uid' => $attributes['uid'],
97 'type' => $source_type,
98 'src' => $source_url,
99 'order' => sanitize_text_field( $attributes['order'] ), // Works only when type = "search".
100 'limit' => $attributes['limit'], // Works only when type = "search".
101 'maxResults' => $attributes['per_page'],
102 'cache' => (int) $attributes['cache']
103 );
104
105 $api_params = apply_filters( 'ayg_youtube_api_request_params', $api_params, $args );
106
107 $youtube_api = new AYG_YouTube_API();
108 $response = $youtube_api->query( $api_params );
109
110 // Process output
111 if ( ! isset( $response->error ) ) {
112 // Store Gallery ID
113 if ( $attributes['post_id'] > 0 && isset( $attributes['deeplinking'] ) && 1 == $attributes['deeplinking'] ) {
114 $pages = ayg_get_option( 'ayg_gallery_page_ids' );
115 $page_id = $attributes['post_id'];
116
117 if ( ! in_array( $page_id, $pages ) ) {
118 $pages[] = $page_id;
119 update_option( 'ayg_gallery_page_ids', $pages );
120 }
121 }
122
123 // Gallery
124 $videos = array();
125
126 $gallery_id_from_url = get_query_var( 'ayg_gallery_id' );
127 $video_id_from_url = get_query_var( 'ayg_video_id' );
128
129 if ( $attributes['uid'] == $gallery_id_from_url || $deprecated_uid == $gallery_id_from_url ) {
130 $video = ayg_db_get_video( $video_id_from_url );
131
132 if ( $video ) {
133 $videos[] = $video;
134 } else {
135 $video_id_from_url = '';
136 }
137 }
138
139 if ( isset( $response->videos ) ) {
140 if ( ! empty( $video_id_from_url ) ) {
141 foreach ( $response->videos as $video ) {
142 if ( $video->id != $video_id_from_url ) {
143 $videos[] = $video;
144 }
145 }
146 } else {
147 $videos = $response->videos;
148 }
149 }
150
151 // Pagination
152 if ( isset( $response->page_info ) ) {
153 $attributes = array_merge( $attributes, $api_params, $response->page_info );
154 }
155
156 // Theme
157 $theme = 'classic';
158
159 if ( 'video' == $source_type ) {
160 $theme = 'single';
161 } elseif ( 'livestream' == $source_type ) {
162 $theme = 'livestream';
163 } else {
164 if ( 1 == count( $videos ) ) {
165 $theme = 'single';
166 }
167 }
168
169 // Enqueue dependencies
170 wp_enqueue_style( AYG_SLUG . '-public' );
171
172 wp_enqueue_script( AYG_SLUG . '-public' );
173 if ( $attributes['theme'] == $theme && 'classic' == $attributes['theme'] ) {
174 wp_enqueue_script( AYG_SLUG . '-theme-classic' );
175 }
176
177 // Output
178 ob_start();
179 include ayg_get_template( AYG_DIR . "public/templates/theme-{$theme}.php", $attributes['theme'] );
180 return ob_get_clean();
181 } else {
182 return sprintf( '<div class="ayg ayg-error">%s</div>', wp_kses_post( $response->error_message ) );
183 }
184 }
185
186 /**
187 * Combine video attributes as a string.
188 *
189 * @since 2.5.0
190 * @param array $atts Array of video attributes.
191 * @param string Combined attributes string.
192 */
193 function ayg_combine_video_attributes( $atts ) {
194 $attributes = array();
195
196 foreach ( $atts as $key => $value ) {
197 if ( '' === $value ) {
198 $attributes[] = $key;
199 } else {
200 $attributes[] = sprintf( '%s="%s"', $key, $value );
201 }
202 }
203
204 return implode( ' ', $attributes );
205 }
206
207 /**
208 * Create custom database tables
209 *
210 * @since 2.1.0
211 */
212 function ayg_db_create_custom_tables() {
213 global $wpdb;
214
215 require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
216 $charset_collate = $wpdb->get_charset_collate();
217
218 $videos_table = $wpdb->prefix . 'ayg_videos';
219
220 // Check if the videos table exists
221 $query = $wpdb->prepare( 'SHOW TABLES LIKE %s', $wpdb->esc_like( $videos_table ) );
222
223 if ( $wpdb->get_var( $query ) === $videos_table ) {
224 // Find and remove duplicate video IDs
225 $wpdb->query(
226 "DELETE v1 FROM $videos_table v1
227 INNER JOIN $videos_table v2
228 ON v1.id = v2.id AND v1.NUM > v2.NUM"
229 );
230 }
231
232 // Create the videos table
233 $sql = "CREATE TABLE $videos_table (
234 NUM bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
235 id varchar(100) NOT NULL,
236 title text NOT NULL,
237 description text NOT NULL,
238 thumbnails text NOT NULL,
239 duration varchar(25) NOT NULL,
240 status varchar(100) NOT NULL,
241 published_at varchar(100) NOT NULL,
242 published_at_datetime datetime NULL,
243 PRIMARY KEY (NUM),
244 UNIQUE KEY ayg_unique_video_id (id),
245 INDEX ayg_idx_published_at_datetime (published_at_datetime)
246 ) $charset_collate;";
247
248 dbDelta( $sql );
249
250 // Add UNIQUE KEY if it is not added
251 $existing_keys = $wpdb->get_results( "SHOW KEYS FROM $videos_table WHERE Key_name = 'ayg_unique_video_id'" );
252
253 if ( empty( $existing_keys ) ) {
254 $wpdb->query( "ALTER TABLE $videos_table ADD UNIQUE KEY ayg_unique_video_id (id)" );
255 }
256
257 // Add INDEX on published_at_datetime if it is not added (existing installs)
258 $existing_dt_index = $wpdb->get_results( "SHOW KEYS FROM $videos_table WHERE Key_name = 'ayg_idx_published_at_datetime'" );
259
260 if ( empty( $existing_dt_index ) ) {
261 $wpdb->query( "ALTER TABLE $videos_table ADD INDEX ayg_idx_published_at_datetime (published_at_datetime)" );
262 }
263
264 // Create the galleries table
265 $galleries_table = $wpdb->prefix . 'ayg_galleries';
266
267 $sql = "CREATE TABLE $galleries_table (
268 NUM bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
269 video_id varchar(100) NOT NULL,
270 gallery_id varchar(100) NOT NULL,
271 PRIMARY KEY (NUM),
272 UNIQUE KEY ayg_unique_video_gallery (video_id, gallery_id),
273 INDEX ayg_idx_gallery_id (gallery_id)
274 ) $charset_collate;";
275
276 dbDelta( $sql );
277 }
278
279 /**
280 * Store videos in our custom database table "{$wpdb->prefix}ayg_videos"
281 *
282 * @since 2.1.0
283 * @param object $data YouTube API response object.
284 * @param array $attributes Array of user attributes.
285 */
286 function ayg_db_store_videos( $data, $attributes = array() ) {
287 if ( AYG_VERSION !== get_option( 'ayg_version' ) ) {
288 return false;
289 }
290
291 if ( isset( $data->kind ) && 'youtube#channelListResponse' == $data->kind ) {
292 return false;
293 }
294
295 if ( empty( $data->items ) || ! is_array( $data->items ) ) {
296 return false;
297 }
298
299 global $wpdb;
300
301 $items = $data->items;
302 $gallery_id = isset( $attributes['uid'] ) ? $attributes['uid'] : '';
303 $source_type = isset( $attributes['type'] ) ? $attributes['type'] : 'videos';
304 $store_gallery = ! empty( $gallery_id ) && ! in_array( $source_type, array( 'video', 'livestream' ) );
305
306 $videos_table = $wpdb->prefix . 'ayg_videos';
307 $galleries_table = $wpdb->prefix . 'ayg_galleries';
308
309 $video_placeholders = array();
310 $video_values = array();
311 $gallery_placeholders = array();
312 $gallery_values = array();
313
314 foreach ( $items as $item ) {
315 $row = array();
316
317 // Video ID
318 $row['id'] = '';
319
320 if ( isset( $item->snippet->resourceId ) && isset( $item->snippet->resourceId->videoId ) ) {
321 $row['id'] = $item->snippet->resourceId->videoId;
322 } elseif ( isset( $item->contentDetails ) && isset( $item->contentDetails->videoId ) ) {
323 $row['id'] = $item->contentDetails->videoId;
324 } elseif ( isset( $item->id ) && isset( $item->id->videoId ) ) {
325 $row['id'] = $item->id->videoId;
326 } elseif ( isset( $item->id ) ) {
327 $row['id'] = $item->id;
328 }
329
330 if ( empty( $row['id'] ) ) {
331 continue;
332 }
333
334 // Video title
335 $row['title'] = $item->snippet->title;
336
337 // Video description
338 $row['description'] = $item->snippet->description;
339
340 // Video thumbnails
341 $row['thumbnails'] = '';
342 if ( isset( $item->snippet->thumbnails ) ) {
343 $row['thumbnails'] = serialize( $item->snippet->thumbnails );
344 }
345
346 // Video duration
347 $row['duration'] = '';
348 if ( isset( $item->contentDetails ) && isset( $item->contentDetails->duration ) ) {
349 $row['duration'] = $item->contentDetails->duration;
350 }
351
352 // Video status
353 $row['status'] = 'private';
354
355 if ( isset( $item->status ) && ( 'public' == $item->status->privacyStatus || 'unlisted' == $item->status->privacyStatus ) ) {
356 $row['status'] = 'public';
357 }
358
359 if ( isset( $item->snippet->status ) && ( 'public' == $item->snippet->status->privacyStatus || 'unlisted' == $item->snippet->status->privacyStatus ) ) {
360 $row['status'] = 'public';
361 }
362
363 if ( 'youtube#searchResult' == $item->kind ) {
364 $row['status'] = 'public';
365 }
366
367 // Video publish date
368 $row['published_at'] = $item->snippet->publishedAt;
369
370 $datetime = new DateTime( $item->snippet->publishedAt );
371 $row['published_at_datetime'] = date_format( $datetime, 'Y-m-d H:i:s' );
372
373 // Collect for bulk insert
374 $video_placeholders[] = '(%s, %s, %s, %s, %s, %s, %s, %s)';
375
376 array_push(
377 $video_values,
378 $row['id'],
379 $row['title'],
380 $row['description'],
381 $row['thumbnails'],
382 $row['duration'],
383 $row['status'],
384 $row['published_at'],
385 $row['published_at_datetime']
386 );
387
388 if ( $store_gallery ) {
389 $gallery_placeholders[] = '(%s, %s)';
390 array_push( $gallery_values, $row['id'], $gallery_id );
391 }
392 }
393
394 // Bulk insert videos (2 queries total instead of N×2)
395 if ( ! empty( $video_placeholders ) ) {
396 $sql = "INSERT INTO $videos_table (id, title, description, thumbnails, duration, status, published_at, published_at_datetime)
397 VALUES " . implode( ', ', $video_placeholders ) . "
398 ON DUPLICATE KEY UPDATE
399 title = VALUES(title),
400 description = VALUES(description),
401 thumbnails = VALUES(thumbnails),
402 duration = VALUES(duration),
403 status = VALUES(status),
404 published_at = VALUES(published_at),
405 published_at_datetime = VALUES(published_at_datetime)";
406
407 $wpdb->query( $wpdb->prepare( $sql, $video_values ) );
408 }
409
410 if ( ! empty( $gallery_placeholders ) ) {
411 $sql = "INSERT IGNORE INTO $galleries_table (video_id, gallery_id) VALUES " . implode( ', ', $gallery_placeholders );
412 $wpdb->query( $wpdb->prepare( $sql, $gallery_values ) );
413 }
414 }
415
416 /**
417 * Get a single video record from our custom database table "{$wpdb->prefix}ayg_videos"
418 *
419 * @since 2.1.0
420 * @param string $video_id YouTube Video ID.
421 * @return mixed
422 */
423 function ayg_db_get_video( $video_id ) {
424 global $wpdb;
425
426 $cache_key = 'ayg_'. $video_id;
427 $row = wp_cache_get( $cache_key );
428
429 if ( false === $row ) {
430 $query = $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}ayg_videos WHERE id = %s", $video_id );
431 $row = $wpdb->get_row( $query );
432
433 if ( $row ) {
434 if ( ! empty( $row->thumbnails ) ) {
435 $row->thumbnails = unserialize( $row->thumbnails );
436 }
437
438 wp_cache_set( $cache_key, $row );
439 }
440 }
441
442 return $row;
443 }
444
445 /**
446 * Dump our plugin transients.
447 *
448 * @since 2.1.0
449 */
450 function ayg_delete_cache() {
451 delete_option( 'ayg_gallery_page_ids' );
452
453 // Get the current list of transients
454 $transient_keys = ayg_get_option( 'ayg_transient_keys' );
455
456 // For each key, delete that transient
457 foreach ( $transient_keys as $key ) {
458 delete_transient( $key );
459 }
460
461 // Reset our DB value (autoload=no: not needed on every page load)
462 update_option( 'ayg_transient_keys', array(), false );
463 }
464
465 /**
466 * Get current address bar URL.
467 *
468 * @since 2.1.0
469 * @return string Current Page URL.
470 */
471 function ayg_get_current_url() {
472 global $wp;
473 $current_url = home_url( add_query_arg( array(), $wp->request ) );
474
475 return $current_url;
476 }
477
478 /**
479 * Get default plugin settings.
480 *
481 * @since 1.6.4
482 * @return array $defaults Array of plugin settings.
483 */
484 function ayg_get_default_settings() {
485 $defaults = array(
486 'ayg_general_settings' => array(
487 'force_load_assets' => array(
488 'css' => 'css'
489 ),
490 'api_key' => '',
491 'lazyload' => 0,
492 'development_mode' => 0
493 ),
494 'ayg_strings_settings' => array(
495 'more_button_label' => __( 'Load More', 'automatic-youtube-gallery' ),
496 'previous_button_label' => __( 'Previous', 'automatic-youtube-gallery' ),
497 'next_button_label' => __( 'Next', 'automatic-youtube-gallery' ),
498 'show_more_label' => __( 'Show More', 'automatic-youtube-gallery' ),
499 'show_less_label' => __( 'Show Less', 'automatic-youtube-gallery' )
500 ),
501 'ayg_gallery_settings' => array(
502 'theme' => 'classic',
503 'columns' => 3,
504 'per_page' => 12,
505 'thumb_ratio' => 56.25,
506 'thumb_title' => 1,
507 'thumb_title_length' => 0,
508 'thumb_excerpt' => 1,
509 'thumb_excerpt_length' => 75,
510 'pagination' => 1,
511 'pagination_type' => 'more',
512 'scroll_top_offset' => 10
513 ),
514 'ayg_player_settings' => array(
515 'player_type' => 'youtube',
516 'player_color' => '#00b3ff',
517 'player_width' => '',
518 'player_ratio' => 56.25,
519 'player_title' => 1,
520 'player_description' => 1,
521 'autoplay' => 0,
522 'autoadvance' => 1,
523 'loop' => 0,
524 'muted' => 0,
525 'controls' => 1,
526 'modestbranding' => 1,
527 'cc_load_policy' => 0,
528 'iv_load_policy' => 0,
529 'hl' => '',
530 'cc_lang_pref' => '',
531 'privacy_enhanced_mode' => 0,
532 'origin' => 0
533 ),
534 'ayg_livestream_settings' => array(
535 'fallback_message' => __( 'Sorry, but the channel is not currently streaming live content. Please check back later.', 'automatic-youtube-gallery' )
536 ),
537 'ayg_privacy_settings' => array(
538 'cookie_consent' => 0,
539 'consent_message' => __( 'Please accept YouTube cookies to play this video. By accepting you will be accessing content from YouTube, a service provided by an external third party.', 'automatic-youtube-gallery' ),
540 'button_label' => __( 'Accept', 'automatic-youtube-gallery' )
541 )
542 );
543
544 return $defaults;
545 }
546
547 /**
548 * Get editor fields.
549 *
550 * @since 1.0.0
551 * @return array Array of fields.
552 */
553 function ayg_get_editor_fields() {
554 $fields = array(
555 'source' => array(
556 'label' => __( 'General', 'automatic-youtube-gallery' ),
557 'fields' => array(
558 array(
559 'name' => 'type',
560 'label' => __( 'Source Type', 'automatic-youtube-gallery' ),
561 'description' => '',
562 'type' => 'select',
563 'options' => array(
564 'playlist' => __( 'Playlist', 'automatic-youtube-gallery' ),
565 'channel' => __( 'Channel', 'automatic-youtube-gallery' ),
566 'username' => __( 'Username', 'automatic-youtube-gallery' ),
567 'search' => __( 'Search Keywords', 'automatic-youtube-gallery' ),
568 'video' => __( 'Single Video', 'automatic-youtube-gallery' ),
569 'livestream' => __( 'Livestream', 'automatic-youtube-gallery' ),
570 'videos' => __( 'Custom Videos List', 'automatic-youtube-gallery' )
571 ),
572 'value' => 'playlist',
573 'sanitize_callback' => 'sanitize_key'
574 ),
575 array(
576 'name' => 'playlist',
577 'label' => __( 'YouTube Playlist ID (or) URL', 'automatic-youtube-gallery' ),
578 'description' => sprintf( '%s: https://www.youtube.com/playlist?list=XXXXXXXXXX', __( 'Example', 'automatic-youtube-gallery' ) ),
579 'type' => 'url',
580 'value' => '',
581 'sanitize_callback' => 'sanitize_text_field'
582 ),
583 array(
584 'name' => 'channel',
585 'label' => __( 'YouTube Channel ID (or) a YouTube Video URL from the Channel', 'automatic-youtube-gallery' ),
586 'description' => sprintf( '%s: https://www.youtube.com/channel/XXXXXXXXXX', __( 'Example', 'automatic-youtube-gallery' ) ),
587 'type' => 'url',
588 'value' => '',
589 'sanitize_callback' => 'sanitize_text_field'
590 ),
591 array(
592 'name' => 'username',
593 'label' => __( 'YouTube Account Username', 'automatic-youtube-gallery' ),
594 'description' => sprintf( '%s: SanRosh', __( 'Example', 'automatic-youtube-gallery' ) ),
595 'type' => 'text',
596 'value' => '',
597 'sanitize_callback' => 'sanitize_text_field'
598 ),
599 array(
600 'name' => 'search',
601 'label' => __( 'Search Keywords', 'automatic-youtube-gallery' ),
602 'description' => sprintf( '%s: Cartoon (space:AND , -:NOT , |:OR)', __( 'Example', 'automatic-youtube-gallery' ) ),
603 'type' => 'text',
604 'value' => '',
605 'sanitize_callback' => 'sanitize_text_field'
606 ),
607 array(
608 'name' => 'video',
609 'label' => __( 'YouTube Video ID (or) URL', 'automatic-youtube-gallery' ),
610 'description' => sprintf( '%s: https://www.youtube.com/watch?v=XXXXXXXXXX', __( 'Example', 'automatic-youtube-gallery' ) ),
611 'type' => 'url',
612 'value' => '',
613 'sanitize_callback' => 'sanitize_text_field'
614 ),
615 array(
616 'name' => 'videos',
617 'label' => __( 'YouTube Video IDs (or) URLs', 'automatic-youtube-gallery' ),
618 'description' => sprintf( '%s: https://www.youtube.com/watch?v=XXXXXXXXXX', __( 'Example', 'automatic-youtube-gallery' ) ),
619 'type' => 'textarea',
620 'placeholder' => __( 'Enter one video per line', 'automatic-youtube-gallery' ),
621 'value' => '',
622 'sanitize_callback' => 'sanitize_text_field'
623 ),
624 array(
625 'name' => 'order',
626 'label' => __( 'Order Videos by', 'automatic-youtube-gallery' ),
627 'description' => '',
628 'type' => 'select',
629 'options' => array(
630 'date' => __( 'Date', 'automatic-youtube-gallery' ),
631 'rating' => __( 'Rating', 'automatic-youtube-gallery' ),
632 'relevance' => __( 'Relevance', 'automatic-youtube-gallery' ),
633 'title' => __( 'Title', 'automatic-youtube-gallery' ),
634 'viewCount' => __( 'View Count', 'automatic-youtube-gallery' )
635 ),
636 'value' => 'relevance',
637 'sanitize_callback' => 'sanitize_key'
638 ),
639 array(
640 'name' => 'limit',
641 'label' => __( 'Number of Videos', 'automatic-youtube-gallery' ),
642 'description' => __( 'Specifies the maximum number of videos that will appear in this gallery. Set to 0 for the maximum amount (500).', 'automatic-youtube-gallery' ),
643 'type' => 'number',
644 'min' => 0,
645 'max' => 500,
646 'value' => 0,
647 'sanitize_callback' => 'intval'
648 ),
649 array(
650 'name' => 'cache',
651 'label' => __( 'Cache Duration', 'automatic-youtube-gallery' ),
652 'description' => __( 'Specifies how frequently we should check your YouTube source for new videos/updates.', 'automatic-youtube-gallery' ),
653 'type' => 'select',
654 'options' => array(
655 '0' => ''. __( 'No Caching', 'automatic-youtube-gallery' ) . '',
656 '900' => __( '15 Minutes', 'automatic-youtube-gallery' ),
657 '1800' => __( '30 Minutes', 'automatic-youtube-gallery' ),
658 '3600' => __( '1 Hour', 'automatic-youtube-gallery' ),
659 '86400' => __( '1 Day', 'automatic-youtube-gallery' ),
660 '604800' => __( '1 Week', 'automatic-youtube-gallery' ),
661 '2419200' => __( '1 Month', 'automatic-youtube-gallery' )
662 ),
663 'value' => 86400,
664 'sanitize_callback' => 'intval'
665 )
666 )
667 ),
668 'gallery' => array(
669 'label' => __( 'Gallery (optional)', 'automatic-youtube-gallery' ),
670 'fields' => ayg_get_gallery_settings_fields()
671 ),
672 'player' => array(
673 'label' => __( 'Player (optional)', 'automatic-youtube-gallery' ),
674 'fields' => ayg_get_player_settings_fields()
675 ),
676 'search' => array(
677 'label' => __( 'Search Form (optional)', 'automatic-youtube-gallery' ),
678 'fields' => array(
679 array(
680 'name' => 'search_form',
681 'label' => __( 'Search Form', 'automatic-youtube-gallery' ),
682 'description' => sprintf(
683 __( 'Check this option to enable the search form. Having issues? <a href="%s" target="_blank" rel="noopener noreferrer">Check here</a>.', 'automatic-youtube-gallery' ),
684 'https://plugins360.com/automatic-youtube-gallery/searchform/'
685 ),
686 'type' => 'checkbox',
687 'value' => 0,
688 'sanitize_callback' => 'intval'
689 )
690 )
691 )
692 );
693
694 return apply_filters( 'ayg_editor_fields', $fields );
695 }
696
697 /**
698 * Get gallery settings fields.
699 *
700 * @since 1.0.0
701 * @return array $fields Array of fields.
702 */
703 function ayg_get_gallery_settings_fields() {
704 $gallery_settings = ayg_get_option( 'ayg_gallery_settings' );
705
706 $fields = array(
707 array(
708 'name' => 'theme',
709 'label' => __( 'Select Theme (Layout)', 'automatic-youtube-gallery' ),
710 'description' => ( ayg_fs()->is_not_paying() ? sprintf( __( '<a href="%s">Upgrade Pro</a> for more themes (Popup, Inline, Slider, Playlist).', 'automatic-youtube-gallery' ), esc_url( ayg_fs()->get_upgrade_url() ) ) : '' ),
711 'type' => 'select',
712 'options' => array(
713 'classic' => __( 'Classic', 'automatic-youtube-gallery' )
714 ),
715 'value' => $gallery_settings['theme'],
716 'sanitize_callback' => 'sanitize_key'
717 ),
718 array(
719 'name' => 'columns',
720 'label' => __( 'Columns', 'automatic-youtube-gallery' ),
721 'description' => __( 'Enter the number of columns you like to have in the gallery. Maximum of 12.', 'automatic-youtube-gallery' ),
722 'type' => 'number',
723 'min' => 0,
724 'max' => 12,
725 'value' => $gallery_settings['columns'],
726 'sanitize_callback' => 'intval'
727 ),
728 array(
729 'name' => 'per_page',
730 'label' => __( 'Videos per Page', 'automatic-youtube-gallery' ),
731 'description' => __( 'Enter the number of videos to show per page. Maximum of 50.', 'automatic-youtube-gallery' ),
732 'type' => 'number',
733 'min' => 0,
734 'max' => 50,
735 'value' => $gallery_settings['per_page'],
736 'sanitize_callback' => 'intval'
737 ),
738 array(
739 'name' => 'thumb_ratio',
740 'label' => __( 'Image Height (Ratio)', 'automatic-youtube-gallery' ),
741 'description' => __( 'Select the ratio value used to calculate the image height in the gallery thumbnails.', 'automatic-youtube-gallery' ),
742 'type' => 'select',
743 'options' => array(
744 '56.25' => __( 'Standard (16:9) — Default', 'automatic-youtube-gallery' ),
745 '177.78' => __( 'Shorts / Vertical (9:16)', 'automatic-youtube-gallery' ),
746 '75' => __( 'Classic (4:3)', 'automatic-youtube-gallery' )
747 ),
748 'value' => $gallery_settings['thumb_ratio'],
749 'sanitize_callback' => 'floatval'
750 ),
751 array(
752 'name' => 'thumb_title',
753 'label' => __( 'Show Video Title', 'automatic-youtube-gallery' ),
754 'description' => __( 'Check this option to show the video title in each gallery item.', 'automatic-youtube-gallery' ),
755 'type' => 'checkbox',
756 'value' => $gallery_settings['thumb_title'],
757 'sanitize_callback' => 'intval'
758 ),
759 array(
760 'name' => 'thumb_title_length',
761 'label' => __( 'Video Title Length', 'automatic-youtube-gallery' ),
762 'description' => __( 'Enter the number of characters you like to show in the title. Set 0 to show the whole title.', 'automatic-youtube-gallery' ),
763 'type' => 'number',
764 'min' => 0,
765 'max' => 500,
766 'value' => $gallery_settings['thumb_title_length'],
767 'sanitize_callback' => 'intval'
768 ),
769 array(
770 'name' => 'thumb_excerpt',
771 'label' => __( 'Show Video Excerpt (Short Description)', 'automatic-youtube-gallery' ),
772 'description' => __( 'Check this option to show the short description of a video in each gallery item.', 'automatic-youtube-gallery' ),
773 'type' => 'checkbox',
774 'value' => $gallery_settings['thumb_excerpt'],
775 'sanitize_callback' => 'intval'
776 ),
777 array(
778 'name' => 'thumb_excerpt_length',
779 'label' => __( 'Video Excerpt Length', 'automatic-youtube-gallery' ),
780 'description' => __( 'Enter the number of characters you like to have in the video excerpt. Set 0 to show the whole description.', 'automatic-youtube-gallery' ),
781 'type' => 'number',
782 'min' => 0,
783 'max' => 500,
784 'value' => $gallery_settings['thumb_excerpt_length'],
785 'sanitize_callback' => 'intval'
786 ),
787 array(
788 'name' => 'pagination',
789 'label' => __( 'Pagination', 'automatic-youtube-gallery' ),
790 'description' => __( 'Check this option to show the pagination.', 'automatic-youtube-gallery' ),
791 'type' => 'checkbox',
792 'value' => $gallery_settings['pagination'],
793 'sanitize_callback' => 'intval'
794 ),
795 array(
796 'name' => 'pagination_type',
797 'label' => __( 'Pagination Type', 'automatic-youtube-gallery' ),
798 'type' => 'select',
799 'options' => array(
800 'more' => __( 'More Button', 'automatic-youtube-gallery' ),
801 'pager' => __( 'Pager', 'automatic-youtube-gallery' )
802
803 ),
804 'value' => $gallery_settings['pagination_type'],
805 'sanitize_callback' => 'sanitize_key'
806 )
807 );
808
809 return apply_filters( 'ayg_gallery_settings_fields', $fields );
810 }
811
812 /**
813 * Retrieve a plugin option with fallback to default settings.
814 *
815 * @since 2.7.0
816 * @param string $option The option name to retrieve.
817 * @return mixed
818 */
819 function ayg_get_option( $option ) {
820 $defaults = ayg_get_default_settings();
821 $default = isset( $defaults[ $option ] ) ? $defaults[ $option ] : array();
822
823 $saved = get_option( $option, null );
824
825 // Option does not exist OR corrupted
826 if ( null === $saved || ! is_array( $saved ) ) {
827 return $default;
828 }
829
830 // Merge saved values with defaults
831 return wp_parse_args( $saved, $default );
832 }
833
834 /**
835 * Get video description to show on top of the player.
836 *
837 * @since 1.0.0
838 * @param stdClass $video YouTube video object.
839 * @param array $attributes Array of user attributes.
840 * @param int $words_count Number of words to show by default.
841 * @return string Video description.
842 */
843 function ayg_get_player_description( $video, $attributes = array(), $words_count = 30 ) {
844 $description = $video->description;
845
846 $words_array = explode( ' ', strip_tags( $description ) );
847 if ( count( $words_array ) > $words_count ) {
848 $show_more_label = ! empty( $attributes['show_more_label'] ) ? $attributes['show_more_label'] : __( 'Show More', 'automatic-youtube-gallery' );
849 $words_array[ $words_count ] = '<span class="ayg-player-description-dots">...</span></span><span class="ayg-player-description-more">' . $words_array[ $words_count ];
850
851 $description = '<span class="ayg-player-description-less">' . implode( ' ', $words_array ) . '</span>';
852 $description .= '<a href="#" class="ayg-player-description-toggle-btn">' . esc_html( $show_more_label ) . '</a>';
853 }
854
855 $description = nl2br( $description );
856 $description = make_clickable( $description );
857
858 return apply_filters( 'ayg_player_description', $description, $video, $attributes, $words_count );
859 }
860
861 /**
862 * Get player settings fields.
863 *
864 * @since 1.0.0
865 * @return array $fields Array of fields.
866 */
867 function ayg_get_player_settings_fields() {
868 $player_settings = ayg_get_option( 'ayg_player_settings' );
869
870 $fields = array(
871 array(
872 'name' => 'player_width',
873 'label' => __( 'Player Width', 'automatic-youtube-gallery' ),
874 'description' => __( 'In pixels. Maximum width of the player. Leave this field empty to scale 100% of its enclosing container/html element.', 'automatic-youtube-gallery' ),
875 'type' => 'text',
876 'value' => isset( $player_settings['player_width'] ) ? $player_settings['player_width'] : '',
877 'sanitize_callback' => 'ayg_sanitize_int'
878 ),
879 array(
880 'name' => 'player_ratio',
881 'label' => __( 'Player Height (Ratio)', 'automatic-youtube-gallery' ),
882 'description' => __( 'Select the ratio value used to calculate the player height.', 'automatic-youtube-gallery' ),
883 'type' => 'select',
884 'options' => array(
885 '56.25' => __( 'Standard (16:9) — Default', 'automatic-youtube-gallery' ),
886 '177.78' => __( 'Shorts / Vertical (9:16)', 'automatic-youtube-gallery' ),
887 '75' => __( 'Classic (4:3)', 'automatic-youtube-gallery' )
888 ),
889 'value' => $player_settings['player_ratio'],
890 'sanitize_callback' => 'floatval'
891 ),
892 array(
893 'name' => 'player_title',
894 'label' => __( 'Show Video Title', 'automatic-youtube-gallery' ),
895 'description' => __( 'Check this option to show the current playing video title on the bottom of the player.', 'automatic-youtube-gallery' ),
896 'type' => 'checkbox',
897 'value' => $player_settings['player_title'],
898 'sanitize_callback' => 'intval'
899 ),
900 array(
901 'name' => 'player_description',
902 'label' => __( 'Show Video Description', 'automatic-youtube-gallery' ),
903 'description' => __( 'Check this option to show the current playing video description on the bottom of the player.', 'automatic-youtube-gallery' ),
904 'type' => 'checkbox',
905 'value' => $player_settings['player_description'],
906 'sanitize_callback' => 'intval'
907 ),
908 array(
909 'name' => 'autoplay',
910 'label' => __( 'Autoplay', 'automatic-youtube-gallery' ),
911 'description' => __( 'Specifies whether the initial video will automatically start to play when the player loads.', 'automatic-youtube-gallery' ),
912 'type' => 'checkbox',
913 'value' => $player_settings['autoplay'],
914 'sanitize_callback' => 'intval'
915 ),
916 array(
917 'name' => 'autoadvance',
918 'label' => __( 'Autoplay Next Video', 'automatic-youtube-gallery' ),
919 'description' => __( 'Specifies whether to play the next video in the list automatically after previous one end.', 'automatic-youtube-gallery' ),
920 'type' => 'checkbox',
921 'value' => $player_settings['autoadvance'],
922 'sanitize_callback' => 'intval'
923 ),
924 array(
925 'name' => 'loop',
926 'label' => __( 'Loop', 'automatic-youtube-gallery' ),
927 'description' => __( 'In the case of a single video player, plays the initial video again and again. In the case of a gallery, plays the entire list in the gallery and then starts again at the first video.', 'automatic-youtube-gallery' ),
928 'type' => 'checkbox',
929 'value' => $player_settings['loop'],
930 'sanitize_callback' => 'intval'
931 ),
932 array(
933 'name' => 'muted',
934 'label' => __( 'Muted', 'automatic-youtube-gallery' ),
935 'description' => __( 'Check this option to turn OFF the audio output of the video by default.', 'automatic-youtube-gallery' ),
936 'type' => 'checkbox',
937 'value' => isset( $player_settings['muted'] ) ? $player_settings['muted'] : 0,
938 'sanitize_callback' => 'intval'
939 ),
940 array(
941 'name' => 'controls',
942 'label' => __( 'Show Player Controls', 'automatic-youtube-gallery' ),
943 'description' => __( 'Uncheck this option to hide the video player controls.', 'automatic-youtube-gallery' ),
944 'type' => 'checkbox',
945 'value' => $player_settings['controls'],
946 'sanitize_callback' => 'intval'
947 ),
948 array(
949 'name' => 'modestbranding',
950 'label' => __( 'Hide YouTube Logo', 'automatic-youtube-gallery' ),
951 'description' => __( "Lets you prevent the YouTube logo from displaying in the control bar. Note that a small YouTube text label will still display in the upper-right corner of a paused video when the user's mouse pointer hovers over the player.", 'automatic-youtube-gallery' ),
952 'type' => 'checkbox',
953 'value' => $player_settings['modestbranding'],
954 'sanitize_callback' => 'intval'
955 ),
956 array(
957 'name' => 'cc_load_policy',
958 'label' => __( 'Force Closed Captions', 'automatic-youtube-gallery' ),
959 'description' => __( 'Show captions by default, even if the user has turned captions off. The default behavior is based on user preference.', 'automatic-youtube-gallery' ),
960 'type' => 'checkbox',
961 'value' => $player_settings['cc_load_policy'],
962 'sanitize_callback' => 'intval'
963 ),
964 array(
965 'name' => 'iv_load_policy',
966 'label' => __( 'Show Annotations', 'automatic-youtube-gallery' ),
967 'description' => __( 'Choose whether to show annotations or not.', 'automatic-youtube-gallery' ),
968 'type' => 'checkbox',
969 'value' => $player_settings['iv_load_policy'],
970 'sanitize_callback' => 'intval'
971 ),
972 array(
973 'name' => 'hl',
974 'label' => __( 'Player Language', 'automatic-youtube-gallery' ),
975 'description' => sprintf(
976 __( 'Specifies the player\'s interface language. Set the field\'s value to an <a href="%s" target="_blank">ISO 639-1 two-letter language code.</a>', 'automatic-youtube-gallery' ),
977 'http://www.loc.gov/standards/iso639-2/php/code_list.php'
978 ),
979 'type' => 'text',
980 'value' => $player_settings['hl'],
981 'sanitize_callback' => 'sanitize_text_field'
982 ),
983 array(
984 'name' => 'cc_lang_pref',
985 'label' => __( 'Default Captions Language', 'automatic-youtube-gallery' ),
986 'description' => sprintf(
987 __( 'Specifies the default language that the player will use to display captions. Set the field\'s value to an <a href="%s" target="_blank">ISO 639-1 two-letter language code.</a>', 'automatic-youtube-gallery' ),
988 'http://www.loc.gov/standards/iso639-2/php/code_list.php'
989 ),
990 'type' => 'text',
991 'value' => $player_settings['cc_lang_pref'],
992 'sanitize_callback' => 'sanitize_text_field'
993 )
994 );
995
996 return $fields;
997 }
998
999
1000 /**
1001 * Get a single video page URL.
1002 *
1003 * @since 2.1.0
1004 * @param stdClass $video YouTube video object.
1005 * @param array $args An array of gallery options.
1006 * @return string Single video URL.
1007 */
1008 function ayg_get_single_video_url( $video, $attributes ) {
1009 return apply_filters( 'ayg_single_video_url', '', $video, $attributes );
1010 }
1011
1012 /**
1013 * Get filtered php template file path.
1014 *
1015 * @since 1.0.0
1016 * @param array $template PHP file path.
1017 * @param string $theme Automatic YouTube Gallery Theme.
1018 * @return string Filtered file path.
1019 */
1020 function ayg_get_template( $template, $theme = '' ) {
1021 return apply_filters( 'ayg_load_template', $template, $theme );
1022 }
1023
1024 /**
1025 * Get unique ID.
1026 *
1027 * @since 1.0.0
1028 * @return string Unique ID.
1029 */
1030 function ayg_get_uniqid() {
1031 global $ayg_uniqid;
1032
1033 if ( ! $ayg_uniqid ) {
1034 $ayg_uniqid = 0;
1035 }
1036
1037 return uniqid() . ++$ayg_uniqid;
1038 }
1039
1040 /**
1041 * Get YouTube domain.
1042 *
1043 * @since 2.3.0
1044 * @return string YouTube embed domain.
1045 */
1046 function ayg_get_youtube_domain() {
1047 $player_settings = ayg_get_option( 'ayg_player_settings' );
1048
1049 $domain = 'https://www.youtube.com';
1050 if ( isset( $player_settings['privacy_enhanced_mode'] ) && ! empty( $player_settings['privacy_enhanced_mode'] ) ) {
1051 $domain = 'https://www.youtube-nocookie.com';
1052 }
1053
1054 return $domain;
1055 }
1056
1057 /**
1058 * Get the YouTube embed URL.
1059 *
1060 * @since 2.5.0
1061 * @param string $video_id YouTube video ID.
1062 * @param array $attributes Array of user attributes.
1063 * @return string Player embed URL.
1064 */
1065 function ayg_get_youtube_embed_url( $video_id, $attributes = array() ) {
1066 $player_settings = ayg_get_option( 'ayg_player_settings' );
1067
1068 $player_website = 'https://www.youtube.com';
1069 if ( isset( $player_settings['privacy_enhanced_mode'] ) && ! empty( $player_settings['privacy_enhanced_mode'] ) ) {
1070 $player_website = 'https://www.youtube-nocookie.com';
1071 }
1072
1073 if ( empty( $video_id ) ) {
1074 return '';
1075 }
1076
1077 $url = $player_website . '/embed/' . $video_id . '?enablejsapi=1&playsinline=1&rel=0';
1078
1079 if ( isset( $player_settings['origin'] ) && ! empty( $player_settings['origin'] ) ) {
1080 $site_url_parts = parse_url( site_url() );
1081 $origin = $site_url_parts['scheme'] . '://' . $site_url_parts['host'];
1082
1083 $url = add_query_arg( 'origin', $origin, $url );
1084 }
1085
1086 if ( ! is_array( $attributes ) ) {
1087 $attributes = (array) $attributes;
1088 }
1089
1090 $autoplay = isset( $attributes['autoplay'] ) ? (int) $attributes['autoplay'] : 0;
1091 if ( 1 == $autoplay ) {
1092 $url = add_query_arg( 'autoplay', 1, $url );
1093 }
1094
1095 $loop = isset( $attributes['loop'] ) ? (int) $attributes['loop'] : 0;
1096 if ( 1 == $loop ) {
1097 $url = add_query_arg( 'playlist', $video_id, $url );
1098 $url = add_query_arg( 'loop', 1, $url );
1099 }
1100
1101 $muted = isset( $attributes['muted'] ) ? (int) $attributes['muted'] : 0;
1102 if ( 1 == $muted ) {
1103 $url = add_query_arg( 'mute', 1, $url );
1104 }
1105
1106 $controls = isset( $attributes['controls'] ) ? (int) $attributes['controls'] : 1;
1107 if ( 0 == $controls ) {
1108 $url = add_query_arg( 'controls', 0, $url );
1109 }
1110
1111 $modestbranding = isset( $attributes['modestbranding'] ) ? (int) $attributes['modestbranding'] : 0;
1112 if ( 1 == $modestbranding ) {
1113 $url = add_query_arg( 'modestbranding', 1, $url );
1114 }
1115
1116 $cc_load_policy = isset( $attributes['cc_load_policy'] ) ? (int) $attributes['cc_load_policy'] : 0;
1117 if ( 1 == $cc_load_policy ) {
1118 $url = add_query_arg( 'cc_load_policy', 1, $url );
1119 }
1120
1121 $iv_load_policy = isset( $attributes['iv_load_policy'] ) ? (int) $attributes['iv_load_policy'] : 0;
1122 if ( 0 == $iv_load_policy ) {
1123 $url = add_query_arg( 'iv_load_policy', 3, $url );
1124 }
1125
1126 if ( isset( $attributes['hl'] ) && ! empty( $attributes['hl'] ) ) {
1127 $url = add_query_arg( 'hl', sanitize_text_field( $attributes['hl'] ), $url );
1128 }
1129
1130 if ( isset( $attributes['cc_lang_pref'] ) && ! empty( $attributes['cc_lang_pref'] ) ) {
1131 $url = add_query_arg( 'cc_lang_pref', sanitize_text_field( $attributes['cc_lang_pref'] ), $url );
1132 }
1133
1134 return apply_filters( 'ayg_youtube_embed_url', $url, $video_id, $attributes );
1135 }
1136
1137 /**
1138 * Inserts a new associative array after another associative array key.
1139 *
1140 * @since 2.1.0
1141 * @param string $key The associative array key to insert after.
1142 * @param array $array An array to insert in to.
1143 * @param array $new_array An array to insert.
1144 * @return array Updated array.
1145 */
1146 function ayg_insert_array_after( $key, $array, $new_array ) {
1147 if ( array_key_exists( $key, $array ) ) {
1148 $new = array();
1149
1150 foreach ( $array as $k => $value ) {
1151 $new[ $k ] = $value;
1152
1153 if ( $k === $key ) {
1154 foreach ( $new_array as $new_key => $new_value ) {
1155 $new[ $new_key ] = $new_value;
1156 }
1157 }
1158 }
1159
1160 return $new;
1161 }
1162
1163 return $array;
1164 }
1165
1166 /**
1167 * Detect if the client is using an iOS device (iPhone, iPad, or iPod).
1168 *
1169 * @return bool True if the user agent string suggests an iOS device, false otherwise.
1170 */
1171 function ayg_is_ios() {
1172 if ( empty( $_SERVER['HTTP_USER_AGENT'] ) ) {
1173 return false;
1174 }
1175
1176 $ua = strtolower( $_SERVER['HTTP_USER_AGENT'] );
1177
1178 if (
1179 strpos( $ua, 'iphone' ) !== false ||
1180 strpos( $ua, 'ipad' ) !== false ||
1181 strpos( $ua, 'ipod' ) !== false
1182 ) {
1183 return true;
1184 }
1185
1186 return false;
1187 }
1188
1189 /**
1190 * Sanitize the array inputs.
1191 *
1192 * @since 2.7.0
1193 * @param array $value Input array.
1194 * @return array Sanitized array.
1195 */
1196 function ayg_sanitize_array( $value ) {
1197 return ! empty( $value ) ? array_map( 'sanitize_text_field', $value ) : array();
1198 }
1199
1200 /**
1201 * Sanitize the integer inputs, accepts empty values.
1202 *
1203 * @since 1.0.0
1204 * @param string|int $value Input value.
1205 * @return string|int Sanitized value.
1206 */
1207 function ayg_sanitize_int( $value ) {
1208 $value = intval( $value );
1209 return ( 0 == $value ) ? '' : $value;
1210 }
1211
1212 /**
1213 * Trims text to a certain number of characters.
1214 *
1215 * @since 2.0.0
1216 * @param string $text Text to trim.
1217 * @param int $num_characters Number of characters.
1218 * @param string $append String to append to the end of the excerpt.
1219 * @return string Trimmed text.
1220 */
1221 function ayg_trim_words( $text, $num_characters, $append = '...' ) {
1222 $num_characters++;
1223
1224 $original_text = $text;
1225 $text = ( $num_characters > 1 ) ? wp_strip_all_tags( $original_text, true ) : nl2br( $original_text );
1226
1227 if ( $num_characters > 1 && mb_strlen( $text ) > $num_characters ) {
1228 $subex = mb_substr( $text, 0, $num_characters - 5 );
1229 $exwords = explode( ' ', $subex );
1230 $excut = - ( mb_strlen( $exwords[ count( $exwords ) - 1 ] ) );
1231
1232 if ( $excut < 0 ) {
1233 $text = mb_substr( $subex, 0, $excut );
1234 } else {
1235 $text = $subex;
1236 }
1237
1238 $text .= $append;
1239 }
1240
1241 return apply_filters( 'ayg_trim_words', $text, $original_text, $num_characters, $append );
1242 }
1243
1244 /**
1245 * Gallery HTML output.
1246 *
1247 * @since 1.0.0
1248 * @param array $video YouTube video object.
1249 * @param array $attributes Array of user attributes.
1250 */
1251 function the_ayg_gallery_thumbnail( $video, $attributes ) {
1252 include ayg_get_template( AYG_DIR . 'public/templates/thumbnail.php' );
1253 }
1254
1255 /**
1256 * Pagination HTML output.
1257 *
1258 * @since 1.0.0
1259 * @param array $attributes Array of user attributes.
1260 */
1261 function the_ayg_pagination( $attributes ) {
1262 if ( ! empty( $attributes['pagination'] ) ) {
1263 include ayg_get_template( AYG_DIR . 'public/templates/pagination.php' );
1264 }
1265 }
1266
1267 /**
1268 * Search Form HTML output.
1269 *
1270 * @since 2.5.7
1271 * @param array $attributes Array of user attributes.
1272 */
1273 function the_ayg_search_form( $attributes ) {
1274 if ( ! empty( $attributes['search_form'] ) ) {
1275 include ayg_get_template( AYG_DIR . 'public/templates/search-form.php' );
1276 }
1277 }
1278
1279 /**
1280 * Gallery HTML output.
1281 *
1282 * @since 2.5.0
1283 * @param array $video YouTube video object.
1284 * @param array $attributes Array of user attributes.
1285 */
1286 function the_ayg_player( $video, $attributes ) {
1287 include ayg_get_template( AYG_DIR . 'public/templates/player.php' );
1288 }