PluginProbe
Automatic YouTube Gallery – Embed Auto-Updating YouTube Video Galleries, Feeds, Playlists & Channels / 2.3.2
Automatic YouTube Gallery – Embed Auto-Updating YouTube Video Galleries, Feeds, Playlists & Channels v2.3.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
← All changes | includes/functions.php +391 -39 2.0.02.3.2 View file →
@@ -21,8 +21,10 @@
21 21 * @param array $args An array of gallery options.
22 22 * @return mixed
23 23 */
24 24 function ayg_build_gallery( $args ) {
25 + global $post;
26 +
25 27 // Vars
26 28 $fields = ayg_get_editor_fields();
27 29 $defaults = array();
28 30
@@ -33,9 +35,12 @@
33 35 }
34 36
35 37 $attributes = shortcode_atts( $defaults, $args );
36 38
37 - $attributes['uid'] = ayg_get_uniqid();
39 + $attributes['post_id'] = 0;
40 + if ( isset( $post->ID ) ) {
41 + $attributes['post_id'] = (int) $post->ID;
42 + }
38 43
39 44 $attributes['columns'] = min( 12, (int) $attributes['columns'] );
40 45 if ( empty( $attributes['columns'] ) ) {
41 46 $attributes['columns'] = 3;
@@ -55,8 +60,14 @@
55 60 if ( 'livestream' == $source_type ) {
56 61 $attributes['livestream'] = $attributes['channel'];
57 62 }
58 63
64 + if ( isset( $args['uid'] ) && ! empty( $args['uid'] ) ) {
65 + $attributes['uid'] = $args['uid'];
66 + } else {
67 + $attributes['uid'] = md5( $source_type . sanitize_text_field( $attributes[ $source_type ] ) . sanitize_text_field( $attributes['theme'] ) );
68 + }
69 +
59 70 // Get Videos
60 71 $api_params = array(
61 72 'type' => $source_type,
62 73 'src' => sanitize_text_field( $attributes[ $source_type ] ),
@@ -71,17 +82,49 @@
71 82 $response = $youtube_api->query( $api_params );
72 83
73 84 // Process output
74 85 if ( ! isset( $response->error ) ) {
86 + // Store Gallery ID
87 + if ( $attributes['post_id'] > 0 && isset( $attributes['deeplinking'] ) && 1 == $attributes['deeplinking'] ) {
88 + $pages = get_option( 'ayg_gallery_page_ids', array() );
89 + $page_id = $attributes['post_id'];
90 +
91 + if ( ! in_array( $page_id, $pages ) ) {
92 + $pages[] = $page_id;
93 + update_option( 'ayg_gallery_page_ids', $pages );
94 + }
95 + }
96 +
75 97 // Enqueue dependencies
76 98 wp_enqueue_style( AYG_SLUG . '-public' );
77 99 wp_enqueue_script( AYG_SLUG . '-public' );
78 100
79 101 // Gallery
80 - $videos = array();
102 + $videos = array();
103 +
104 + $gallery_id_from_url = get_query_var( 'ayg_gallery_id' );
105 + $video_id_from_url = get_query_var( 'ayg_video_id' );
106 +
107 + if ( $attributes['uid'] == $gallery_id_from_url ) {
108 + $video = ayg_db_get_video( $video_id_from_url );
109 +
110 + if ( $video ) {
111 + $videos[] = $video;
112 + } else {
113 + $video_id_from_url = '';
114 + }
115 + }
81 116
82 117 if ( isset( $response->videos ) ) {
83 - $videos = $response->videos;
118 + if ( ! empty( $video_id_from_url ) ) {
119 + foreach ( $response->videos as $video ) {
120 + if ( $video->id != $video_id_from_url ) {
121 + $videos[] = $video;
122 + }
123 + }
124 + } else {
125 + $videos = $response->videos;
126 + }
84 127 }
85 128
86 129 // Pagination
87 130 if ( isset( $response->page_info ) ) {
@@ -110,8 +153,203 @@
110 153 }
111 154 }
112 155
113 156 /**
157 + * Create a custom database table "{$wpdb->prefix}ayg_videos"
158 + *
159 + * @since 2.1.0
160 + */
161 +function ayg_db_create_videos_table() {
162 + global $wpdb;
163 +
164 + $charset_collate = $wpdb->get_charset_collate();
165 +
166 + $sql = "CREATE TABLE `{$wpdb->prefix}ayg_videos` (
167 + NUM bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
168 + id varchar(100) NOT NULL,
169 + title text NOT NULL,
170 + description text NOT NULL,
171 + thumbnails text NOT NULL,
172 + duration varchar(25) NOT NULL,
173 + status varchar(100) NOT NULL,
174 + published_at varchar(100) NOT NULL,
175 + PRIMARY KEY (NUM)
176 + ) $charset_collate;";
177 +
178 + require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
179 + dbDelta( $sql );
180 +}
181 +
182 +/**
183 + * Store videos in our custom database table "{$wpdb->prefix}ayg_videos"
184 + *
185 + * @since 2.1.0
186 + * @param object $data YouTube API response object.
187 + */
188 +function ayg_db_store_videos( $data ) {
189 + if ( AYG_VERSION !== get_option( 'ayg_version' ) ) {
190 + return false;
191 + }
192 +
193 + global $wpdb, $post;
194 +
195 + $table_name = $wpdb->prefix . 'ayg_videos';
196 +
197 + if ( isset( $data->kind ) && 'youtube#channelListResponse' == $data->kind ) {
198 + return false;
199 + }
200 +
201 + if ( ! isset( $data->items ) ) {
202 + return false;
203 + }
204 +
205 + $items = $data->items;
206 + if ( ! is_array( $items ) || 0 == count( $items ) ) {
207 + return false;
208 + }
209 +
210 + // Store Videos
211 + foreach ( $items as $item ) {
212 + $row = array();
213 +
214 + // Video ID
215 + $row['id'] = '';
216 +
217 + if ( isset( $item->snippet->resourceId ) && isset( $item->snippet->resourceId->videoId ) ) {
218 + $row['id'] = $item->snippet->resourceId->videoId;
219 + } elseif ( isset( $item->contentDetails ) && isset( $item->contentDetails->videoId ) ) {
220 + $row['id'] = $item->contentDetails->videoId;
221 + } elseif ( isset( $item->id ) && isset( $item->id->videoId ) ) {
222 + $row['id'] = $item->id->videoId;
223 + } elseif ( isset( $item->id ) ) {
224 + $row['id'] = $item->id;
225 + }
226 +
227 + if ( empty( $row['id'] ) ) {
228 + continue;
229 + }
230 +
231 + // Video title
232 + $row['title'] = $item->snippet->title;
233 +
234 + // Video description
235 + $row['description'] = $item->snippet->description;
236 +
237 + // Video thumbnails
238 + $row['thumbnails'] = '';
239 + if ( isset( $item->snippet->thumbnails ) ) {
240 + $row['thumbnails'] = serialize( $item->snippet->thumbnails );
241 + }
242 +
243 + // Video duration
244 + $row['duration'] = '';
245 + if ( isset( $item->contentDetails ) && isset( $item->contentDetails->duration ) ) {
246 + $row['duration'] = $item->contentDetails->duration;
247 + }
248 +
249 + // Video status
250 + $row['status'] = 'private';
251 +
252 + if ( isset( $item->status ) && ( 'public' == $item->status->privacyStatus || 'unlisted' == $item->status->privacyStatus ) ) {
253 + $row['status'] = 'public';
254 + }
255 +
256 + if ( isset( $item->snippet->status ) && ( 'public' == $item->snippet->status->privacyStatus || 'unlisted' == $item->snippet->status->privacyStatus ) ) {
257 + $row['status'] = 'public';
258 + }
259 +
260 + if ( 'youtube#searchResult' == $item->kind ) {
261 + $row['status'] = 'public';
262 + }
263 +
264 + // Video publish date
265 + $row['published_at'] = $item->snippet->publishedAt;
266 +
267 + // Store
268 + $query = $wpdb->prepare( "SELECT NUM FROM $table_name WHERE id = %s", $row['id'] );
269 + $insert_id = $wpdb->get_var( $query );
270 +
271 + if ( empty( $insert_id ) ) {
272 + $wpdb->insert(
273 + $table_name,
274 + $row,
275 + array( '%s', '%s', '%s', '%s', '%s', '%s', '%s' )
276 + );
277 + } else {
278 + $wpdb->update(
279 + $table_name,
280 + $row,
281 + array( 'NUM' => $insert_id ),
282 + array( '%s', '%s', '%s', '%s', '%s', '%s', '%s' ),
283 + array( '%d' )
284 + );
285 + }
286 + }
287 +}
288 +
289 +/**
290 + * Get a single video record from our custom database table "{$wpdb->prefix}ayg_videos"
291 + *
292 + * @since 2.1.0
293 + * @param string $video_id YouTube Video ID.
294 + * @return mixed
295 + */
296 +function ayg_db_get_video( $video_id ) {
297 + global $wpdb;
298 +
299 + $cache_key = 'ayg_'. $video_id;
300 + $row = wp_cache_get( $cache_key );
301 +
302 + if ( false === $row ) {
303 + $query = $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}ayg_videos WHERE id = %s", $video_id );
304 + $row = $wpdb->get_row( $query );
305 +
306 + if ( $row ) {
307 + if ( ! empty( $row->thumbnails ) ) {
308 + $row->thumbnails = unserialize( $row->thumbnails );
309 + }
310 +
311 + wp_cache_set( $cache_key, $row );
312 + }
313 + }
314 +
315 + return $row;
316 +}
317 +
318 +/**
319 + * Dump our plugin transients.
320 + *
321 + * @since 2.1.0
322 + */
323 +function ayg_delete_cache() {
324 + delete_option( 'ayg_gallery_page_ids' );
325 +
326 + // Get the current list of transients
327 + $transient_keys = get_option( 'ayg_transient_keys', array() );
328 +
329 + // For each key, delete that transient
330 + foreach ( $transient_keys as $key ) {
331 + delete_transient( $key );
332 + }
333 +
334 + // Reset our DB value
335 + update_option( 'ayg_transient_keys', array() );
336 +}
337 +
338 +/**
339 + * Get current address bar URL.
340 + *
341 + * @since 2.1.0
342 + * @return string Current Page URL.
343 + */
344 +function ayg_get_current_url() {
345 + global $wp;
346 + $current_url = home_url( add_query_arg( array(), $wp->request ) );
347 +
348 + return $current_url;
349 +}
350 +
351 +/**
114 352 * Get default plugin settings.
115 353 *
116 354 * @since 1.6.4
117 355 * @return array $defaults Array of plugin settings.
@@ -122,40 +360,46 @@
122 360 'api_key' => '',
123 361 'development_mode' => 1
124 362 ),
125 363 'ayg_gallery_settings' => array(
126 - 'theme' => 'classic',
127 - 'columns' => 3,
128 - 'per_page' => 12,
129 - 'thumb_ratio' => 56.25,
130 - 'thumb_title' => 1,
131 - 'thumb_title_length' => 0,
132 - 'thumb_excerpt' => 1,
133 - 'thumb_excerpt_length' => 75,
134 - 'pagination' => 1,
135 - 'pagination_type' => 'more'
364 + 'theme' => 'classic',
365 + 'columns' => 3,
366 + 'per_page' => 12,
367 + 'thumb_ratio' => 56.25,
368 + 'thumb_title' => 1,
369 + 'thumb_title_length' => 0,
370 + 'thumb_excerpt' => 1,
371 + 'thumb_excerpt_length' => 75,
372 + 'pagination' => 1,
373 + 'pagination_type' => 'more',
374 + 'more_button_label' => __( 'Load More', 'automatic-youtube-gallery' ),
375 + 'previous_button_label' => __( 'Previous', 'automatic-youtube-gallery' ),
376 + 'next_button_label' => __( 'Next', 'automatic-youtube-gallery' )
136 377 ),
137 378 'ayg_player_settings' => array(
138 - 'player_ratio' => 56.25,
139 - 'player_title' => 1,
140 - 'player_description' => 1,
141 - 'autoplay' => 0,
142 - 'autoadvance' => 1,
143 - 'loop' => 0,
144 - 'controls' => 1,
145 - 'modestbranding' => 1,
146 - 'cc_load_policy' => 0,
147 - 'iv_load_policy' => 0,
148 - 'hl' => '',
149 - 'cc_lang_pref' => ''
379 + 'player_ratio' => 56.25,
380 + 'player_title' => 1,
381 + 'player_description' => 1,
382 + 'autoplay' => 0,
383 + 'autoadvance' => 1,
384 + 'loop' => 0,
385 + 'muted' => 0,
386 + 'controls' => 1,
387 + 'modestbranding' => 1,
388 + 'cc_load_policy' => 0,
389 + 'iv_load_policy' => 0,
390 + 'hl' => '',
391 + 'cc_lang_pref' => '',
392 + 'privacy_enhanced_mode' => 0,
393 + 'origin' => 0
150 394 ),
151 395 'ayg_livestream_settings' => array(
152 396 'fallback_message' => __( 'Sorry, but the channel is not currently streaming live content. Please check back later.', 'automatic-youtube-gallery' )
153 397 ),
154 - 'ayg_privacy_settings' => array(
155 - 'cookie_consent' => 0,
156 - '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' ),
157 - 'button_label' => __( 'Accept', 'automatic-youtube-gallery' )
398 + 'ayg_privacy_settings' => array(
399 + 'cookie_consent' => 0,
400 + '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' ),
401 + 'button_label' => __( 'Accept', 'automatic-youtube-gallery' )
158 402 )
159 403 );
160 404
161 405 return $defaults;
@@ -268,14 +512,14 @@
268 512 'label' => __( 'Cache Duration', 'automatic-youtube-gallery' ),
269 513 'description' => __( 'Specifies how frequently we should check your YouTube source for new videos/updates.', 'automatic-youtube-gallery' ),
270 514 'type' => 'select',
271 515 'options' => array(
272 - '900' => __( '15 minutes', 'automatic-youtube-gallery' ),
273 - '1800' => __( '30 minutes', 'automatic-youtube-gallery' ),
516 + '900' => __( '15 Minutes', 'automatic-youtube-gallery' ),
517 + '1800' => __( '30 Minutes', 'automatic-youtube-gallery' ),
274 518 '3600' => __( '1 Hour', 'automatic-youtube-gallery' ),
275 519 '86400' => __( '1 Day', 'automatic-youtube-gallery' ),
276 520 '604800' => __( '1 Week', 'automatic-youtube-gallery' ),
277 - '2419200' => __( ' 1Month', 'automatic-youtube-gallery' )
521 + '2419200' => __( '1 Month', 'automatic-youtube-gallery' )
278 522 ),
279 523 'value' => 86400,
280 524 'sanitize_callback' => 'intval'
281 525 )
@@ -306,9 +550,9 @@
306 550 $fields = array(
307 551 array(
308 552 'name' => 'theme',
309 553 'label' => __( 'Select Theme (Layout)', 'automatic-youtube-gallery' ),
310 - 'description' => ( ayg_fs()->is_not_paying() ? sprintf( __( '<a href="%s">Upgrade Pro</a> for more themes (Inline, Popup, Slider, Playlist).', 'automatic-youtube-gallery' ), esc_url( ayg_fs()->get_upgrade_url() ) ) : '' ),
554 + '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() ) ) : '' ),
311 555 'type' => 'select',
312 556 'options' => array(
313 557 'classic' => __( 'Classic', 'automatic-youtube-gallery' )
314 558 ),
@@ -401,8 +645,32 @@
401 645
402 646 ),
403 647 'value' => $gallery_settings['pagination_type'],
404 648 'sanitize_callback' => 'sanitize_key'
649 + ),
650 + array(
651 + 'name' => 'more_button_label',
652 + 'label' => __( 'More Button Label', 'automatic-youtube-gallery' ),
653 + 'description' => __( 'Enter the more button label text.', 'automatic-youtube-gallery' ),
654 + 'type' => 'text',
655 + 'value' => isset( $gallery_settings['more_button_label'] ) ? $gallery_settings['more_button_label'] : __( 'Load More', 'automatic-youtube-gallery' ),
656 + 'sanitize_callback' => 'sanitize_text_field'
657 + ),
658 + array(
659 + 'name' => 'previous_button_label',
660 + 'label' => __( 'Previous Button Label', 'automatic-youtube-gallery' ),
661 + 'description' => __( 'Enter the previous button label text.', 'automatic-youtube-gallery' ),
662 + 'type' => 'text',
663 + 'value' => isset( $gallery_settings['previous_button_label'] ) ? $gallery_settings['previous_button_label'] : __( 'Previous', 'automatic-youtube-gallery' ),
664 + 'sanitize_callback' => 'sanitize_text_field'
665 + ),
666 + array(
667 + 'name' => 'next_button_label',
668 + 'label' => __( 'Next Button Label', 'automatic-youtube-gallery' ),
669 + 'description' => __( 'Enter the next button label text.', 'automatic-youtube-gallery' ),
670 + 'type' => 'text',
671 + 'value' => isset( $gallery_settings['next_button_label'] ) ? $gallery_settings['next_button_label'] : __( 'Next', 'automatic-youtube-gallery' ),
672 + 'sanitize_callback' => 'sanitize_text_field'
405 673 )
406 674 );
407 675
408 676 return apply_filters( 'ayg_gallery_settings_fields', $fields );
@@ -423,9 +691,9 @@
423 691 if ( count( $words_array ) > $words_count ) {
424 692 $words_array[ $words_count ] = '<span class="ayg-player-description-dots">...</span></span><span class="ayg-player-description-more">' . $words_array[ $words_count ];
425 693
426 694 $description = '<span class="ayg-player-description-less">' . implode( ' ', $words_array ) . '</span>';
427 - $description .= '<a href="javascript:void(0);" class="ayg-player-description-toggle-btn">[+] ' . __( 'Show More', 'automatic-youtube-gallery' ) . '</a>';
695 + $description .= '<a href="#" class="ayg-player-description-toggle-btn">[+] ' . __( 'Show More', 'automatic-youtube-gallery' ) . '</a>';
428 696 }
429 697
430 698 $description = nl2br( $description );
431 699 $description = make_clickable( $description );
@@ -493,10 +761,18 @@
493 761 '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' ),
494 762 'type' => 'checkbox',
495 763 'value' => $player_settings['loop'],
496 764 'sanitize_callback' => 'intval'
497 - ),
765 + ),
498 766 array(
767 + 'name' => 'muted',
768 + 'label' => __( 'Muted', 'automatic-youtube-gallery' ),
769 + 'description' => __( 'Check this option to turn OFF the audio output of the video by default.', 'automatic-youtube-gallery' ),
770 + 'type' => 'checkbox',
771 + 'value' => isset( $player_settings['muted'] ) ? $player_settings['muted'] : 0,
772 + 'sanitize_callback' => 'intval'
773 + ),
774 + array(
499 775 'name' => 'controls',
500 776 'label' => __( 'Show Player Controls', 'automatic-youtube-gallery' ),
501 777 'description' => __( 'Uncheck this option to hide the video player controls.', 'automatic-youtube-gallery' ),
502 778 'type' => 'checkbox',
@@ -547,15 +823,44 @@
547 823 ),
548 824 'type' => 'text',
549 825 'value' => $player_settings['cc_lang_pref'],
550 826 'sanitize_callback' => 'sanitize_text_field'
551 - )
827 + ),
828 + array(
829 + 'name' => 'privacy_enhanced_mode',
830 + 'label' => __( 'Privacy Enhanced Mode', 'automatic-youtube-gallery' ),
831 + 'description' => __( "Prevent YouTube from leaving tracking cookies on your visitor's browsers unless they actually play the videos. Please uncheck this option if you see errors while testing your playlist embeds or watching your videos on mobile.", 'automatic-youtube-gallery' ),
832 + 'type' => 'checkbox',
833 + 'value' => isset( $player_settings['privacy_enhanced_mode'] ) ? $player_settings['privacy_enhanced_mode'] : 0,
834 + 'sanitize_callback' => 'intval'
835 + ),
836 + array(
837 + 'name' => 'origin',
838 + 'label' => __( 'Extra Player Security', 'automatic-youtube-gallery' ),
839 + 'description' => __( 'Add site origin information with each embed code as an extra security measure. In YouTube\'s own words, checking this option "protects against malicious third-party JavaScript being injected into your page and hijacking control of your YouTube player."', 'automatic-youtube-gallery' ),
840 + 'type' => 'checkbox',
841 + 'value' => isset( $player_settings['origin'] ) ? $player_settings['origin'] : 0,
842 + 'sanitize_callback' => 'intval'
843 + ),
552 844 );
553 845
554 846 return $fields;
555 847 }
556 848
849 +
557 850 /**
851 + * Get a single video page URL.
852 + *
853 + * @since 2.1.0
854 + * @param stdClass $video YouTube video object.
855 + * @param array $args An array of gallery options.
856 + * @return string Single video URL.
857 + */
858 +function ayg_get_single_video_url( $video, $attributes ) {
859 + return apply_filters( 'ayg_single_video_url', '', $video, $attributes );
860 +}
861 +
862 +/**
558 863 * Get filtered php template file path.
559 864 *
560 865 * @since 1.0.0
561 866 * @param array $template PHP file path.
@@ -582,8 +887,54 @@
582 887 return uniqid() . ++$ayg_uniqid;
583 888 }
584 889
585 890 /**
891 + * Get YouTube domain.
892 + *
893 + * @since 2.3.0
894 + * @return string YouTube embed domain.
895 + */
896 +function ayg_get_youtube_domain() {
897 + $player_settings = get_option( 'ayg_player_settings' );
898 +
899 + $domain = 'https://www.youtube.com';
900 + if ( isset( $player_settings['privacy_enhanced_mode'] ) && ! empty( $player_settings['privacy_enhanced_mode'] ) ) {
901 + $domain = 'https://www.youtube-nocookie.com';
902 + }
903 +
904 + return $domain;
905 +}
906 +
907 +/**
908 + * Inserts a new associative array after another associative array key.
909 + *
910 + * @since 2.1.0
911 + * @param string $key The associative array key to insert after.
912 + * @param array $array An array to insert in to.
913 + * @param array $new_array An array to insert.
914 + * @return array Updated array.
915 + */
916 +function ayg_insert_array_after( $key, $array, $new_array ) {
917 + if ( array_key_exists( $key, $array ) ) {
918 + $new = array();
919 +
920 + foreach ( $array as $k => $value ) {
921 + $new[ $k ] = $value;
922 +
923 + if ( $k === $key ) {
924 + foreach ( $new_array as $new_key => $new_value ) {
925 + $new[ $new_key ] = $new_value;
926 + }
927 + }
928 + }
929 +
930 + return $new;
931 + }
932 +
933 + return $array;
934 +}
935 +
936 +/**
586 937 * Sanitize the integer inputs, accepts empty values.
587 938 *
588 939 * @since 1.0.0
589 940 * @param string|int $value Input value.
@@ -599,11 +950,12 @@
599 950 *
600 951 * @since 2.0.0
601 952 * @param string $text Text to trim.
602 953 * @param int $num_characters Number of characters.
954 + * @param string $append String to append to the end of the excerpt.
603 955 * @return string Trimmed text.
604 956 */
605 -function ayg_trim_words( $text, $num_characters ) {
957 +function ayg_trim_words( $text, $num_characters, $append = '...' ) {
606 958 $num_characters++;
607 959
608 960 $original_text = $text;
609 961 $text = ( $num_characters > 1 ) ? wp_strip_all_tags( $original_text, true ) : nl2br( $original_text );
@@ -618,12 +970,12 @@
618 970 } else {
619 971 $text = $subex;
620 972 }
621 973
622 - $text .= '...';
974 + $text .= $append;
623 975 }
624 976
625 - return apply_filters( 'ayg_trim_words', $text, $original_text, $num_characters );
977 + return apply_filters( 'ayg_trim_words', $text, $original_text, $num_characters, $append );
626 978 }
627 979
628 980 /**
629 981 * Gallery HTML output.