| @@ -21,30 +21,21 @@ | ||
| 21 | 21 | * @param array $args An array of gallery options. |
| 22 | 22 | * @return mixed |
| 23 | 23 | */ |
| 24 | 24 | function ayg_build_gallery( $args ) { |
| 25 | - $general_settings = ayg_get_option( 'ayg_general_settings' ); | |
| 26 | - $strings_settings = ayg_get_option( 'ayg_strings_settings' ); | |
| 25 | + $general_settings = get_option( 'ayg_general_settings' ); | |
| 26 | + $strings_settings = get_option( 'ayg_strings_settings' ); | |
| 27 | 27 | |
| 28 | 28 | global $post; |
| 29 | 29 | |
| 30 | 30 | // Vars |
| 31 | - $fields = ayg_get_editor_fields(); | |
| 32 | - $excluded = array( 'popup' ); // Fields not part of attributes | |
| 31 | + $fields = ayg_get_editor_fields(); | |
| 32 | + $excluded_fields = array( 'popup' ); // Fields not part of attributes | |
| 33 | + $defaults = array(); | |
| 33 | 34 | |
| 34 | - // Defaults not backed by an editor field (kept through shortcode_atts): internal "db" source + sort. | |
| 35 | - $defaults = array( | |
| 36 | - 'db' => '', | |
| 37 | - 'sort_by' => 'date', | |
| 38 | - 'sort_order' => 'desc', | |
| 39 | - 'sort_seed' => '', | |
| 40 | - 'duration_filter' => '', | |
| 41 | - 'duration' => 0 | |
| 42 | - ); | |
| 43 | - | |
| 44 | 35 | foreach ( $fields as $key => $value ) { |
| 45 | 36 | foreach ( $value['fields'] as $field ) { |
| 46 | - if ( in_array( $field['name'], $excluded ) ) { | |
| 37 | + if ( in_array( $field['name'], $excluded_fields ) ) { | |
| 47 | 38 | continue; |
| 48 | 39 | } |
| 49 | 40 | |
| 50 | 41 | $defaults[ $field['name'] ] = $field['value']; |
| @@ -51,46 +42,8 @@ | ||
| 51 | 42 | } |
| 52 | 43 | } |
| 53 | 44 | |
| 54 | 45 | $defaults = array_merge( $defaults, (array) $strings_settings ); |
| 55 | - | |
| 56 | - // Gallery Builder mode: a numeric "id" loads the saved gallery config, layers its saved | |
| 57 | - // settings under $args (shortcode attributes still win, except the source), and switches | |
| 58 | - // the source to the internal "db" type so the existing build pipeline serves it from the DB. | |
| 59 | - if ( isset( $args['id'] ) && is_numeric( $args['id'] ) && (int) $args['id'] > 0 ) { | |
| 60 | - $config = ayg_get_gallery( (int) $args['id'] ); | |
| 61 | - | |
| 62 | - if ( ! $config ) { | |
| 63 | - return sprintf( '<div class="ayg ayg-error">%s</div>', esc_html__( 'Gallery not found.', 'automatic-youtube-gallery' ) ); | |
| 64 | - } | |
| 65 | - | |
| 66 | - $config_params = json_decode( (string) $config->params, true ); | |
| 67 | - if ( ! is_array( $config_params ) ) { | |
| 68 | - $config_params = array(); | |
| 69 | - } | |
| 70 | - | |
| 71 | - // Saved settings act as defaults; explicit shortcode attributes override them. | |
| 72 | - $args = array_merge( $config_params, $args ); | |
| 73 | - | |
| 74 | - // The source always comes from the config and can't be overridden by the shortcode. | |
| 75 | - // Livestream, search and single video query the live API at display time (nothing is | |
| 76 | - // imported/stored); everything else renders from the DB. ayg_get_gallery_source() owns that | |
| 77 | - // mapping so the public AJAX endpoint resolves the same source from the same saved row. | |
| 78 | - $source = ayg_get_gallery_source( $config ); | |
| 79 | - | |
| 80 | - $args['type'] = $source['type']; | |
| 81 | - $args[ $source['field'] ] = $source['src']; | |
| 82 | - | |
| 83 | - // Single video + popup mode → force the popup theme, mirroring the block and widget (which | |
| 84 | - // apply this before calling ayg_build_gallery()). | |
| 85 | - if ( 'video' === $config->source_type && ! empty( $args['popup'] ) ) { | |
| 86 | - $args['theme'] = 'popup'; | |
| 87 | - } | |
| 88 | - | |
| 89 | - // Gallery Builder relationships are keyed by the config ID as a string. | |
| 90 | - $args['uid'] = strval( $config->id ); | |
| 91 | - } | |
| 92 | - | |
| 93 | 46 | $attributes = shortcode_atts( $defaults, $args, 'automatic_youtube_gallery' ); |
| 94 | 47 | |
| 95 | 48 | $attributes['post_id'] = 0; |
| 96 | 49 | if ( isset( $post->ID ) ) { |
| @@ -106,22 +59,14 @@ | ||
| 106 | 59 | if ( empty( $attributes['limit'] ) ) { |
| 107 | 60 | $attributes['limit'] = 500; |
| 108 | 61 | } |
| 109 | 62 | |
| 110 | - $source_type = sanitize_text_field( $attributes['type'] ); | |
| 111 | - | |
| 112 | - // Videos per page. Database (Gallery Builder) galleries read from our own table, so 0 means | |
| 113 | - // "show all videos on a single page" (no pagination). The live-API sources (search, livestream) | |
| 114 | - // stay capped at 50 because that is YouTube's maximum number of results per request. | |
| 115 | - if ( 'db' === $source_type ) { | |
| 116 | - $attributes['per_page'] = max( 0, (int) $attributes['per_page'] ); | |
| 117 | - } else { | |
| 118 | - $attributes['per_page'] = min( 50, (int) $attributes['per_page'] ); | |
| 119 | - if ( empty( $attributes['per_page'] ) ) { | |
| 120 | - $attributes['per_page'] = 50; | |
| 121 | - } | |
| 63 | + $attributes['per_page'] = min( 50, (int) $attributes['per_page'] ); | |
| 64 | + if ( empty( $attributes['per_page'] ) ) { | |
| 65 | + $attributes['per_page'] = 50; | |
| 122 | 66 | } |
| 123 | 67 | |
| 68 | + $source_type = sanitize_text_field( $attributes['type'] ); | |
| 124 | 69 | if ( 'livestream' == $source_type ) { |
| 125 | 70 | $attributes['livestream'] = $attributes['channel']; |
| 126 | 71 | } |
| 127 | 72 | |
| @@ -131,12 +76,8 @@ | ||
| 131 | 76 | } |
| 132 | 77 | |
| 133 | 78 | $source_url = sanitize_text_field( $attributes[ $source_type ] ); |
| 134 | 79 | |
| 135 | - if ( isset( $args['id'] ) && ! empty( $args['id'] ) ) { | |
| 136 | - $attributes['id'] = absint( $args['id'] ); | |
| 137 | - } | |
| 138 | - | |
| 139 | 80 | if ( isset( $args['uid'] ) && ! empty( $args['uid'] ) ) { |
| 140 | 81 | $attributes['uid'] = sanitize_text_field( $args['uid'] ); |
| 141 | 82 | } else { |
| 142 | 83 | $attributes['uid'] = md5( $source_type . $source_url ); |
| @@ -149,47 +90,17 @@ | ||
| 149 | 90 | if ( isset( $args['deprecated_uid'] ) && ! empty( $args['deprecated_uid'] ) ) { |
| 150 | 91 | $deprecated_uid = sanitize_text_field( $args['deprecated_uid'] ); |
| 151 | 92 | } |
| 152 | 93 | |
| 153 | - // Deeplinked video (premium): resolve before the query so DB-served galleries can pin it as | |
| 154 | - // the first item at the SQL level, keeping the per-page count exact. API-served (legacy) | |
| 155 | - // galleries keep the old prepend behavior below. | |
| 156 | - $gallery_id_from_url = get_query_var( 'ayg_gallery_id' ); | |
| 157 | - $video_id_from_url = get_query_var( 'ayg_video_id' ); | |
| 158 | - $deeplinked_video = false; | |
| 159 | - | |
| 160 | - if ( ! empty( $video_id_from_url ) && ( $attributes['uid'] == $gallery_id_from_url || $deprecated_uid == $gallery_id_from_url ) ) { | |
| 161 | - $deeplinked_video = ayg_db_get_video( $video_id_from_url ); | |
| 162 | - } | |
| 163 | - | |
| 164 | - if ( ! $deeplinked_video ) { | |
| 165 | - $video_id_from_url = ''; | |
| 166 | - } | |
| 167 | - | |
| 168 | - $featured_video_id = ( 'db' === $source_type && ! empty( $video_id_from_url ) ) ? sanitize_text_field( $video_id_from_url ) : ''; | |
| 169 | - | |
| 170 | - // Random ordering: generate a per-render seed (once) so RAND(seed) stays stable across this | |
| 171 | - // gallery's own pagination/search AJAX calls. A seed hardcoded in the shortcode is respected. | |
| 172 | - if ( 'random' === $attributes['sort_by'] && empty( $attributes['sort_seed'] ) ) { | |
| 173 | - $attributes['sort_seed'] = wp_rand( 1, 2147483647 ); | |
| 174 | - } | |
| 175 | - | |
| 176 | 94 | // Get Videos |
| 177 | 95 | $api_params = array( |
| 178 | - 'uid' => $attributes['uid'], | |
| 179 | - 'type' => $source_type, | |
| 180 | - 'src' => $source_url, | |
| 181 | - 'store' => true, // Trusted context: the source comes from the rendered shortcode, not from a visitor's request. | |
| 182 | - 'featured_video_id' => $featured_video_id, // Works only when type = "db". | |
| 183 | - 'order' => sanitize_text_field( $attributes['order'] ), // Works only when type = "search". | |
| 184 | - 'sort_by' => sanitize_key( $attributes['sort_by'] ), // Works only when type = "db". | |
| 185 | - 'sort_order' => sanitize_key( $attributes['sort_order'] ), // Works only when type = "db". | |
| 186 | - 'sort_seed' => absint( $attributes['sort_seed'] ), // Works only when type = "db" + sort_by = "random". | |
| 187 | - 'duration_filter' => sanitize_key( $attributes['duration_filter'] ), // Works only when type = "db". | |
| 188 | - 'duration' => absint( $attributes['duration'] ), // Works only when type = "db". | |
| 189 | - 'limit' => $attributes['limit'], // Works only when type = "search". | |
| 190 | - 'maxResults' => $attributes['per_page'], | |
| 191 | - 'cache' => (int) $attributes['cache'] | |
| 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'] | |
| 192 | 103 | ); |
| 193 | 104 | |
| 194 | 105 | $api_params = apply_filters( 'ayg_youtube_api_request_params', $api_params, $args ); |
| 195 | 106 | |
| @@ -199,9 +110,9 @@ | ||
| 199 | 110 | // Process output |
| 200 | 111 | if ( ! isset( $response->error ) ) { |
| 201 | 112 | // Store Gallery ID |
| 202 | 113 | if ( $attributes['post_id'] > 0 && isset( $attributes['deeplinking'] ) && 1 == $attributes['deeplinking'] ) { |
| 203 | - $pages = ayg_get_option( 'ayg_gallery_page_ids' ); | |
| 114 | + $pages = get_option( 'ayg_gallery_page_ids', array() ); | |
| 204 | 115 | $page_id = $attributes['post_id']; |
| 205 | 116 | |
| 206 | 117 | if ( ! in_array( $page_id, $pages ) ) { |
| 207 | 118 | $pages[] = $page_id; |
| @@ -209,24 +120,25 @@ | ||
| 209 | 120 | } |
| 210 | 121 | } |
| 211 | 122 | |
| 212 | 123 | // Gallery |
| 213 | - $videos = array(); | |
| 124 | + $videos = array(); | |
| 214 | 125 | |
| 215 | - if ( ! empty( $video_id_from_url ) ) { | |
| 216 | - // DB-served galleries pin the deeplinked video via the SQL query itself, so the result | |
| 217 | - // set already starts with it. Fall back to prepending it only when the pin couldn't | |
| 218 | - // apply: API-served (legacy) sources, or the video is no longer part of this gallery's | |
| 219 | - // result set (removed from the gallery, or excluded by a duration filter). | |
| 220 | - $is_pinned_by_sql = ! empty( $api_params['featured_video_id'] ) && ! empty( $response->videos ) && $response->videos[0]->id == $video_id_from_url; | |
| 126 | + $gallery_id_from_url = get_query_var( 'ayg_gallery_id' ); | |
| 127 | + $video_id_from_url = get_query_var( 'ayg_video_id' ); | |
| 221 | 128 | |
| 222 | - if ( ! $is_pinned_by_sql ) { | |
| 223 | - $videos[] = $deeplinked_video; | |
| 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 = ''; | |
| 224 | 136 | } |
| 225 | 137 | } |
| 226 | - | |
| 138 | + | |
| 227 | 139 | if ( isset( $response->videos ) ) { |
| 228 | - if ( ! empty( $videos ) ) { | |
| 140 | + if ( ! empty( $video_id_from_url ) ) { | |
| 229 | 141 | foreach ( $response->videos as $video ) { |
| 230 | 142 | if ( $video->id != $video_id_from_url ) { |
| 231 | 143 | $videos[] = $video; |
| 232 | 144 | } |
| @@ -237,17 +149,9 @@ | ||
| 237 | 149 | } |
| 238 | 150 | |
| 239 | 151 | // Pagination |
| 240 | 152 | if ( isset( $response->page_info ) ) { |
| 241 | - $page_info = $response->page_info; | |
| 242 | - | |
| 243 | - // Sign the page tokens on their way out to the browser so the public AJAX endpoint can | |
| 244 | - // tell the tokens this site issued from ones a visitor made up. | |
| 245 | - if ( ayg_page_token_is_signed( $source_type ) ) { | |
| 246 | - $page_info = ayg_sign_page_tokens( $page_info, $attributes['uid'] ); | |
| 247 | - } | |
| 248 | - | |
| 249 | - $attributes = array_merge( $attributes, $api_params, $page_info ); | |
| 153 | + $attributes = array_merge( $attributes, $api_params, $response->page_info ); | |
| 250 | 154 | } |
| 251 | 155 | |
| 252 | 156 | // Theme |
| 253 | 157 | $theme = 'classic'; |
| @@ -309,215 +213,63 @@ | ||
| 309 | 213 | global $wpdb; |
| 310 | 214 | |
| 311 | 215 | require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); |
| 312 | 216 | $charset_collate = $wpdb->get_charset_collate(); |
| 313 | - | |
| 217 | + | |
| 314 | 218 | $videos_table = $wpdb->prefix . 'ayg_videos'; |
| 315 | - $rel_table = $wpdb->prefix . 'ayg_gallery_relationships'; | |
| 316 | - $old_table = $wpdb->prefix . 'ayg_galleries'; | |
| 317 | 219 | |
| 318 | - // Rename wp_ayg_galleries (old pivot) → wp_ayg_gallery_relationships. | |
| 319 | - // Guard: only when the old table exists AND the new name does not yet exist AND | |
| 320 | - // the old table is the pivot (identified by having a video_id column). | |
| 321 | - $old_exists = $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $wpdb->esc_like( $old_table ) ) ) === $old_table; | |
| 322 | - $new_not_exist = $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $wpdb->esc_like( $rel_table ) ) ) !== $rel_table; | |
| 220 | + // Check if the videos table exists | |
| 221 | + $query = $wpdb->prepare( 'SHOW TABLES LIKE %s', $wpdb->esc_like( $videos_table ) ); | |
| 323 | 222 | |
| 324 | - if ( $old_exists && $new_not_exist ) { | |
| 325 | - $is_old_pivot = ! empty( $wpdb->get_results( "SHOW COLUMNS FROM `$old_table` LIKE 'video_id'" ) ); | |
| 326 | - | |
| 327 | - if ( $is_old_pivot ) { | |
| 328 | - $renamed = $wpdb->query( "RENAME TABLE `$old_table` TO `$rel_table`" ); | |
| 329 | - | |
| 330 | - if ( false === $renamed ) { | |
| 331 | - // Rename failed (insufficient DB privilege on some hosts). | |
| 332 | - // This table holds auto-generated cache data, not user content — safe to drop. | |
| 333 | - $wpdb->query( "DROP TABLE IF EXISTS `$old_table`" ); | |
| 334 | - } | |
| 335 | - } | |
| 336 | - } | |
| 337 | - | |
| 338 | - // Rename columns in wp_ayg_videos (NUM → id, id → video_id). | |
| 339 | - // Each ALTER is guarded so the block is idempotent on re-runs. | |
| 340 | - $videos_table_exists = $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $wpdb->esc_like( $videos_table ) ) ) === $videos_table; | |
| 341 | - | |
| 342 | - if ( $videos_table_exists ) { | |
| 343 | - // Rename 'id' → 'video_id' first. Must happen before NUM → id to avoid a duplicate | |
| 344 | - // column name error: if NUM were renamed to 'id' while the varchar 'id' still exists, | |
| 345 | - // MySQL would reject it with "Duplicate column name 'id'". | |
| 346 | - $old_id_col = $wpdb->get_row( "SHOW COLUMNS FROM `$videos_table` LIKE 'id'" ); | |
| 347 | - | |
| 348 | - if ( $old_id_col && false !== strpos( strtolower( $old_id_col->Type ), 'varchar' ) ) { | |
| 349 | - $wpdb->query( "ALTER TABLE `$videos_table` CHANGE `id` `video_id` varchar(100) NOT NULL" ); | |
| 350 | - } | |
| 351 | - | |
| 352 | - // Now safe to rename NUM → id (no column named 'id' exists at this point). | |
| 353 | - $has_num = ! empty( $wpdb->get_results( "SHOW COLUMNS FROM `$videos_table` LIKE 'NUM'" ) ); | |
| 354 | - | |
| 355 | - if ( $has_num ) { | |
| 356 | - $wpdb->query( "ALTER TABLE `$videos_table` CHANGE `NUM` `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT" ); | |
| 357 | - } | |
| 358 | - | |
| 359 | - // Remove duplicate rows using the new column names (idempotent). | |
| 223 | + if ( $wpdb->get_var( $query ) === $videos_table ) { | |
| 224 | + // Find and remove duplicate video IDs | |
| 360 | 225 | $wpdb->query( |
| 361 | 226 | "DELETE v1 FROM $videos_table v1 |
| 362 | 227 | INNER JOIN $videos_table v2 |
| 363 | - ON v1.video_id = v2.video_id AND v1.id > v2.id" | |
| 228 | + ON v1.id = v2.id AND v1.NUM > v2.NUM" | |
| 364 | 229 | ); |
| 365 | 230 | } |
| 366 | 231 | |
| 367 | - // Create/update wp_ayg_videos — dbDelta adds the 2 new columns on existing installs. | |
| 232 | + // Create the videos table | |
| 368 | 233 | $sql = "CREATE TABLE $videos_table ( |
| 369 | - id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT, | |
| 370 | - video_id varchar(100) NOT NULL, | |
| 234 | + NUM bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT, | |
| 235 | + id varchar(100) NOT NULL, | |
| 371 | 236 | title text NOT NULL, |
| 372 | 237 | description text NOT NULL, |
| 373 | 238 | thumbnails text NOT NULL, |
| 374 | 239 | duration varchar(25) NOT NULL, |
| 375 | - duration_seconds int(11) UNSIGNED NOT NULL DEFAULT 0, | |
| 376 | - video_type varchar(20) NOT NULL DEFAULT 'none', | |
| 377 | 240 | status varchar(100) NOT NULL, |
| 378 | 241 | published_at varchar(100) NOT NULL, |
| 379 | 242 | published_at_datetime datetime NULL, |
| 380 | - PRIMARY KEY (id), | |
| 381 | - UNIQUE KEY ayg_unique_video_id (video_id), | |
| 382 | - INDEX ayg_idx_published_at_datetime (published_at_datetime) | |
| 243 | + PRIMARY KEY (NUM), | |
| 244 | + UNIQUE KEY ayg_unique_video_id (id) | |
| 383 | 245 | ) $charset_collate;"; |
| 384 | 246 | |
| 385 | 247 | dbDelta( $sql ); |
| 386 | 248 | |
| 387 | - // Fallback: add UNIQUE KEY if dbDelta did not create it (edge case on existing installs). | |
| 249 | + // Add UNIQUE KEY if it is not added | |
| 388 | 250 | $existing_keys = $wpdb->get_results( "SHOW KEYS FROM $videos_table WHERE Key_name = 'ayg_unique_video_id'" ); |
| 389 | - | |
| 251 | + | |
| 390 | 252 | if ( empty( $existing_keys ) ) { |
| 391 | - $wpdb->query( "ALTER TABLE $videos_table ADD UNIQUE KEY ayg_unique_video_id (video_id)" ); | |
| 253 | + $wpdb->query( "ALTER TABLE $videos_table ADD UNIQUE KEY ayg_unique_video_id (id)" ); | |
| 392 | 254 | } |
| 393 | 255 | |
| 394 | - // Fallback: add INDEX on published_at_datetime if missing (existing installs). | |
| 395 | - $existing_dt_index = $wpdb->get_results( "SHOW KEYS FROM $videos_table WHERE Key_name = 'ayg_idx_published_at_datetime'" ); | |
| 396 | - | |
| 397 | - if ( empty( $existing_dt_index ) ) { | |
| 398 | - $wpdb->query( "ALTER TABLE $videos_table ADD INDEX ayg_idx_published_at_datetime (published_at_datetime)" ); | |
| 399 | - } | |
| 256 | + // Create the galleries table | |
| 257 | + $galleries_table = $wpdb->prefix . 'ayg_galleries'; | |
| 400 | 258 | |
| 401 | - // Rename NUM → id in wp_ayg_gallery_relationships (only if rename succeeded above). | |
| 402 | - // If the table was recreated fresh by dbDelta below, it already has 'id' — no ALTER needed. | |
| 403 | - $rel_table_exists = $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $wpdb->esc_like( $rel_table ) ) ) === $rel_table; | |
| 404 | - | |
| 405 | - if ( $rel_table_exists ) { | |
| 406 | - $has_num_in_rel = ! empty( $wpdb->get_results( "SHOW COLUMNS FROM `$rel_table` LIKE 'NUM'" ) ); | |
| 407 | - | |
| 408 | - if ( $has_num_in_rel ) { | |
| 409 | - $wpdb->query( "ALTER TABLE `$rel_table` CHANGE `NUM` `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT" ); | |
| 410 | - } | |
| 411 | - } | |
| 412 | - | |
| 413 | - // Create/update wp_ayg_gallery_relationships (fresh creation if the rename fallback dropped the old table). | |
| 414 | - $sql = "CREATE TABLE $rel_table ( | |
| 415 | - id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT, | |
| 259 | + $sql = "CREATE TABLE $galleries_table ( | |
| 260 | + NUM bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT, | |
| 416 | 261 | video_id varchar(100) NOT NULL, |
| 417 | 262 | gallery_id varchar(100) NOT NULL, |
| 418 | - synced_at datetime NULL, | |
| 419 | - PRIMARY KEY (id), | |
| 263 | + PRIMARY KEY (NUM), | |
| 420 | 264 | UNIQUE KEY ayg_unique_video_gallery (video_id, gallery_id), |
| 421 | 265 | INDEX ayg_idx_gallery_id (gallery_id) |
| 422 | 266 | ) $charset_collate;"; |
| 423 | 267 | |
| 424 | 268 | dbDelta( $sql ); |
| 425 | - | |
| 426 | - // Fallback: add the synced_at column if dbDelta did not (existing installs). | |
| 427 | - $has_synced_at = ! empty( $wpdb->get_results( "SHOW COLUMNS FROM `$rel_table` LIKE 'synced_at'" ) ); | |
| 428 | - | |
| 429 | - if ( ! $has_synced_at ) { | |
| 430 | - $wpdb->query( "ALTER TABLE `$rel_table` ADD `synced_at` datetime NULL" ); | |
| 431 | - } | |
| 432 | - | |
| 433 | - // Create new wp_ayg_galleries entity table (one row per saved gallery config). | |
| 434 | - $galleries_table = $wpdb->prefix . 'ayg_galleries'; | |
| 435 | - | |
| 436 | - $sql = "CREATE TABLE $galleries_table ( | |
| 437 | - id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT, | |
| 438 | - title text NOT NULL, | |
| 439 | - source_type varchar(50) NOT NULL DEFAULT 'channel', | |
| 440 | - source_value text NOT NULL, | |
| 441 | - params longtext NOT NULL, | |
| 442 | - import_status varchar(20) NOT NULL DEFAULT 'idle', | |
| 443 | - import_error text NULL, | |
| 444 | - import_log longtext NULL, | |
| 445 | - last_imported_at datetime NULL, | |
| 446 | - next_import_at datetime NULL, | |
| 447 | - video_count int(11) UNSIGNED NOT NULL DEFAULT 0, | |
| 448 | - created_at datetime NOT NULL, | |
| 449 | - updated_at datetime NOT NULL, | |
| 450 | - PRIMARY KEY (id), | |
| 451 | - INDEX idx_import (next_import_at, import_status) | |
| 452 | - ) $charset_collate;"; | |
| 453 | - | |
| 454 | - dbDelta( $sql ); | |
| 455 | 269 | } |
| 456 | 270 | |
| 457 | 271 | /** |
| 458 | - * Check whether any videos are linked to the given gallery UID. | |
| 459 | - * | |
| 460 | - * Lets the public AJAX endpoint tell a gallery this site actually displays from a UID a visitor | |
| 461 | - * simply made up: a gallery that has been rendered even once always has its videos in the | |
| 462 | - * relationship table, an invented UID never does. | |
| 463 | - * | |
| 464 | - * @since 2.9.0 | |
| 465 | - * @param string $gallery_id Gallery UID. | |
| 466 | - * @return bool True when at least one video is linked to the UID. | |
| 467 | - */ | |
| 468 | -function ayg_db_gallery_has_videos( $gallery_id ) { | |
| 469 | - global $wpdb; | |
| 470 | - | |
| 471 | - $gallery_id = (string) $gallery_id; | |
| 472 | - | |
| 473 | - if ( '' === $gallery_id ) { | |
| 474 | - return false; | |
| 475 | - } | |
| 476 | - | |
| 477 | - $found = $wpdb->get_var( | |
| 478 | - $wpdb->prepare( | |
| 479 | - "SELECT 1 FROM {$wpdb->prefix}ayg_gallery_relationships WHERE gallery_id = %s LIMIT 1", | |
| 480 | - $gallery_id | |
| 481 | - ) | |
| 482 | - ); | |
| 483 | - | |
| 484 | - return ! empty( $found ); | |
| 485 | -} | |
| 486 | - | |
| 487 | -/** | |
| 488 | - * Get a single video record from our custom database table "{$wpdb->prefix}ayg_videos" | |
| 489 | - * | |
| 490 | - * @since 2.1.0 | |
| 491 | - * @param string $video_id YouTube Video ID. | |
| 492 | - * @return mixed | |
| 493 | - */ | |
| 494 | -function ayg_db_get_video( $video_id ) { | |
| 495 | - global $wpdb; | |
| 496 | - | |
| 497 | - $cache_key = 'ayg_'. $video_id; | |
| 498 | - $row = wp_cache_get( $cache_key ); | |
| 499 | - | |
| 500 | - if ( false === $row ) { | |
| 501 | - $query = $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}ayg_videos WHERE video_id = %s", $video_id ); | |
| 502 | - $row = $wpdb->get_row( $query ); | |
| 503 | - | |
| 504 | - if ( $row ) { | |
| 505 | - if ( ! empty( $row->thumbnails ) ) { | |
| 506 | - $row->thumbnails = ayg_maybe_unserialize( $row->thumbnails ); | |
| 507 | - } | |
| 508 | - | |
| 509 | - // Backward compat: templates reference $video->id as the YouTube video ID. | |
| 510 | - $row->id = $row->video_id; | |
| 511 | - | |
| 512 | - wp_cache_set( $cache_key, $row ); | |
| 513 | - } | |
| 514 | - } | |
| 515 | - | |
| 516 | - return $row; | |
| 517 | -} | |
| 518 | - | |
| 519 | -/** | |
| 520 | 272 | * Store videos in our custom database table "{$wpdb->prefix}ayg_videos" |
| 521 | 273 | * |
| 522 | 274 | * @since 2.1.0 |
| 523 | 275 | * @param object $data YouTube API response object. |
| @@ -537,52 +289,31 @@ | ||
| 537 | 289 | } |
| 538 | 290 | |
| 539 | 291 | global $wpdb; |
| 540 | 292 | |
| 541 | - $items = $data->items; | |
| 542 | - $gallery_id = isset( $attributes['uid'] ) ? $attributes['uid'] : ''; | |
| 543 | - $source_type = isset( $attributes['type'] ) ? $attributes['type'] : 'videos'; | |
| 544 | - $store_gallery = ! empty( $gallery_id ) && 'livestream' !== $source_type; | |
| 545 | - $exclude = ( isset( $attributes['exclude'] ) && is_array( $attributes['exclude'] ) ) ? $attributes['exclude'] : array(); | |
| 293 | + $items = $data->items; | |
| 546 | 294 | |
| 547 | - // Only videos.list responses carry contentDetails.duration and snippet.liveBroadcastContent. | |
| 548 | - // For other responses (playlistItems.list, search.list) the duration_seconds / video_type | |
| 549 | - // columns are left out entirely so existing values are never clobbered with defaults. | |
| 550 | - $has_video_details = isset( $data->kind ) && 'youtube#videoListResponse' === $data->kind; | |
| 551 | - | |
| 552 | - $videos_table = $wpdb->prefix . 'ayg_videos'; | |
| 553 | - $galleries_table = $wpdb->prefix . 'ayg_gallery_relationships'; | |
| 554 | - | |
| 555 | - $video_placeholders = array(); | |
| 556 | - $video_values = array(); | |
| 557 | - $gallery_placeholders = array(); | |
| 558 | - $gallery_values = array(); | |
| 559 | - | |
| 560 | - foreach ( $items as $item ) { | |
| 295 | + // Store Videos | |
| 296 | + foreach ( $items as $item ) { | |
| 561 | 297 | $row = array(); |
| 562 | 298 | |
| 563 | 299 | // Video ID |
| 564 | - $row['video_id'] = ''; | |
| 300 | + $row['id'] = ''; | |
| 565 | 301 | |
| 566 | 302 | if ( isset( $item->snippet->resourceId ) && isset( $item->snippet->resourceId->videoId ) ) { |
| 567 | - $row['video_id'] = $item->snippet->resourceId->videoId; | |
| 303 | + $row['id'] = $item->snippet->resourceId->videoId; | |
| 568 | 304 | } elseif ( isset( $item->contentDetails ) && isset( $item->contentDetails->videoId ) ) { |
| 569 | - $row['video_id'] = $item->contentDetails->videoId; | |
| 305 | + $row['id'] = $item->contentDetails->videoId; | |
| 570 | 306 | } elseif ( isset( $item->id ) && isset( $item->id->videoId ) ) { |
| 571 | - $row['video_id'] = $item->id->videoId; | |
| 307 | + $row['id'] = $item->id->videoId; | |
| 572 | 308 | } elseif ( isset( $item->id ) ) { |
| 573 | - $row['video_id'] = $item->id; | |
| 574 | - } | |
| 309 | + $row['id'] = $item->id; | |
| 310 | + } | |
| 575 | 311 | |
| 576 | - if ( empty( $row['video_id'] ) ) { | |
| 312 | + if ( empty( $row['id'] ) ) { | |
| 577 | 313 | continue; |
| 578 | 314 | } |
| 579 | 315 | |
| 580 | - // Skip videos on the gallery's exclude list (kept out of both tables) | |
| 581 | - if ( ayg_is_video_excluded( $row['video_id'], $exclude ) ) { | |
| 582 | - continue; | |
| 583 | - } | |
| 584 | - | |
| 585 | 316 | // Video title |
| 586 | 317 | $row['title'] = $item->snippet->title; |
| 587 | 318 | |
| 588 | 319 | // Video description |
| @@ -591,40 +322,29 @@ | ||
| 591 | 322 | // Video thumbnails |
| 592 | 323 | $row['thumbnails'] = ''; |
| 593 | 324 | if ( isset( $item->snippet->thumbnails ) ) { |
| 594 | 325 | $row['thumbnails'] = serialize( $item->snippet->thumbnails ); |
| 595 | - } | |
| 326 | + } | |
| 596 | 327 | |
| 597 | 328 | // Video duration |
| 598 | 329 | $row['duration'] = ''; |
| 599 | 330 | if ( isset( $item->contentDetails ) && isset( $item->contentDetails->duration ) ) { |
| 600 | 331 | $row['duration'] = $item->contentDetails->duration; |
| 601 | - } | |
| 332 | + } | |
| 602 | 333 | |
| 603 | - if ( $has_video_details ) { | |
| 604 | - $row['duration_seconds'] = ayg_parse_duration_seconds( $row['duration'] ); | |
| 605 | - | |
| 606 | - // Raw liveBroadcastContent value ('live', 'upcoming', 'none'); shorts are not | |
| 607 | - // classified at import time — filter by duration_seconds <= 60 at query time. | |
| 608 | - $row['video_type'] = 'none'; | |
| 609 | - if ( ! empty( $item->snippet->liveBroadcastContent ) ) { | |
| 610 | - $row['video_type'] = $item->snippet->liveBroadcastContent; | |
| 611 | - } | |
| 612 | - } | |
| 613 | - | |
| 614 | 334 | // Video status |
| 615 | 335 | $row['status'] = 'private'; |
| 616 | - | |
| 336 | + | |
| 617 | 337 | if ( isset( $item->status ) && ( 'public' == $item->status->privacyStatus || 'unlisted' == $item->status->privacyStatus ) ) { |
| 618 | - $row['status'] = 'public'; | |
| 338 | + $row['status'] = 'public'; | |
| 619 | 339 | } |
| 620 | 340 | |
| 621 | 341 | if ( isset( $item->snippet->status ) && ( 'public' == $item->snippet->status->privacyStatus || 'unlisted' == $item->snippet->status->privacyStatus ) ) { |
| 622 | - $row['status'] = 'public'; | |
| 342 | + $row['status'] = 'public'; | |
| 623 | 343 | } |
| 624 | 344 | |
| 625 | 345 | if ( 'youtube#searchResult' == $item->kind ) { |
| 626 | - $row['status'] = 'public'; | |
| 346 | + $row['status'] = 'public'; | |
| 627 | 347 | } |
| 628 | 348 | |
| 629 | 349 | // Video publish date |
| 630 | 350 | $row['published_at'] = $item->snippet->publishedAt; |
| @@ -629,168 +349,101 @@ | ||
| 629 | 349 | // Video publish date |
| 630 | 350 | $row['published_at'] = $item->snippet->publishedAt; |
| 631 | 351 | |
| 632 | 352 | $datetime = new DateTime( $item->snippet->publishedAt ); |
| 633 | - $row['published_at_datetime'] = date_format( $datetime, 'Y-m-d H:i:s' ); | |
| 353 | + $row['published_at_datetime'] = date_format( $datetime, 'Y-m-d H:i:s' ); | |
| 634 | 354 | |
| 635 | - // Collect for bulk insert | |
| 636 | - if ( $has_video_details ) { | |
| 637 | - $video_placeholders[] = '(%s, %s, %s, %s, %s, %d, %s, %s, %s, %s)'; | |
| 355 | + // Store the video | |
| 356 | + $videos_table = $wpdb->prefix . 'ayg_videos'; | |
| 638 | 357 | |
| 639 | - array_push( | |
| 640 | - $video_values, | |
| 641 | - $row['video_id'], | |
| 642 | - $row['title'], | |
| 643 | - $row['description'], | |
| 644 | - $row['thumbnails'], | |
| 645 | - $row['duration'], | |
| 646 | - $row['duration_seconds'], | |
| 647 | - $row['video_type'], | |
| 648 | - $row['status'], | |
| 649 | - $row['published_at'], | |
| 650 | - $row['published_at_datetime'] | |
| 651 | - ); | |
| 652 | - } else { | |
| 653 | - $video_placeholders[] = '(%s, %s, %s, %s, %s, %s, %s, %s)'; | |
| 358 | + $query = $wpdb->prepare( | |
| 359 | + "INSERT INTO $videos_table (id, title, description, thumbnails, duration, status, published_at, published_at_datetime) | |
| 360 | + VALUES (%s, %s, %s, %s, %s, %s, %s, %s) | |
| 361 | + ON DUPLICATE KEY UPDATE | |
| 362 | + title = VALUES(title), | |
| 363 | + description = VALUES(description), | |
| 364 | + thumbnails = VALUES(thumbnails), | |
| 365 | + duration = VALUES(duration), | |
| 366 | + status = VALUES(status), | |
| 367 | + published_at = VALUES(published_at), | |
| 368 | + published_at_datetime = VALUES(published_at_datetime)", | |
| 369 | + $row['id'], | |
| 370 | + $row['title'], | |
| 371 | + $row['description'], | |
| 372 | + $row['thumbnails'], | |
| 373 | + $row['duration'], | |
| 374 | + $row['status'], | |
| 375 | + $row['published_at'], | |
| 376 | + $row['published_at_datetime'] | |
| 377 | + ); | |
| 654 | 378 | |
| 655 | - array_push( | |
| 656 | - $video_values, | |
| 657 | - $row['video_id'], | |
| 658 | - $row['title'], | |
| 659 | - $row['description'], | |
| 660 | - $row['thumbnails'], | |
| 661 | - $row['duration'], | |
| 662 | - $row['status'], | |
| 663 | - $row['published_at'], | |
| 664 | - $row['published_at_datetime'] | |
| 665 | - ); | |
| 666 | - } | |
| 379 | + $wpdb->query( $query ); | |
| 667 | 380 | |
| 668 | - if ( $store_gallery ) { | |
| 669 | - $gallery_placeholders[] = '(%s, %s)'; | |
| 670 | - array_push( $gallery_values, $row['video_id'], $gallery_id ); | |
| 671 | - } | |
| 672 | - } | |
| 381 | + // Store the gallery association | |
| 382 | + $gallery_id = isset( $attributes['uid'] ) ? $attributes['uid'] : ''; | |
| 383 | + $source_type = isset( $attributes['type'] ) ? $attributes['type'] : 'videos'; | |
| 673 | 384 | |
| 674 | - // Bulk insert videos (2 queries total instead of N×2) | |
| 675 | - if ( ! empty( $video_placeholders ) ) { | |
| 676 | - if ( $has_video_details ) { | |
| 677 | - $sql = "INSERT INTO $videos_table (video_id, title, description, thumbnails, duration, duration_seconds, video_type, status, published_at, published_at_datetime) | |
| 678 | - VALUES " . implode( ', ', $video_placeholders ) . " | |
| 679 | - ON DUPLICATE KEY UPDATE | |
| 680 | - title = VALUES(title), | |
| 681 | - description = VALUES(description), | |
| 682 | - thumbnails = VALUES(thumbnails), | |
| 683 | - duration = VALUES(duration), | |
| 684 | - duration_seconds = VALUES(duration_seconds), | |
| 685 | - video_type = VALUES(video_type), | |
| 686 | - status = VALUES(status), | |
| 687 | - published_at = VALUES(published_at), | |
| 688 | - published_at_datetime = VALUES(published_at_datetime)"; | |
| 689 | - } else { | |
| 690 | - $sql = "INSERT INTO $videos_table (video_id, title, description, thumbnails, duration, status, published_at, published_at_datetime) | |
| 691 | - VALUES " . implode( ', ', $video_placeholders ) . " | |
| 692 | - ON DUPLICATE KEY UPDATE | |
| 693 | - title = VALUES(title), | |
| 694 | - description = VALUES(description), | |
| 695 | - thumbnails = VALUES(thumbnails), | |
| 696 | - duration = VALUES(duration), | |
| 697 | - status = VALUES(status), | |
| 698 | - published_at = VALUES(published_at), | |
| 699 | - published_at_datetime = VALUES(published_at_datetime)"; | |
| 700 | - } | |
| 385 | + if ( ! empty( $gallery_id ) && ! in_array( $source_type, array( 'video', 'livestream' ) ) ) { | |
| 386 | + $galleries_table = $wpdb->prefix . 'ayg_galleries'; | |
| 701 | 387 | |
| 702 | - $wpdb->query( $wpdb->prepare( $sql, $video_values ) ); | |
| 703 | - } | |
| 388 | + $query = $wpdb->prepare( | |
| 389 | + "INSERT IGNORE INTO $galleries_table (video_id, gallery_id) VALUES (%s, %s)", | |
| 390 | + $row['id'], | |
| 391 | + $gallery_id | |
| 392 | + ); | |
| 704 | 393 | |
| 705 | - // Bulk insert gallery relationships (2 queries total instead of N×2) | |
| 706 | - if ( ! empty( $gallery_placeholders ) ) { | |
| 707 | - $sql = "INSERT IGNORE INTO $galleries_table (video_id, gallery_id) VALUES " . implode( ', ', $gallery_placeholders ); | |
| 708 | - $wpdb->query( $wpdb->prepare( $sql, $gallery_values ) ); | |
| 394 | + $wpdb->query( $query ); | |
| 395 | + } | |
| 709 | 396 | } |
| 710 | 397 | } |
| 711 | 398 | |
| 712 | 399 | /** |
| 713 | - * Dump our plugin transients. | |
| 400 | + * Get a single video record from our custom database table "{$wpdb->prefix}ayg_videos" | |
| 714 | 401 | * |
| 715 | - * @since 2.1.0 | |
| 716 | - * @param string $uid Gallery uid to target. Empty string flushes all plugin transients. | |
| 402 | + * @since 2.1.0 | |
| 403 | + * @param string $video_id YouTube Video ID. | |
| 404 | + * @return mixed | |
| 717 | 405 | */ |
| 718 | -function ayg_delete_cache( $uid = '' ) { | |
| 719 | - $uid = (string) $uid; | |
| 720 | - $keys = (array) ayg_get_option( 'ayg_transient_keys' ); | |
| 406 | +function ayg_db_get_video( $video_id ) { | |
| 407 | + global $wpdb; | |
| 721 | 408 | |
| 722 | - // Targeted: delete only the keys prefixed with this gallery's uid, keep the rest in the registry. | |
| 723 | - if ( '' !== $uid ) { | |
| 724 | - $prefix = 'ayg_' . $uid . '_'; | |
| 725 | - $remaining = array(); | |
| 409 | + $cache_key = 'ayg_'. $video_id; | |
| 410 | + $row = wp_cache_get( $cache_key ); | |
| 726 | 411 | |
| 727 | - foreach ( $keys as $key ) { | |
| 728 | - if ( 0 === strpos( $key, $prefix ) ) { | |
| 729 | - delete_transient( $key ); | |
| 730 | - } else { | |
| 731 | - $remaining[] = $key; | |
| 412 | + if ( false === $row ) { | |
| 413 | + $query = $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}ayg_videos WHERE id = %s", $video_id ); | |
| 414 | + $row = $wpdb->get_row( $query ); | |
| 415 | + | |
| 416 | + if ( $row ) { | |
| 417 | + if ( ! empty( $row->thumbnails ) ) { | |
| 418 | + $row->thumbnails = unserialize( $row->thumbnails ); | |
| 732 | 419 | } |
| 733 | - } | |
| 734 | 420 | |
| 735 | - update_option( 'ayg_transient_keys', $remaining, false ); | |
| 736 | - return; | |
| 421 | + wp_cache_set( $cache_key, $row ); | |
| 422 | + } | |
| 737 | 423 | } |
| 738 | 424 | |
| 739 | - // Full flush: every transient, plus the cached gallery page-id lookup. | |
| 740 | - delete_option( 'ayg_gallery_page_ids' ); | |
| 741 | - | |
| 742 | - foreach ( $keys as $key ) { | |
| 743 | - delete_transient( $key ); | |
| 744 | - } | |
| 745 | - | |
| 746 | - // Reset our DB value (autoload=no: not needed on every page load) | |
| 747 | - update_option( 'ayg_transient_keys', array(), false ); | |
| 425 | + return $row; | |
| 748 | 426 | } |
| 749 | 427 | |
| 750 | 428 | /** |
| 751 | - * Remove a gallery's excluded videos from the relationship table. | |
| 429 | + * Dump our plugin transients. | |
| 752 | 430 | * |
| 753 | - * @since 2.8.0 | |
| 754 | - * @param int $gallery_id Gallery ID. | |
| 755 | - * @param array $exclude Exclude entries (video IDs or URLs). | |
| 756 | - * @return int Number of relationships removed. | |
| 431 | + * @since 2.1.0 | |
| 757 | 432 | */ |
| 758 | -function ayg_delete_excluded_relationships( $gallery_id, $exclude ) { | |
| 759 | - global $wpdb; | |
| 433 | +function ayg_delete_cache() { | |
| 434 | + delete_option( 'ayg_gallery_page_ids' ); | |
| 435 | + | |
| 436 | + // Get the current list of transients | |
| 437 | + $transient_keys = get_option( 'ayg_transient_keys', array() ); | |
| 760 | 438 | |
| 761 | - $gallery_id = absint( $gallery_id ); | |
| 762 | - | |
| 763 | - if ( $gallery_id <= 0 || empty( $exclude ) || ! is_array( $exclude ) ) { | |
| 764 | - return 0; | |
| 439 | + // For each key, delete that transient | |
| 440 | + foreach ( $transient_keys as $key ) { | |
| 441 | + delete_transient( $key ); | |
| 765 | 442 | } |
| 766 | - | |
| 767 | - // Resolve the exclude entries (IDs or URLs) to video IDs. | |
| 768 | - $video_ids = array(); | |
| 769 | - | |
| 770 | - foreach ( $exclude as $entry ) { | |
| 771 | - $video_id = ayg_get_youtube_video_id( $entry ); | |
| 772 | - | |
| 773 | - if ( '' !== $video_id ) { | |
| 774 | - $video_ids[] = $video_id; | |
| 775 | - } | |
| 776 | - } | |
| 777 | - | |
| 778 | - $video_ids = array_values( array_unique( $video_ids ) ); | |
| 779 | - | |
| 780 | - if ( empty( $video_ids ) ) { | |
| 781 | - return 0; | |
| 782 | - } | |
| 783 | - | |
| 784 | - $rel_table = $wpdb->prefix . 'ayg_gallery_relationships'; | |
| 785 | - $placeholders = implode( ',', array_fill( 0, count( $video_ids ), '%s' ) ); | |
| 786 | - | |
| 787 | - return (int) $wpdb->query( | |
| 788 | - $wpdb->prepare( | |
| 789 | - "DELETE FROM $rel_table WHERE gallery_id = %s AND video_id IN ( $placeholders )", | |
| 790 | - array_merge( array( strval( $gallery_id ) ), $video_ids ) | |
| 791 | - ) | |
| 792 | - ); | |
| 443 | + | |
| 444 | + // Reset our DB value | |
| 445 | + update_option( 'ayg_transient_keys', array() ); | |
| 793 | 446 | } |
| 794 | 447 | |
| 795 | 448 | /** |
| 796 | 449 | * Get current address bar URL. |
| @@ -813,14 +466,11 @@ | ||
| 813 | 466 | */ |
| 814 | 467 | function ayg_get_default_settings() { |
| 815 | 468 | $defaults = array( |
| 816 | 469 | 'ayg_general_settings' => array( |
| 817 | - 'force_load_assets' => array( | |
| 818 | - 'css' => 'css' | |
| 819 | - ), | |
| 820 | - 'api_key' => '', | |
| 821 | - 'lazyload' => 0, | |
| 822 | - 'development_mode' => 0 | |
| 470 | + 'api_key' => '', | |
| 471 | + 'lazyload' => 0, | |
| 472 | + 'development_mode' => 0 | |
| 823 | 473 | ), |
| 824 | 474 | 'ayg_strings_settings' => array( |
| 825 | 475 | 'more_button_label' => __( 'Load More', 'automatic-youtube-gallery' ), |
| 826 | 476 | 'previous_button_label' => __( 'Previous', 'automatic-youtube-gallery' ), |
| @@ -854,8 +504,9 @@ | ||
| 854 | 504 | 'muted' => 0, |
| 855 | 505 | 'controls' => 1, |
| 856 | 506 | 'modestbranding' => 1, |
| 857 | 507 | 'cc_load_policy' => 0, |
| 508 | + 'iv_load_policy' => 0, | |
| 858 | 509 | 'hl' => '', |
| 859 | 510 | 'cc_lang_pref' => '', |
| 860 | 511 | 'privacy_enhanced_mode' => 0, |
| 861 | 512 | 'origin' => 0 |
| @@ -878,12 +529,12 @@ | ||
| 878 | 529 | * |
| 879 | 530 | * @since 1.0.0 |
| 880 | 531 | * @return array Array of fields. |
| 881 | 532 | */ |
| 882 | -function ayg_get_editor_fields() { | |
| 533 | +function ayg_get_editor_fields() { | |
| 883 | 534 | $fields = array( |
| 884 | 535 | 'source' => array( |
| 885 | - 'label' => __( 'Source Configuration', 'automatic-youtube-gallery' ), | |
| 536 | + 'label' => __( 'General', 'automatic-youtube-gallery' ), | |
| 886 | 537 | 'fields' => array( |
| 887 | 538 | array( |
| 888 | 539 | 'name' => 'type', |
| 889 | 540 | 'label' => __( 'Source Type', 'automatic-youtube-gallery' ), |
| @@ -888,9 +539,17 @@ | ||
| 888 | 539 | 'name' => 'type', |
| 889 | 540 | 'label' => __( 'Source Type', 'automatic-youtube-gallery' ), |
| 890 | 541 | 'description' => '', |
| 891 | 542 | 'type' => 'select', |
| 892 | - 'options' => ayg_get_source_types(), | |
| 543 | + 'options' => array( | |
| 544 | + 'playlist' => __( 'Playlist', 'automatic-youtube-gallery' ), | |
| 545 | + 'channel' => __( 'Channel', 'automatic-youtube-gallery' ), | |
| 546 | + 'username' => __( 'Username', 'automatic-youtube-gallery' ), | |
| 547 | + 'search' => __( 'Search Keywords', 'automatic-youtube-gallery' ), | |
| 548 | + 'video' => __( 'Single Video', 'automatic-youtube-gallery' ), | |
| 549 | + 'livestream' => __( 'Livestream', 'automatic-youtube-gallery' ), | |
| 550 | + 'videos' => __( 'Custom Videos List', 'automatic-youtube-gallery' ) | |
| 551 | + ), | |
| 893 | 552 | 'value' => 'playlist', |
| 894 | 553 | 'sanitize_callback' => 'sanitize_key' |
| 895 | 554 | ), |
| 896 | 555 | array( |
| @@ -897,18 +556,16 @@ | ||
| 897 | 556 | 'name' => 'playlist', |
| 898 | 557 | 'label' => __( 'YouTube Playlist ID (or) URL', 'automatic-youtube-gallery' ), |
| 899 | 558 | 'description' => sprintf( '%s: https://www.youtube.com/playlist?list=XXXXXXXXXX', __( 'Example', 'automatic-youtube-gallery' ) ), |
| 900 | 559 | 'type' => 'url', |
| 901 | - 'required' => 1, | |
| 902 | 560 | 'value' => '', |
| 903 | 561 | 'sanitize_callback' => 'sanitize_text_field' |
| 904 | 562 | ), |
| 905 | 563 | array( |
| 906 | 564 | 'name' => 'channel', |
| 907 | - 'label' => __( 'YouTube Channel ID (or) a Video URL from the Channel', 'automatic-youtube-gallery' ), | |
| 565 | + 'label' => __( 'YouTube Channel ID (or) a YouTube Video URL from the Channel', 'automatic-youtube-gallery' ), | |
| 908 | 566 | 'description' => sprintf( '%s: https://www.youtube.com/channel/XXXXXXXXXX', __( 'Example', 'automatic-youtube-gallery' ) ), |
| 909 | 567 | 'type' => 'url', |
| 910 | - 'required' => 1, | |
| 911 | 568 | 'value' => '', |
| 912 | 569 | 'sanitize_callback' => 'sanitize_text_field' |
| 913 | 570 | ), |
| 914 | 571 | array( |
| @@ -915,9 +572,8 @@ | ||
| 915 | 572 | 'name' => 'username', |
| 916 | 573 | 'label' => __( 'YouTube Account Username', 'automatic-youtube-gallery' ), |
| 917 | 574 | 'description' => sprintf( '%s: SanRosh', __( 'Example', 'automatic-youtube-gallery' ) ), |
| 918 | 575 | 'type' => 'text', |
| 919 | - 'required' => 1, | |
| 920 | 576 | 'value' => '', |
| 921 | 577 | 'sanitize_callback' => 'sanitize_text_field' |
| 922 | 578 | ), |
| 923 | 579 | array( |
| @@ -924,9 +580,8 @@ | ||
| 924 | 580 | 'name' => 'search', |
| 925 | 581 | 'label' => __( 'Search Keywords', 'automatic-youtube-gallery' ), |
| 926 | 582 | 'description' => sprintf( '%s: Cartoon (space:AND , -:NOT , |:OR)', __( 'Example', 'automatic-youtube-gallery' ) ), |
| 927 | 583 | 'type' => 'text', |
| 928 | - 'required' => 1, | |
| 929 | 584 | 'value' => '', |
| 930 | 585 | 'sanitize_callback' => 'sanitize_text_field' |
| 931 | 586 | ), |
| 932 | 587 | array( |
| @@ -933,9 +588,8 @@ | ||
| 933 | 588 | 'name' => 'video', |
| 934 | 589 | 'label' => __( 'YouTube Video ID (or) URL', 'automatic-youtube-gallery' ), |
| 935 | 590 | 'description' => sprintf( '%s: https://www.youtube.com/watch?v=XXXXXXXXXX', __( 'Example', 'automatic-youtube-gallery' ) ), |
| 936 | 591 | 'type' => 'url', |
| 937 | - 'required' => 1, | |
| 938 | 592 | 'value' => '', |
| 939 | 593 | 'sanitize_callback' => 'sanitize_text_field' |
| 940 | 594 | ), |
| 941 | 595 | array( |
| @@ -942,16 +596,15 @@ | ||
| 942 | 596 | 'name' => 'videos', |
| 943 | 597 | 'label' => __( 'YouTube Video IDs (or) URLs', 'automatic-youtube-gallery' ), |
| 944 | 598 | 'description' => sprintf( '%s: https://www.youtube.com/watch?v=XXXXXXXXXX', __( 'Example', 'automatic-youtube-gallery' ) ), |
| 945 | 599 | 'type' => 'textarea', |
| 946 | - 'required' => 1, | |
| 947 | 600 | 'placeholder' => __( 'Enter one video per line', 'automatic-youtube-gallery' ), |
| 948 | 601 | 'value' => '', |
| 949 | - 'sanitize_callback' => 'sanitize_textarea_field' | |
| 602 | + 'sanitize_callback' => 'sanitize_text_field' | |
| 950 | 603 | ), |
| 951 | 604 | array( |
| 952 | 605 | 'name' => 'order', |
| 953 | - 'label' => __( 'Search Order', 'automatic-youtube-gallery' ), | |
| 606 | + 'label' => __( 'Order Videos by', 'automatic-youtube-gallery' ), | |
| 954 | 607 | 'description' => '', |
| 955 | 608 | 'type' => 'select', |
| 956 | 609 | 'options' => array( |
| 957 | 610 | 'date' => __( 'Date', 'automatic-youtube-gallery' ), |
| @@ -960,14 +613,14 @@ | ||
| 960 | 613 | 'title' => __( 'Title', 'automatic-youtube-gallery' ), |
| 961 | 614 | 'viewCount' => __( 'View Count', 'automatic-youtube-gallery' ) |
| 962 | 615 | ), |
| 963 | 616 | 'value' => 'relevance', |
| 964 | - 'sanitize_callback' => 'sanitize_text_field' | |
| 617 | + 'sanitize_callback' => 'sanitize_key' | |
| 965 | 618 | ), |
| 966 | 619 | array( |
| 967 | 620 | 'name' => 'limit', |
| 968 | - 'label' => __( 'Search Limit', 'automatic-youtube-gallery' ), | |
| 969 | - 'description' => __( 'Enter the number of videos to display in this gallery. Set to 0 for the maximum amount (500).', 'automatic-youtube-gallery' ), | |
| 621 | + 'label' => __( 'Number of Videos', 'automatic-youtube-gallery' ), | |
| 622 | + 'description' => __( 'Specifies the maximum number of videos that will appear in this gallery. Set to 0 for the maximum amount (500).', 'automatic-youtube-gallery' ), | |
| 970 | 623 | 'type' => 'number', |
| 971 | 624 | 'min' => 0, |
| 972 | 625 | 'max' => 500, |
| 973 | 626 | 'value' => 0, |
| @@ -992,17 +645,17 @@ | ||
| 992 | 645 | ) |
| 993 | 646 | ) |
| 994 | 647 | ), |
| 995 | 648 | 'gallery' => array( |
| 996 | - 'label' => __( 'Gallery Options', 'automatic-youtube-gallery' ), | |
| 649 | + 'label' => __( 'Gallery (optional)', 'automatic-youtube-gallery' ), | |
| 997 | 650 | 'fields' => ayg_get_gallery_settings_fields() |
| 998 | 651 | ), |
| 999 | 652 | 'player' => array( |
| 1000 | - 'label' => __( 'Player Options', 'automatic-youtube-gallery' ), | |
| 653 | + 'label' => __( 'Player (optional)', 'automatic-youtube-gallery' ), | |
| 1001 | 654 | 'fields' => ayg_get_player_settings_fields() |
| 1002 | 655 | ), |
| 1003 | 656 | 'search' => array( |
| 1004 | - 'label' => __( 'Search Form', 'automatic-youtube-gallery' ), | |
| 657 | + 'label' => __( 'Search Form (optional)', 'automatic-youtube-gallery' ), | |
| 1005 | 658 | 'fields' => array( |
| 1006 | 659 | array( |
| 1007 | 660 | 'name' => 'search_form', |
| 1008 | 661 | 'label' => __( 'Search Form', 'automatic-youtube-gallery' ), |
| @@ -1021,23 +674,8 @@ | ||
| 1021 | 674 | return apply_filters( 'ayg_editor_fields', $fields ); |
| 1022 | 675 | } |
| 1023 | 676 | |
| 1024 | 677 | /** |
| 1025 | - * Fetch a single gallery row by ID. | |
| 1026 | - * | |
| 1027 | - * @since 2.8.0 | |
| 1028 | - * @param int $gallery_id Gallery ID. | |
| 1029 | - * @return object|null | |
| 1030 | - */ | |
| 1031 | -function ayg_get_gallery( $gallery_id ) { | |
| 1032 | - global $wpdb; | |
| 1033 | - | |
| 1034 | - return $wpdb->get_row( | |
| 1035 | - $wpdb->prepare( "SELECT * FROM `{$wpdb->prefix}ayg_galleries` WHERE id = %d", absint( $gallery_id ) ) | |
| 1036 | - ); | |
| 1037 | -} | |
| 1038 | - | |
| 1039 | -/** | |
| 1040 | 678 | * Get gallery settings fields. |
| 1041 | 679 | * |
| 1042 | 680 | * @since 1.0.0 |
| 1043 | 681 | * @return array $fields Array of fields. |
| @@ -1042,9 +680,9 @@ | ||
| 1042 | 680 | * @since 1.0.0 |
| 1043 | 681 | * @return array $fields Array of fields. |
| 1044 | 682 | */ |
| 1045 | 683 | function ayg_get_gallery_settings_fields() { |
| 1046 | - $gallery_settings = ayg_get_option( 'ayg_gallery_settings' ); | |
| 684 | + $gallery_settings = get_option( 'ayg_gallery_settings' ); | |
| 1047 | 685 | |
| 1048 | 686 | $fields = array( |
| 1049 | 687 | array( |
| 1050 | 688 | 'name' => 'theme', |
| @@ -1069,9 +707,9 @@ | ||
| 1069 | 707 | ), |
| 1070 | 708 | array( |
| 1071 | 709 | 'name' => 'per_page', |
| 1072 | 710 | 'label' => __( 'Videos per Page', 'automatic-youtube-gallery' ), |
| 1073 | - 'description' => __( 'Enter the number of videos to show per page. Maximum of 50.', 'automatic-youtube-gallery' ), | |
| 711 | + 'description' => __( 'Enter the number of videos to show per page. Maximum of 50.', 'automatic-youtube-gallery' ), | |
| 1074 | 712 | 'type' => 'number', |
| 1075 | 713 | 'min' => 0, |
| 1076 | 714 | 'max' => 50, |
| 1077 | 715 | 'value' => $gallery_settings['per_page'], |
| @@ -1080,13 +718,12 @@ | ||
| 1080 | 718 | array( |
| 1081 | 719 | 'name' => 'thumb_ratio', |
| 1082 | 720 | 'label' => __( 'Image Height (Ratio)', 'automatic-youtube-gallery' ), |
| 1083 | 721 | 'description' => __( 'Select the ratio value used to calculate the image height in the gallery thumbnails.', 'automatic-youtube-gallery' ), |
| 1084 | - 'type' => 'select', | |
| 722 | + 'type' => 'radio', | |
| 1085 | 723 | 'options' => array( |
| 1086 | - '56.25' => __( 'Standard (16:9) — Default', 'automatic-youtube-gallery' ), | |
| 1087 | - '177.78' => __( 'Shorts / Vertical (9:16)', 'automatic-youtube-gallery' ), | |
| 1088 | - '75' => __( 'Classic (4:3)', 'automatic-youtube-gallery' ) | |
| 724 | + '56.25' => '16:9', | |
| 725 | + '75' => '4:3' | |
| 1089 | 726 | ), |
| 1090 | 727 | 'value' => $gallery_settings['thumb_ratio'], |
| 1091 | 728 | 'sanitize_callback' => 'floatval' |
| 1092 | 729 | ), |
| @@ -1151,198 +788,8 @@ | ||
| 1151 | 788 | return apply_filters( 'ayg_gallery_settings_fields', $fields ); |
| 1152 | 789 | } |
| 1153 | 790 | |
| 1154 | 791 | /** |
| 1155 | - * Build the signature that ties a gallery UID to the source and cache duration it was rendered | |
| 1156 | - * with. | |
| 1157 | - * | |
| 1158 | - * A gallery UID is printed into the page, so it is not a secret and cannot be trusted on its own. | |
| 1159 | - * What this protects is the *pairing*: a request may only ask for the source that was rendered | |
| 1160 | - * alongside that UID, at the cache duration that gallery was configured with. | |
| 1161 | - * | |
| 1162 | - * It exists because a UID cannot always be recomputed. ayg_build_gallery() derives it as | |
| 1163 | - * md5( type + source ), but a gallery can override that through the "uid" shortcode attribute or | |
| 1164 | - * the ayg_gallery_id filter, and neither is knowable from the request alone. Signing the whole set | |
| 1165 | - * at render time lets the public AJAX endpoint accept such galleries without also having to accept | |
| 1166 | - * whatever source — or cache duration — the caller claims goes with them. | |
| 1167 | - * | |
| 1168 | - * Including the cache duration is what lets the "Cache Duration" gallery option keep working | |
| 1169 | - * exactly as the site owner set it, right down to "No Caching", while still making it impossible | |
| 1170 | - * for a visitor to bypass the cache and force live API requests. | |
| 1171 | - * | |
| 1172 | - * Each part is length prefixed so that no two different sets of values can produce the same | |
| 1173 | - * string to sign. | |
| 1174 | - * | |
| 1175 | - * @since 2.9.0 | |
| 1176 | - * @param string $uid Gallery UID. | |
| 1177 | - * @param string $type Gallery source type. | |
| 1178 | - * @param string $src Gallery source value. | |
| 1179 | - * @param string|int $cache Gallery cache duration in seconds. | |
| 1180 | - * @return string Signature. | |
| 1181 | - */ | |
| 1182 | -function ayg_get_gallery_signature( $uid, $type, $src, $cache ) { | |
| 1183 | - $parts = array( (string) $uid, (string) $type, (string) $src, (string) (int) $cache ); | |
| 1184 | - $data = 'ayg_gallery'; | |
| 1185 | - | |
| 1186 | - foreach ( $parts as $part ) { | |
| 1187 | - $data .= '|' . strlen( $part ) . ':' . $part; | |
| 1188 | - } | |
| 1189 | - | |
| 1190 | - return substr( wp_hash( $data ), 0, 16 ); | |
| 1191 | -} | |
| 1192 | - | |
| 1193 | -/** | |
| 1194 | - * Resolve a saved gallery's source type and value. | |
| 1195 | - * | |
| 1196 | - * Livestream, search and single video galleries query the YouTube API at display time — nothing | |
| 1197 | - * is imported for them — so they keep their own source type. Everything else is served from the | |
| 1198 | - * custom tables through the internal "db" source type, keyed by the gallery ID. | |
| 1199 | - * | |
| 1200 | - * Both the renderer (ayg_build_gallery) and the public AJAX endpoint resolve a saved gallery's | |
| 1201 | - * source through this function, so an untrusted request can never point a gallery at a source | |
| 1202 | - * other than the one stored in its own row. | |
| 1203 | - * | |
| 1204 | - * @since 2.9.0 | |
| 1205 | - * @param object $gallery Gallery row from "{$wpdb->prefix}ayg_galleries". | |
| 1206 | - * @return array Source "type", the matching attribute name in "field", and the | |
| 1207 | - * source value in "src". | |
| 1208 | - */ | |
| 1209 | -function ayg_get_gallery_source( $gallery ) { | |
| 1210 | - $source_type = isset( $gallery->source_type ) ? $gallery->source_type : ''; | |
| 1211 | - $source_value = isset( $gallery->source_value ) ? $gallery->source_value : ''; | |
| 1212 | - | |
| 1213 | - if ( 'livestream' === $source_type ) { | |
| 1214 | - return array( | |
| 1215 | - 'type' => 'livestream', | |
| 1216 | - 'field' => 'channel', | |
| 1217 | - 'src' => $source_value | |
| 1218 | - ); | |
| 1219 | - } | |
| 1220 | - | |
| 1221 | - if ( 'search' === $source_type ) { | |
| 1222 | - return array( | |
| 1223 | - 'type' => 'search', | |
| 1224 | - 'field' => 'search', | |
| 1225 | - 'src' => $source_value | |
| 1226 | - ); | |
| 1227 | - } | |
| 1228 | - | |
| 1229 | - if ( 'video' === $source_type ) { | |
| 1230 | - return array( | |
| 1231 | - 'type' => 'video', | |
| 1232 | - 'field' => 'video', | |
| 1233 | - 'src' => $source_value | |
| 1234 | - ); | |
| 1235 | - } | |
| 1236 | - | |
| 1237 | - return array( | |
| 1238 | - 'type' => 'db', | |
| 1239 | - 'field' => 'db', | |
| 1240 | - 'src' => strval( $gallery->id ) | |
| 1241 | - ); | |
| 1242 | -} | |
| 1243 | - | |
| 1244 | -/** | |
| 1245 | - * Return the schedule interval options for import scheduling. | |
| 1246 | - * | |
| 1247 | - * @since 2.8.0 | |
| 1248 | - * @return array Value (seconds as string) => label pairs. | |
| 1249 | - */ | |
| 1250 | -function ayg_get_import_schedule_options() { | |
| 1251 | - return array( | |
| 1252 | - 'paused' => __( '— Pause Automatic Imports —', 'automatic-youtube-gallery' ), | |
| 1253 | - '0' => __( 'Only Once', 'automatic-youtube-gallery' ), | |
| 1254 | - '3600' => __( 'Every Hour', 'automatic-youtube-gallery' ), | |
| 1255 | - '86400' => __( 'Every Day', 'automatic-youtube-gallery' ), | |
| 1256 | - '604800' => __( 'Every Week', 'automatic-youtube-gallery' ), | |
| 1257 | - '2592000' => __( 'Every Month', 'automatic-youtube-gallery' ) | |
| 1258 | - ); | |
| 1259 | -} | |
| 1260 | - | |
| 1261 | -/** | |
| 1262 | - * Return the human-readable label for an import status key. | |
| 1263 | - * | |
| 1264 | - * @since 2.8.0 | |
| 1265 | - * @param string $status Import status key (idle, running, paused, error, completed). | |
| 1266 | - * @param int|null $video_count Optional. Imported video count, used to resolve the | |
| 1267 | - * ambiguous "idle" status into "Pending Import" (nothing | |
| 1268 | - * imported yet) or "Up to Date" (waiting for the next sync). | |
| 1269 | - * @param bool $resuming Optional. True when an import was capped mid-run and parked | |
| 1270 | - * as 'idle' for cron to resume — shown as "Importing", not idle. | |
| 1271 | - * @param string $context Optional. 'log' for a per-run history entry, where a successful | |
| 1272 | - * run (stored as 'idle' for recurring galleries) reads "Completed" | |
| 1273 | - * like non-recurring runs, instead of the live-state "Idle". | |
| 1274 | - * @return string | |
| 1275 | - */ | |
| 1276 | -function ayg_get_import_status_label( $status, $video_count = null, $resuming = false, $context = '' ) { | |
| 1277 | - if ( 'idle' === $status ) { | |
| 1278 | - // History rows record a finished run: a recurring gallery's success is stored as 'idle', | |
| 1279 | - // so surface it as "Completed" to match non-recurring runs rather than the live "Idle". | |
| 1280 | - if ( 'log' === $context ) { | |
| 1281 | - return __( 'Completed', 'automatic-youtube-gallery' ); | |
| 1282 | - } | |
| 1283 | - | |
| 1284 | - // If the import was capped mid-run and parked as 'idle' for cron to resume, show "Importing". | |
| 1285 | - if ( $resuming ) { | |
| 1286 | - return __( 'Importing', 'automatic-youtube-gallery' ); | |
| 1287 | - } | |
| 1288 | - | |
| 1289 | - // If the import has never run, show "Pending Import" instead of "Idle". | |
| 1290 | - if ( null !== $video_count ) { | |
| 1291 | - return ( (int) $video_count > 0 ) ? __( 'Up to Date', 'automatic-youtube-gallery' ) : __( 'Pending Import', 'automatic-youtube-gallery' ); | |
| 1292 | - } | |
| 1293 | - } | |
| 1294 | - | |
| 1295 | - $statuses = array( | |
| 1296 | - 'idle' => __( 'Idle', 'automatic-youtube-gallery' ), | |
| 1297 | - 'running' => __( 'Importing', 'automatic-youtube-gallery' ), | |
| 1298 | - 'paused' => __( 'Paused', 'automatic-youtube-gallery' ), | |
| 1299 | - 'error' => __( 'Error', 'automatic-youtube-gallery' ), | |
| 1300 | - 'completed' => __( 'Completed', 'automatic-youtube-gallery' ) | |
| 1301 | - ); | |
| 1302 | - | |
| 1303 | - return isset( $statuses[ $status ] ) ? $statuses[ $status ] : ucfirst( $status ); | |
| 1304 | -} | |
| 1305 | - | |
| 1306 | -/** | |
| 1307 | - * Retrieve a plugin option with fallback to default settings. | |
| 1308 | - * | |
| 1309 | - * @since 2.7.0 | |
| 1310 | - * @param string $option The option name to retrieve. | |
| 1311 | - * @return mixed | |
| 1312 | - */ | |
| 1313 | -function ayg_get_option( $option ) { | |
| 1314 | - $defaults = ayg_get_default_settings(); | |
| 1315 | - $default = isset( $defaults[ $option ] ) ? $defaults[ $option ] : array(); | |
| 1316 | - | |
| 1317 | - $saved = get_option( $option, null ); | |
| 1318 | - | |
| 1319 | - // Option does not exist OR corrupted | |
| 1320 | - if ( null === $saved || ! is_array( $saved ) ) { | |
| 1321 | - return $default; | |
| 1322 | - } | |
| 1323 | - | |
| 1324 | - // Merge saved values with defaults | |
| 1325 | - return wp_parse_args( $saved, $default ); | |
| 1326 | -} | |
| 1327 | - | |
| 1328 | -/** | |
| 1329 | - * Build the signature for a pagination token. | |
| 1330 | - * | |
| 1331 | - * Keyed on the site's own salts through wp_hash(), and bound to the gallery so a token issued for | |
| 1332 | - * one gallery cannot be replayed against another. Unlike a nonce this never expires, so tokens | |
| 1333 | - * printed into a page that is held by a full page cache keep working. | |
| 1334 | - * | |
| 1335 | - * @since 2.9.0 | |
| 1336 | - * @param string $token Raw page token. | |
| 1337 | - * @param string $uid Gallery UID the token belongs to. | |
| 1338 | - * @return string Signature. | |
| 1339 | - */ | |
| 1340 | -function ayg_get_page_token_signature( $token, $uid ) { | |
| 1341 | - return substr( wp_hash( 'ayg_page_token|' . (string) $uid . '|' . (string) $token ), 0, 16 ); | |
| 1342 | -} | |
| 1343 | - | |
| 1344 | -/** | |
| 1345 | 792 | * Get video description to show on top of the player. |
| 1346 | 793 | * |
| 1347 | 794 | * @since 1.0.0 |
| 1348 | 795 | * @param stdClass $video YouTube video object. |
| @@ -1374,9 +821,9 @@ | ||
| 1374 | 821 | * @since 1.0.0 |
| 1375 | 822 | * @return array $fields Array of fields. |
| 1376 | 823 | */ |
| 1377 | 824 | function ayg_get_player_settings_fields() { |
| 1378 | - $player_settings = ayg_get_option( 'ayg_player_settings' ); | |
| 825 | + $player_settings = get_option( 'ayg_player_settings' ); | |
| 1379 | 826 | |
| 1380 | 827 | $fields = array( |
| 1381 | 828 | array( |
| 1382 | 829 | 'name' => 'player_width', |
| @@ -1389,13 +836,12 @@ | ||
| 1389 | 836 | array( |
| 1390 | 837 | 'name' => 'player_ratio', |
| 1391 | 838 | 'label' => __( 'Player Height (Ratio)', 'automatic-youtube-gallery' ), |
| 1392 | 839 | 'description' => __( 'Select the ratio value used to calculate the player height.', 'automatic-youtube-gallery' ), |
| 1393 | - 'type' => 'select', | |
| 840 | + 'type' => 'radio', | |
| 1394 | 841 | 'options' => array( |
| 1395 | - '56.25' => __( 'Standard (16:9) — Default', 'automatic-youtube-gallery' ), | |
| 1396 | - '177.78' => __( 'Shorts / Vertical (9:16)', 'automatic-youtube-gallery' ), | |
| 1397 | - '75' => __( 'Classic (4:3)', 'automatic-youtube-gallery' ) | |
| 842 | + '56.25' => '16:9', | |
| 843 | + '75' => '4:3' | |
| 1398 | 844 | ), |
| 1399 | 845 | 'value' => $player_settings['player_ratio'], |
| 1400 | 846 | 'sanitize_callback' => 'floatval' |
| 1401 | 847 | ), |
| @@ -1417,9 +863,9 @@ | ||
| 1417 | 863 | ), |
| 1418 | 864 | array( |
| 1419 | 865 | 'name' => 'autoplay', |
| 1420 | 866 | 'label' => __( 'Autoplay', 'automatic-youtube-gallery' ), |
| 1421 | - 'description' => __( 'Check this option to automatically start playing the initial video when the player loads.', 'automatic-youtube-gallery' ), | |
| 867 | + 'description' => __( 'Specifies whether the initial video will automatically start to play when the player loads.', 'automatic-youtube-gallery' ), | |
| 1422 | 868 | 'type' => 'checkbox', |
| 1423 | 869 | 'value' => $player_settings['autoplay'], |
| 1424 | 870 | 'sanitize_callback' => 'intval' |
| 1425 | 871 | ), |
| @@ -1425,9 +871,9 @@ | ||
| 1425 | 871 | ), |
| 1426 | 872 | array( |
| 1427 | 873 | 'name' => 'autoadvance', |
| 1428 | 874 | 'label' => __( 'Autoplay Next Video', 'automatic-youtube-gallery' ), |
| 1429 | - 'description' => __( 'Check this option to automatically play the next video in the list after the previous one ends.', 'automatic-youtube-gallery' ), | |
| 875 | + 'description' => __( 'Specifies whether to play the next video in the list automatically after previous one end.', 'automatic-youtube-gallery' ), | |
| 1430 | 876 | 'type' => 'checkbox', |
| 1431 | 877 | 'value' => $player_settings['autoadvance'], |
| 1432 | 878 | 'sanitize_callback' => 'intval' |
| 1433 | 879 | ), |
| @@ -1433,9 +879,9 @@ | ||
| 1433 | 879 | ), |
| 1434 | 880 | array( |
| 1435 | 881 | 'name' => 'loop', |
| 1436 | 882 | 'label' => __( 'Loop', 'automatic-youtube-gallery' ), |
| 1437 | - 'description' => __( 'Check this option to loop playback. 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 and then starts again at the first video.', 'automatic-youtube-gallery' ), | |
| 883 | + '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' ), | |
| 1438 | 884 | 'type' => 'checkbox', |
| 1439 | 885 | 'value' => $player_settings['loop'], |
| 1440 | 886 | 'sanitize_callback' => 'intval' |
| 1441 | 887 | ), |
| @@ -1457,9 +903,9 @@ | ||
| 1457 | 903 | ), |
| 1458 | 904 | array( |
| 1459 | 905 | 'name' => 'modestbranding', |
| 1460 | 906 | 'label' => __( 'Hide YouTube Logo', 'automatic-youtube-gallery' ), |
| 1461 | - 'description' => __( "Check this option to 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' ), | |
| 907 | + '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' ), | |
| 1462 | 908 | 'type' => 'checkbox', |
| 1463 | 909 | 'value' => $player_settings['modestbranding'], |
| 1464 | 910 | 'sanitize_callback' => 'intval' |
| 1465 | 911 | ), |
| @@ -1465,12 +911,20 @@ | ||
| 1465 | 911 | ), |
| 1466 | 912 | array( |
| 1467 | 913 | 'name' => 'cc_load_policy', |
| 1468 | 914 | 'label' => __( 'Force Closed Captions', 'automatic-youtube-gallery' ), |
| 1469 | - 'description' => __( 'Check this option to show captions by default, even if the user has turned captions off. The default behavior is based on user preference.', 'automatic-youtube-gallery' ), | |
| 915 | + 'description' => __( 'Show captions by default, even if the user has turned captions off. The default behavior is based on user preference.', 'automatic-youtube-gallery' ), | |
| 1470 | 916 | 'type' => 'checkbox', |
| 1471 | 917 | 'value' => $player_settings['cc_load_policy'], |
| 1472 | 918 | 'sanitize_callback' => 'intval' |
| 919 | + ), | |
| 920 | + array( | |
| 921 | + 'name' => 'iv_load_policy', | |
| 922 | + 'label' => __( 'Show Annotations', 'automatic-youtube-gallery' ), | |
| 923 | + 'description' => __( 'Choose whether to show annotations or not.', 'automatic-youtube-gallery' ), | |
| 924 | + 'type' => 'checkbox', | |
| 925 | + 'value' => $player_settings['iv_load_policy'], | |
| 926 | + 'sanitize_callback' => 'intval' | |
| 1473 | 927 | ), |
| 1474 | 928 | array( |
| 1475 | 929 | 'name' => 'hl', |
| 1476 | 930 | 'label' => __( 'Player Language', 'automatic-youtube-gallery' ), |
| @@ -1511,38 +965,8 @@ | ||
| 1511 | 965 | return apply_filters( 'ayg_single_video_url', '', $video, $attributes ); |
| 1512 | 966 | } |
| 1513 | 967 | |
| 1514 | 968 | /** |
| 1515 | - * Return the human-readable label for a source type key. | |
| 1516 | - * | |
| 1517 | - * @since 2.8.0 | |
| 1518 | - * @param string $type Source type key (channel, playlist, username, search, livestream, video, videos). | |
| 1519 | - * @return string | |
| 1520 | - */ | |
| 1521 | -function ayg_get_source_type_label( $type ) { | |
| 1522 | - $types = ayg_get_source_types(); | |
| 1523 | - return isset( $types[ $type ] ) ? $types[ $type ] : ucfirst( $type ); | |
| 1524 | -} | |
| 1525 | - | |
| 1526 | -/** | |
| 1527 | - * Get source types. | |
| 1528 | - * | |
| 1529 | - * @since 2.8.0 | |
| 1530 | - * @return array | |
| 1531 | - */ | |
| 1532 | -function ayg_get_source_types() { | |
| 1533 | - return array( | |
| 1534 | - 'channel' => __( 'Channel', 'automatic-youtube-gallery' ), | |
| 1535 | - 'playlist' => __( 'Playlist', 'automatic-youtube-gallery' ), | |
| 1536 | - 'username' => __( 'Username', 'automatic-youtube-gallery' ), | |
| 1537 | - 'search' => __( 'Search Keywords', 'automatic-youtube-gallery' ), | |
| 1538 | - 'livestream' => __( 'Livestream', 'automatic-youtube-gallery' ), | |
| 1539 | - 'video' => __( 'Single Video', 'automatic-youtube-gallery' ), | |
| 1540 | - 'videos' => __( 'Custom Videos List', 'automatic-youtube-gallery' ) | |
| 1541 | - ); | |
| 1542 | -} | |
| 1543 | - | |
| 1544 | -/** | |
| 1545 | 969 | * Get filtered php template file path. |
| 1546 | 970 | * |
| 1547 | 971 | * @since 1.0.0 |
| 1548 | 972 | * @param array $template PHP file path. |
| @@ -1575,9 +999,9 @@ | ||
| 1575 | 999 | * @since 2.3.0 |
| 1576 | 1000 | * @return string YouTube embed domain. |
| 1577 | 1001 | */ |
| 1578 | 1002 | function ayg_get_youtube_domain() { |
| 1579 | - $player_settings = ayg_get_option( 'ayg_player_settings' ); | |
| 1003 | + $player_settings = get_option( 'ayg_player_settings' ); | |
| 1580 | 1004 | |
| 1581 | 1005 | $domain = 'https://www.youtube.com'; |
| 1582 | 1006 | if ( isset( $player_settings['privacy_enhanced_mode'] ) && ! empty( $player_settings['privacy_enhanced_mode'] ) ) { |
| 1583 | 1007 | $domain = 'https://www.youtube-nocookie.com'; |
| @@ -1594,9 +1018,9 @@ | ||
| 1594 | 1018 | * @param array $attributes Array of user attributes. |
| 1595 | 1019 | * @return string Player embed URL. |
| 1596 | 1020 | */ |
| 1597 | 1021 | function ayg_get_youtube_embed_url( $video_id, $attributes = array() ) { |
| 1598 | - $player_settings = ayg_get_option( 'ayg_player_settings' ); | |
| 1022 | + $player_settings = get_option( 'ayg_player_settings' ); | |
| 1599 | 1023 | |
| 1600 | 1024 | $player_website = 'https://www.youtube.com'; |
| 1601 | 1025 | if ( isset( $player_settings['privacy_enhanced_mode'] ) && ! empty( $player_settings['privacy_enhanced_mode'] ) ) { |
| 1602 | 1026 | $player_website = 'https://www.youtube-nocookie.com'; |
| @@ -1649,8 +1073,13 @@ | ||
| 1649 | 1073 | if ( 1 == $cc_load_policy ) { |
| 1650 | 1074 | $url = add_query_arg( 'cc_load_policy', 1, $url ); |
| 1651 | 1075 | } |
| 1652 | 1076 | |
| 1077 | + $iv_load_policy = isset( $attributes['iv_load_policy'] ) ? (int) $attributes['iv_load_policy'] : 0; | |
| 1078 | + if ( 0 == $iv_load_policy ) { | |
| 1079 | + $url = add_query_arg( 'iv_load_policy', 3, $url ); | |
| 1080 | + } | |
| 1081 | + | |
| 1653 | 1082 | if ( isset( $attributes['hl'] ) && ! empty( $attributes['hl'] ) ) { |
| 1654 | 1083 | $url = add_query_arg( 'hl', sanitize_text_field( $attributes['hl'] ), $url ); |
| 1655 | 1084 | } |
| 1656 | 1085 | |
| @@ -1661,35 +1090,8 @@ | ||
| 1661 | 1090 | return apply_filters( 'ayg_youtube_embed_url', $url, $video_id, $attributes ); |
| 1662 | 1091 | } |
| 1663 | 1092 | |
| 1664 | 1093 | /** |
| 1665 | - * Resolve a YouTube video ID from a bare ID or a YouTube URL. | |
| 1666 | - * | |
| 1667 | - * @since 2.8.0 | |
| 1668 | - * @param string $string A video ID or YouTube URL. | |
| 1669 | - * @return string The 11-char video ID, or '' if none found. | |
| 1670 | - */ | |
| 1671 | -function ayg_get_youtube_video_id( $string ) { | |
| 1672 | - $string = trim( (string) $string ); | |
| 1673 | - | |
| 1674 | - if ( '' === $string ) { | |
| 1675 | - return ''; | |
| 1676 | - } | |
| 1677 | - | |
| 1678 | - // Already a bare video ID. | |
| 1679 | - if ( preg_match( '~^[A-Za-z0-9_-]{11}$~', $string ) ) { | |
| 1680 | - return $string; | |
| 1681 | - } | |
| 1682 | - | |
| 1683 | - // Common YouTube URL forms. | |
| 1684 | - if ( preg_match( '~(?:v=|/(?:embed|v|shorts|live)/|youtu\.be/)([A-Za-z0-9_-]{11})~', $string, $matches ) ) { | |
| 1685 | - return $matches[1]; | |
| 1686 | - } | |
| 1687 | - | |
| 1688 | - return ''; | |
| 1689 | -} | |
| 1690 | - | |
| 1691 | -/** | |
| 1692 | 1094 | * Inserts a new associative array after another associative array key. |
| 1693 | 1095 | * |
| 1694 | 1096 | * @since 2.1.0 |
| 1695 | 1097 | * @param string $key The associative array key to insert after. |
| @@ -1740,118 +1142,8 @@ | ||
| 1740 | 1142 | return false; |
| 1741 | 1143 | } |
| 1742 | 1144 | |
| 1743 | 1145 | /** |
| 1744 | - * Check whether a video ID matches a gallery's exclude list. | |
| 1745 | - * | |
| 1746 | - * @since 2.8.0 | |
| 1747 | - * @param string $video_id YouTube video ID. | |
| 1748 | - * @param array $exclude Exclude entries (video IDs or URLs). | |
| 1749 | - * @return bool True if the video is excluded. | |
| 1750 | - */ | |
| 1751 | -function ayg_is_video_excluded( $video_id, $exclude ) { | |
| 1752 | - if ( empty( $video_id ) || empty( $exclude ) || ! is_array( $exclude ) ) { | |
| 1753 | - return false; | |
| 1754 | - } | |
| 1755 | - | |
| 1756 | - foreach ( $exclude as $entry ) { | |
| 1757 | - if ( false !== strpos( $entry, $video_id ) ) { | |
| 1758 | - return true; | |
| 1759 | - } | |
| 1760 | - } | |
| 1761 | - | |
| 1762 | - return false; | |
| 1763 | -} | |
| 1764 | - | |
| 1765 | -/** | |
| 1766 | - * Unserialize a stored value without letting it instantiate arbitrary classes. | |
| 1767 | - * | |
| 1768 | - * Our serialized columns only ever hold the thumbnail set from an API response — plain data plus | |
| 1769 | - * stdClass objects — so nothing else is allowed through. This keeps a row that was tampered with | |
| 1770 | - * or carried over from another install from building an object of some other class. | |
| 1771 | - * | |
| 1772 | - * @since 2.9.0 | |
| 1773 | - * @param string $value Serialized value. | |
| 1774 | - * @return mixed Unserialized value, or the value unchanged when it isn't serialized. | |
| 1775 | - */ | |
| 1776 | -function ayg_maybe_unserialize( $value ) { | |
| 1777 | - if ( ! is_serialized( $value ) ) { | |
| 1778 | - return $value; | |
| 1779 | - } | |
| 1780 | - | |
| 1781 | - // is_serialized() trims the value before testing it, so trim here as well — otherwise a padded | |
| 1782 | - // value passes the test and then fails to unserialize. Mirrors core's maybe_unserialize(). | |
| 1783 | - $value = trim( $value ); | |
| 1784 | - | |
| 1785 | - // PHP 7.0+ can restrict this natively. | |
| 1786 | - if ( version_compare( PHP_VERSION, '7.0', '>=' ) ) { | |
| 1787 | - return @unserialize( $value, array( 'allowed_classes' => array( 'stdClass' ) ) ); | |
| 1788 | - } | |
| 1789 | - | |
| 1790 | - // PHP 5.6 has no "allowed_classes" option, so screen the payload instead: "O:" introduces a | |
| 1791 | - // plain object and "C:" a Serializable one, so refuse the value outright if it names any class | |
| 1792 | - // other than stdClass. Same protection as the call above, without raising the minimum PHP | |
| 1793 | - // version and cutting those sites off from plugin updates. | |
| 1794 | - if ( preg_match_all( '/(?:^|[;{])([OC]):\d+:"([^"]*)"/', $value, $matches, PREG_SET_ORDER ) ) { | |
| 1795 | - foreach ( $matches as $match ) { | |
| 1796 | - if ( 'O' !== $match[1] || 'stdClass' !== $match[2] ) { | |
| 1797 | - return false; | |
| 1798 | - } | |
| 1799 | - } | |
| 1800 | - } | |
| 1801 | - | |
| 1802 | - return @unserialize( $value ); | |
| 1803 | -} | |
| 1804 | - | |
| 1805 | -/** | |
| 1806 | - * Does this source type hand out signed pagination tokens? | |
| 1807 | - * | |
| 1808 | - * Only the sources that page through the live YouTube API do, because for those every distinct | |
| 1809 | - * page token means another API call. The rest either never reach the API at all (the Gallery | |
| 1810 | - * Builder "db" source) or page through a list already known to the site ("videos"), where the | |
| 1811 | - * page number is simply clamped to the real range and so cannot force extra calls. | |
| 1812 | - * | |
| 1813 | - * @since 2.9.0 | |
| 1814 | - * @param string $source_type Gallery source type. | |
| 1815 | - * @return bool True when tokens of this source type are signed. | |
| 1816 | - */ | |
| 1817 | -function ayg_page_token_is_signed( $source_type ) { | |
| 1818 | - return in_array( $source_type, array( 'playlist', 'channel', 'username', 'search' ), true ); | |
| 1819 | -} | |
| 1820 | - | |
| 1821 | -/** | |
| 1822 | - * Parse an ISO 8601 duration (e.g. PT4M13S) into total seconds. | |
| 1823 | - * | |
| 1824 | - * @since 2.8.0 | |
| 1825 | - * @param string $iso8601 ISO 8601 duration string from the YouTube API. | |
| 1826 | - * @return int Duration in seconds. | |
| 1827 | - */ | |
| 1828 | -function ayg_parse_duration_seconds( $iso8601 ) { | |
| 1829 | - if ( empty( $iso8601 ) ) { | |
| 1830 | - return 0; | |
| 1831 | - } | |
| 1832 | - | |
| 1833 | - try { | |
| 1834 | - $interval = new DateInterval( $iso8601 ); | |
| 1835 | - } catch ( Exception $e ) { | |
| 1836 | - return 0; | |
| 1837 | - } | |
| 1838 | - | |
| 1839 | - return ( $interval->d * DAY_IN_SECONDS ) + ( $interval->h * HOUR_IN_SECONDS ) + ( $interval->i * MINUTE_IN_SECONDS ) + $interval->s; | |
| 1840 | -} | |
| 1841 | - | |
| 1842 | -/** | |
| 1843 | - * Sanitize the array inputs. | |
| 1844 | - * | |
| 1845 | - * @since 2.7.0 | |
| 1846 | - * @param array $value Input array. | |
| 1847 | - * @return array Sanitized array. | |
| 1848 | - */ | |
| 1849 | -function ayg_sanitize_array( $value ) { | |
| 1850 | - return ! empty( $value ) ? array_map( 'sanitize_text_field', $value ) : array(); | |
| 1851 | -} | |
| 1852 | - | |
| 1853 | -/** | |
| 1854 | 1146 | * Sanitize the integer inputs, accepts empty values. |
| 1855 | 1147 | * |
| 1856 | 1148 | * @since 1.0.0 |
| 1857 | 1149 | * @param string|int $value Input value. |
| @@ -1862,49 +1154,8 @@ | ||
| 1862 | 1154 | return ( 0 == $value ) ? '' : $value; |
| 1863 | 1155 | } |
| 1864 | 1156 | |
| 1865 | 1157 | /** |
| 1866 | - * Sign a pagination token before it is handed to the browser. | |
| 1867 | - * | |
| 1868 | - * Page tokens travel out to the visitor and are posted back to the public AJAX endpoint, where | |
| 1869 | - * each distinct token means another live call to the YouTube Data API. Signing them means only | |
| 1870 | - * the tokens this site actually issued are ever acted on, so a visitor cannot invent an endless | |
| 1871 | - * stream of new ones and burn through the site's daily API quota. | |
| 1872 | - * | |
| 1873 | - * @since 2.9.0 | |
| 1874 | - * @param string $token Raw page token from the API response. | |
| 1875 | - * @param string $uid Gallery UID the token belongs to. | |
| 1876 | - * @return string Signed token, or an empty string when there is no token. | |
| 1877 | - */ | |
| 1878 | -function ayg_sign_page_token( $token, $uid ) { | |
| 1879 | - $token = (string) $token; | |
| 1880 | - | |
| 1881 | - if ( '' === $token ) { | |
| 1882 | - return ''; | |
| 1883 | - } | |
| 1884 | - | |
| 1885 | - return $token . '.' . ayg_get_page_token_signature( $token, $uid ); | |
| 1886 | -} | |
| 1887 | - | |
| 1888 | -/** | |
| 1889 | - * Sign the pagination tokens in a page info array. | |
| 1890 | - * | |
| 1891 | - * @since 2.9.0 | |
| 1892 | - * @param array $page_info Page info array from the API response. | |
| 1893 | - * @param string $uid Gallery UID the tokens belong to. | |
| 1894 | - * @return array The same array with its tokens signed. | |
| 1895 | - */ | |
| 1896 | -function ayg_sign_page_tokens( $page_info, $uid ) { | |
| 1897 | - foreach ( array( 'next_page_token', 'prev_page_token' ) as $key ) { | |
| 1898 | - if ( ! empty( $page_info[ $key ] ) ) { | |
| 1899 | - $page_info[ $key ] = ayg_sign_page_token( $page_info[ $key ], $uid ); | |
| 1900 | - } | |
| 1901 | - } | |
| 1902 | - | |
| 1903 | - return $page_info; | |
| 1904 | -} | |
| 1905 | - | |
| 1906 | -/** | |
| 1907 | 1158 | * Trims text to a certain number of characters. |
| 1908 | 1159 | * |
| 1909 | 1160 | * @since 2.0.0 |
| 1910 | 1161 | * @param string $text Text to trim. |
| @@ -1931,43 +1182,9 @@ | ||
| 1931 | 1182 | |
| 1932 | 1183 | $text .= $append; |
| 1933 | 1184 | } |
| 1934 | 1185 | |
| 1935 | - return apply_filters( 'ayg_trim_words', $text, $original_text, $num_characters, $append ); | |
| 1936 | -} | |
| 1937 | - | |
| 1938 | -/** | |
| 1939 | - * Verify a pagination token that came back from the browser. | |
| 1940 | - * | |
| 1941 | - * @since 2.9.0 | |
| 1942 | - * @param string $token Signed token as posted by the browser. | |
| 1943 | - * @param string $uid Gallery UID the token is claimed to belong to. | |
| 1944 | - * @return string|false The raw token when the signature matches, false when it does not. An | |
| 1945 | - * empty token is the first page and needs no signature. | |
| 1946 | - */ | |
| 1947 | -function ayg_verify_page_token( $token, $uid ) { | |
| 1948 | - $token = (string) $token; | |
| 1949 | - | |
| 1950 | - if ( '' === $token ) { | |
| 1951 | - return ''; | |
| 1952 | - } | |
| 1953 | - | |
| 1954 | - // The signature is appended last, and a YouTube page token can itself contain almost anything, | |
| 1955 | - // so split on the final separator rather than the first. | |
| 1956 | - $position = strrpos( $token, '.' ); | |
| 1957 | - | |
| 1958 | - if ( false === $position ) { | |
| 1959 | - return false; | |
| 1960 | - } | |
| 1961 | - | |
| 1962 | - $raw = substr( $token, 0, $position ); | |
| 1963 | - $signature = substr( $token, $position + 1 ); | |
| 1964 | - | |
| 1965 | - if ( '' === $raw || ! hash_equals( ayg_get_page_token_signature( $raw, $uid ), $signature ) ) { | |
| 1966 | - return false; | |
| 1967 | - } | |
| 1968 | - | |
| 1969 | - return $raw; | |
| 1186 | + return apply_filters( 'ayg_trim_words', $text, $original_text, $num_characters, $append ); | |
| 1970 | 1187 | } |
| 1971 | 1188 | |
| 1972 | 1189 | /** |
| 1973 | 1190 | * Gallery HTML output. |