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

gallery-form.php in Automatic YouTube Gallery – Embed Auto-Updating YouTube Video Galleries, Feeds, Playlists & Channels trunk, at admin/templates/gallery-form.php

498 lines 25.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Gallery Form (add / edit).
5 *
6 * @link https://plugins360.com
7 * @since 2.8.0
8 *
9 * @package Automatic_YouTube_Gallery
10 */
11
12 // Exit if accessed directly
13 if ( ! defined( 'WPINC' ) ) {
14 die;
15 }
16
17 $action = isset( $_GET['action'] ) ? sanitize_text_field( $_GET['action'] ) : '';
18 $gallery_id = ( 'edit' === $action ) ? absint( isset( $_GET['id'] ) ? $_GET['id'] : 0 ) : 0;
19 $source_value_fields = array( 'channel', 'playlist', 'username', 'search', 'video', 'videos' );
20 $no_schedule_types = array( 'search', 'livestream', 'video', 'videos' );
21 $live_types = array( 'search', 'livestream', 'video' ); // Rendered live at display time — nothing is imported/stored.
22 $date_format = get_option( 'date_format' ) . ' ' . get_option( 'time_format' );
23 $is_new = ( 0 === $gallery_id ) ? true : false;
24
25 // Get the editor fields.
26 $fields = ayg_get_editor_fields();
27 $excluded = array();
28
29 foreach ( $fields as $key => $section ) {
30 foreach ( $section['fields'] as $index => $field ) {
31 // Exclude certain fields from the form
32 if ( in_array( $field['name'], $excluded, true ) ) {
33 unset( $fields[ $key ]['fields'][ $index ] );
34 continue;
35 }
36
37 // Add the exclude + schedule fields to the end of the source section.
38 if ( 'order' === $field['name'] ) {
39 $fields[ $key ]['fields'][] = array(
40 'name' => 'exclude',
41 'label' => __( 'Exclude Videos', 'automatic-youtube-gallery' ),
42 'description' => __( 'Enter the video IDs or URLs you want to exclude, one per line. These videos will never be imported into this gallery.', 'automatic-youtube-gallery' ),
43 'type' => 'textarea',
44 'placeholder' => __( 'Enter one video ID or URL per line', 'automatic-youtube-gallery' ),
45 'value' => '',
46 'sanitize_callback' => 'sanitize_textarea_field'
47 );
48
49 $fields[ $key ]['fields'][] = array(
50 'name' => 'schedule',
51 'label' => __( 'Import Schedule', 'automatic-youtube-gallery' ),
52 'description' => __( 'How often we automatically check your YouTube source for new videos and import them in the background. Choose "Pause Automatic Imports" to stop these background imports — you can still import on demand by saving the gallery.', 'automatic-youtube-gallery' ),
53 'type' => 'select',
54 'options' => ayg_get_import_schedule_options(),
55 'value' => 86400,
56 'sanitize_callback' => 'absint'
57 );
58 }
59
60 // Add the sort and duration filter fields to the gallery section.
61 if ( 'gallery' === $key && 'per_page' === $field['name'] ) {
62 // Builder galleries render from our own table, so "Videos per Page" can go beyond the
63 // 50-video API cap here — 0 shows all videos on one page. (The shared field keeps its 50
64 // limit elsewhere, e.g. the global settings page.)
65 $fields[ $key ]['fields'][ $index ]['description'] = __( 'Enter the number of videos to show per page, or 0 to show all videos on a single page.', 'automatic-youtube-gallery' );
66 unset( $fields[ $key ]['fields'][ $index ]['max'] );
67
68 // Add the display-time sort fields right after the per_page field in the gallery section.
69 array_splice( $fields[ $key ]['fields'], $index + 1, 0, array(
70 array(
71 'name' => 'sort_by',
72 'label' => __( 'Order Videos By', 'automatic-youtube-gallery' ),
73 'description' => __( 'Select how imported videos are ordered in this gallery.', 'automatic-youtube-gallery' ),
74 'type' => 'select',
75 'options' => array(
76 'date' => __( 'Published Date', 'automatic-youtube-gallery' ),
77 'title' => __( 'Title', 'automatic-youtube-gallery' ),
78 'duration' => __( 'Duration', 'automatic-youtube-gallery' ),
79 'random' => __( 'Random', 'automatic-youtube-gallery' )
80 ),
81 'value' => 'date',
82 'sanitize_callback' => 'sanitize_key'
83 ),
84 array(
85 'name' => 'sort_order',
86 'label' => __( 'Order', 'automatic-youtube-gallery' ),
87 'description' => __( 'Descending shows newest, Z–A or longest first. Ascending shows oldest, A–Z or shortest first.', 'automatic-youtube-gallery' ),
88 'type' => 'select',
89 'options' => array(
90 'desc' => __( 'Descending', 'automatic-youtube-gallery' ),
91 'asc' => __( 'Ascending', 'automatic-youtube-gallery' )
92 ),
93 'value' => 'desc',
94 'sanitize_callback' => 'sanitize_key'
95 ),
96 array(
97 'name' => 'duration_filter',
98 'label' => __( 'Filter by Duration', 'automatic-youtube-gallery' ),
99 'description' => __( 'Show only videos longer or shorter than the duration below — handy for including or excluding Shorts.', 'automatic-youtube-gallery' ),
100 'type' => 'select',
101 'options' => array(
102 '' => '' . __( 'No Filter', 'automatic-youtube-gallery' ) . '',
103 'long' => __( 'Longer Than', 'automatic-youtube-gallery' ),
104 'short' => __( 'Shorter Than', 'automatic-youtube-gallery' )
105 ),
106 'value' => '',
107 'sanitize_callback' => 'sanitize_key'
108 ),
109 array(
110 'name' => 'duration',
111 'label' => __( 'Duration (Seconds)', 'automatic-youtube-gallery' ),
112 'description' => __( 'The duration threshold in seconds for the filter above. Shorts are typically up to 60 seconds long, so enter 60 to include or exclude Shorts. Has no effect when the filter is set to "No Filter".', 'automatic-youtube-gallery' ),
113 'type' => 'text',
114 'value' => '',
115 'sanitize_callback' => 'ayg_sanitize_int'
116 )
117 ) );
118 }
119
120 // Add a description to the search form field in the search section.
121 if ( 'search' === $key && 'search_form' === $field['name'] ) {
122 $fields[ $key ]['fields'][ $index ]['description'] = __( 'Check this option to enable the search form.', 'automatic-youtube-gallery' );
123 }
124 }
125 }
126
127 // Load gallery config when editing
128 $form_data = array(
129 'id' => $gallery_id,
130 'title' => '',
131 'type' => 'playlist',
132 'theme' => 'classic',
133 'import_status' => 'idle',
134 'import_error' => '',
135 'import_log' => '',
136 'last_imported_at' => '',
137 'next_import_at' => '',
138 'video_count' => 0,
139 'schedule' => 86400
140 );
141
142 if ( $gallery_id > 0 ) {
143 $gallery = ayg_get_gallery( $gallery_id );
144
145 if ( ! $gallery ) {
146 ?>
147 <div class="ayg-notice ayg-notice-error">
148 <span class="dashicons dashicons-dismiss" aria-hidden="true"></span>
149 <?php esc_html_e( 'Gallery not found.', 'automatic-youtube-gallery' ); ?>
150 </div>
151 <?php
152 return;
153 }
154
155 // Override default values with saved gallery data
156 $form_data['title'] = $gallery->title;
157 $form_data['import_status'] = $gallery->import_status;
158 $form_data['import_error'] = $gallery->import_error;
159 $form_data['import_log'] = $gallery->import_log;
160 $form_data['last_imported_at'] = $gallery->last_imported_at;
161 $form_data['next_import_at'] = $gallery->next_import_at;
162 $form_data['video_count'] = absint( $gallery->video_count );
163
164 $allowed_source_types = ayg_get_source_types();
165 $source_type = array_key_exists( $gallery->source_type, $allowed_source_types ) ? $gallery->source_type : 'playlist';
166 $form_data['type'] = $source_type;
167
168 if ( 'livestream' === $source_type ) {
169 $form_data['channel'] = $gallery->source_value;
170 } else {
171 $form_data[ $source_type ] = $gallery->source_value;
172 }
173
174 if ( ! empty( $gallery->params ) ) {
175 $params = json_decode( $gallery->params, true ) ?: array();
176 $form_data = array_merge( $form_data, $params );
177 }
178 }
179
180 // The source locks only once videos have been imported. Until then it stays editable
181 // so a bad source (e.g. a failed first import) can be corrected without recreating.
182 // Live types (search / livestream / single video) never import, so their source never locks.
183 $source_locked = ( ! $is_new && $form_data['video_count'] > 0 && ! in_array( $form_data['type'], $live_types, true ) );
184 ?>
185 <div id="ayg-gallery-form" class="ayg-gallery-form">
186 <div class="ayg-back-to-galleries-link">
187 <a href="<?php echo esc_url( admin_url( 'admin.php?page=automatic-youtube-gallery' ) ); ?>">
188 <?php esc_html_e( '← Back to Galleries', 'automatic-youtube-gallery' ); ?>
189 </a>
190 </div>
191
192 <?php if ( $is_new ) : ?>
193 <h1 class="ayg-gallery-form-heading"><?php esc_html_e( 'Add New Gallery', 'automatic-youtube-gallery' ); ?></h1>
194 <?php else : ?>
195 <h1 class="ayg-gallery-form-heading">
196 <?php esc_html_e( 'Edit Gallery', 'automatic-youtube-gallery' ); ?>&nbsp;
197 <a href="<?php echo esc_url( admin_url( 'admin.php?page=automatic-youtube-gallery&action=new' ) ); ?>" class="ayg-button button button-small">
198 <?php esc_html_e( 'Add New Gallery', 'automatic-youtube-gallery' ); ?>
199 </a>
200 </h1>
201
202 <?php if ( isset( $_GET['saved'] ) ) : ?>
203 <div class="ayg-notice ayg-notice-success">
204 <span class="dashicons dashicons-yes-alt" aria-hidden="true"></span>
205 <?php esc_html_e( 'Gallery created successfully.', 'automatic-youtube-gallery' ); ?>
206 </div>
207 <?php elseif ( isset( $_GET['updated'] ) ) : ?>
208 <div class="ayg-notice ayg-notice-success">
209 <span class="dashicons dashicons-yes-alt" aria-hidden="true"></span>
210 <?php esc_html_e( 'Gallery updated successfully.', 'automatic-youtube-gallery' ); ?>
211 </div>
212 <?php endif; ?>
213
214 <?php if ( ! empty( $form_data['import_error'] ) ) : ?>
215 <div class="ayg-notice ayg-notice-error">
216 <span class="dashicons dashicons-dismiss" aria-hidden="true"></span>
217 <strong><?php esc_html_e( 'Import Error', 'automatic-youtube-gallery' ); ?>:</strong> <?php echo esc_html( $form_data['import_error'] ); ?>
218 </div>
219 <?php elseif ( 'running' === $form_data['import_status'] ) : ?>
220 <div class="ayg-notice ayg-notice-info">
221 <span class="dashicons dashicons-update" aria-hidden="true"></span>
222 <?php esc_html_e( 'An import is in progress for this gallery. It continues automatically in the background and may take a few minutes for large channels. Refresh this page to check the latest status.', 'automatic-youtube-gallery' ); ?>
223 </div>
224 <?php endif; ?>
225
226 <?php $shortcode = sprintf( '[automatic_youtube_gallery id="%d"]', $gallery_id ); ?>
227 <div class="ayg-notice ayg-notice-info ayg-notice-shortcode">
228 <div class="ayg-notice-shortcode-text">
229 <span>
230 <span class="dashicons dashicons-awards" aria-hidden="true"></span>
231 <?php esc_html_e( 'Your gallery is ready! Copy the shortcode below and paste it into any post, page, or widget to display it.', 'automatic-youtube-gallery' ); ?>
232 </span>
233 <code><?php echo esc_html( $shortcode ); ?></code>
234 </div>
235 <button type="button" class="ayg-button ayg-button-copy-shortcode button" data-clipboard-text="<?php echo esc_attr( $shortcode ); ?>">
236 <?php esc_html_e( 'Copy Shortcode', 'automatic-youtube-gallery' ); ?>
237 </button>
238 </div>
239
240 <?php
241 // KPI cards show for imported source types only. Live types (search / livestream / single
242 // video) store nothing, so they're excluded. 'videos' (multiple) keeps the cards since the
243 // imported count is useful.
244 if ( ! in_array( $form_data['type'], $live_types, true ) ) :
245 ?>
246 <div class="ayg-kpi-cards">
247 <div class="ayg-card ayg-card-kpi">
248 <span class="ayg-kpi-icon dashicons dashicons-dashboard" aria-hidden="true"></span>
249 <div class="ayg-kpi-body">
250 <?php $import_status_label = ayg_get_import_status_label( $form_data['import_status'], $form_data['video_count'], ! empty( $form_data['page_token'] ) ); ?>
251 <span class="ayg-badge ayg-badge-<?php echo esc_attr( $form_data['import_status'] ); ?>"><?php echo esc_html( $import_status_label ); ?></span>
252 <span class="ayg-kpi-label"><?php esc_html_e( 'Status', 'automatic-youtube-gallery' ); ?></span>
253 </div>
254 </div>
255
256 <div class="ayg-card ayg-card-kpi">
257 <span class="ayg-kpi-icon dashicons dashicons-editor-video" aria-hidden="true"></span>
258 <div class="ayg-kpi-body">
259 <strong class="ayg-kpi-value"><?php echo number_format_i18n( $form_data['video_count'] ); ?></strong>
260 <span class="ayg-kpi-label"><?php esc_html_e( 'Videos Imported', 'automatic-youtube-gallery' ); ?></span>
261 </div>
262 </div>
263
264 <?php if ( ! in_array( $form_data['type'], $no_schedule_types, true ) ) : ?>
265 <div class="ayg-card ayg-card-kpi">
266 <span class="ayg-kpi-icon dashicons dashicons-clock" aria-hidden="true"></span>
267 <div class="ayg-kpi-body">
268 <strong class="ayg-kpi-value ayg-kpi-value-date">
269 <?php
270 if ( ! empty( $form_data['last_imported_at'] ) ) {
271 echo esc_html( wp_date( $date_format, strtotime( $form_data['last_imported_at'] ) ) );
272 } elseif ( $form_data['video_count'] > 0 ) {
273 // Videos are stored but no run has completed yet (import still in progress / was interrupted).
274 esc_html_e( 'In progress', 'automatic-youtube-gallery' );
275 } else {
276 esc_html_e( 'Never', 'automatic-youtube-gallery' );
277 }
278 ?>
279 </strong>
280 <span class="ayg-kpi-label"><?php esc_html_e( 'Last Imported', 'automatic-youtube-gallery' ); ?></span>
281 <?php if ( ! empty( $form_data['next_import_at'] ) ) : ?>
282 <span class="ayg-kpi-sublabel">
283 <strong><?php esc_html_e( 'Next', 'automatic-youtube-gallery' ); ?>: </strong>
284 <?php echo esc_html( wp_date( $date_format, strtotime( $form_data['next_import_at'] ) ) ); ?></span>
285 <?php endif; ?>
286 </div>
287 </div>
288 <?php endif; ?>
289 </div>
290 <?php endif; ?>
291 <?php endif; ?>
292
293 <form class="ayg-form ayg-form-field-type-<?php echo esc_attr( $form_data['type'] ); ?> ayg-form-field-theme-<?php echo esc_attr( $form_data['theme'] ); ?>" method="post">
294 <details class="ayg-form-section-title" open>
295 <summary>
296 <span><?php esc_html_e( 'Gallery Title', 'automatic-youtube-gallery' ); ?></span>
297 </summary>
298
299 <div class="ayg-form-controls">
300 <div class="ayg-form-control ayg-form-control-title">
301 <input type="text" name="title" id="ayg-form-field-title" class="ayg-form-field ayg-form-field-title widefat" value="<?php echo esc_attr( $form_data['title'] ); ?>" placeholder="<?php esc_attr_e( 'Enter a title or leave blank to auto-generate', 'automatic-youtube-gallery' ); ?>"<?php if ( $is_new ) echo ' autofocus'; ?>>
302 </div>
303 </div>
304 </details>
305
306 <?php foreach ( $fields as $key => $section ) : ?>
307 <details class="ayg-form-section-<?php echo esc_attr( $key ); ?>"<?php if ( 'source' == $key ) echo ' open'; ?>>
308 <summary>
309 <span><?php echo esc_html( $section['label'] ); ?></span>
310 </summary>
311
312 <div class="ayg-form-controls">
313 <?php if ( 'source' === $key ) : ?>
314 <p class="description">
315 <span class="ayg-text-info dashicons dashicons-info" aria-hidden="true"></span>
316 <?php
317 // The live / importable text (not the locked text) is kept in sync with the
318 // source-type dropdown by admin.js — the strings are mirrored in ayg_admin.i18n
319 // (source_live / source_importable). Keep the three in sync when editing copy.
320 ?>
321 <span class="ayg-source-hint"><?php
322 if ( $source_locked ) {
323 esc_html_e( 'The video source is locked because videos have been imported. Please create a new gallery to use a different source type.', 'automatic-youtube-gallery' );
324 } elseif ( in_array( $form_data['type'], $live_types, true ) ) {
325 esc_html_e( 'This is a live source — you can change it anytime. Updates take effect immediately the next time the gallery is viewed.', 'automatic-youtube-gallery' );
326 } else {
327 esc_html_e( 'The video source can’t be changed once videos are imported. So please make sure you select the right source before saving.', 'automatic-youtube-gallery' );
328 }
329 ?>
330 </span>
331 </p>
332 <?php endif; ?>
333
334 <?php
335 foreach ( $section['fields'] as $field ) :
336 if ( ! isset( $field['placeholder'] ) ) {
337 $field['placeholder'] = '';
338 }
339
340 // Source settings lock once videos are imported. Fields that don't define the
341 // source itself stay editable: the exclude list, the import schedule, and the
342 // popup display options (popup mode + its custom trigger).
343 $is_locked = ( $source_locked && 'source' === $key && ! in_array( $field['name'], array( 'exclude', 'schedule', 'popup', 'content' ), true ) );
344
345 // Required-field marker (asterisk) appended after the label.
346 $required_mark = ! empty( $field['required'] ) ? ' <span class="ayg-form-required" aria-hidden="true">*</span>' : '';
347
348 if ( isset( $form_data[ $field['name'] ] ) ) {
349 $field['value'] = $form_data[ $field['name'] ];
350
351 if ( is_array( $field['value'] ) ) {
352 $field['value'] = implode( "\n", $field['value'] );
353 }
354 }
355 ?>
356 <div class="ayg-form-control ayg-form-control-<?php echo esc_attr( $field['name'] ); ?>">
357 <?php if ( 'text' == $field['type'] || 'url' == $field['type'] || 'number' == $field['type'] ) : ?>
358 <label class="ayg-form-label" for="ayg-form-field-<?php echo esc_attr( $field['name'] ); ?>"><?php echo esc_html( $field['label'] ); echo $required_mark; ?></label>
359 <input type="text" name="<?php echo esc_attr( $field['name'] ); ?>" id="ayg-form-field-<?php echo esc_attr( $field['name'] ); ?>" class="ayg-form-field ayg-form-field-<?php echo esc_attr( $field['name'] ); ?> widefat" placeholder="<?php echo esc_attr( $field['placeholder'] ); ?>" value="<?php echo esc_attr( $field['value'] ); ?>"<?php disabled( $is_locked ); ?> />
360 <?php elseif ( 'textarea' == $field['type'] ) : ?>
361 <label class="ayg-form-label" for="ayg-form-field-<?php echo esc_attr( $field['name'] ); ?>"><?php echo esc_html( $field['label'] ); echo $required_mark; ?></label>
362 <textarea name="<?php echo esc_attr( $field['name'] ); ?>" id="ayg-form-field-<?php echo esc_attr( $field['name'] ); ?>" rows="8" class="ayg-form-field ayg-form-field-<?php echo esc_attr( $field['name'] ); ?> widefat" placeholder="<?php echo esc_attr( $field['placeholder'] ); ?>"<?php disabled( $is_locked ); ?>><?php echo esc_textarea( $field['value'] ); ?></textarea>
363 <?php elseif ( 'select' == $field['type'] || 'radio' == $field['type'] ) : ?>
364 <label class="ayg-form-label" for="ayg-form-field-<?php echo esc_attr( $field['name'] ); ?>"><?php echo esc_html( $field['label'] ); echo $required_mark; ?></label>
365 <select name="<?php echo esc_attr( $field['name'] ); ?>" id="ayg-form-field-<?php echo esc_attr( $field['name'] ); ?>" class="ayg-form-field ayg-form-field-<?php echo esc_attr( $field['name'] ); ?> widefat"<?php disabled( $is_locked ); ?>>
366 <?php
367 foreach ( $field['options'] as $value => $label ) {
368 printf(
369 '<option value="%s"%s>%s</option>',
370 esc_attr( $value ),
371 selected( $value, $field['value'], false ),
372 esc_html( $label )
373 );
374 }
375 ?>
376 </select>
377 <?php elseif ( 'checkbox' == $field['type'] ) : ?>
378 <label class="ayg-form-label" for="ayg-form-field-<?php echo esc_attr( $field['name'] ); ?>">
379 <input type="checkbox" name="<?php echo esc_attr( $field['name'] ); ?>" id="ayg-form-field-<?php echo esc_attr( $field['name'] ); ?>" class="ayg-form-field ayg-form-field-<?php echo esc_attr( $field['name'] ); ?>" value="1" <?php checked( $field['value'], 1 ); disabled( $is_locked ); ?> />
380 <?php echo esc_html( $field['label'] ); ?>
381 </label>
382 <?php elseif ( 'color' == $field['type'] ) : ?>
383 <label class="ayg-form-label" for="ayg-form-field-<?php echo esc_attr( $field['name'] ); ?>"><?php echo esc_html( $field['label'] ); echo $required_mark; ?></label>
384 <input type="text" name="<?php echo esc_attr( $field['name'] ); ?>" id="ayg-form-field-<?php echo esc_attr( $field['name'] ); ?>" class="ayg-form-field ayg-form-field-<?php echo esc_attr( $field['name'] ); ?> ayg-color-picker widefat" value="<?php echo esc_attr( $field['value'] ); ?>"<?php disabled( $is_locked ); ?> />
385 <?php endif; ?>
386
387 <?php if ( 'source' === $key && in_array( $field['name'], $source_value_fields, true ) ) : ?>
388 <span class="ayg-form-status"></span>
389 <?php endif; ?>
390
391 <?php if ( ! empty( $field['description'] ) ) : ?>
392 <p class="description"><?php echo wp_kses_post( $field['description'] ); ?></p>
393 <?php endif; ?>
394 </div>
395 <?php
396 endforeach;
397 ?>
398 </div>
399 </details>
400 <?php endforeach; ?>
401
402 <?php
403 $logs = ! $is_new ? json_decode( (string) $form_data['import_log'], true ) : array();
404 $logs = is_array( $logs ) ? array_reverse( $logs ) : array();
405
406 if ( $logs ) : ?>
407 <details class="ayg-form-section-import-history">
408 <summary>
409 <span><?php esc_html_e( 'Import History', 'automatic-youtube-gallery' ); ?></span>
410 </summary>
411
412 <div class="ayg-form-controls">
413 <table class="wp-list-table widefat fixed striped">
414 <thead>
415 <tr>
416 <th scope="col" class="column-number">#</th>
417 <th scope="col" class="column-date column-primary"><?php esc_html_e( 'Date', 'automatic-youtube-gallery' ); ?></th>
418 <th scope="col" class="column-videos"><?php esc_html_e( 'Videos', 'automatic-youtube-gallery' ); ?></th>
419 <th scope="col" class="column-status"><?php esc_html_e( 'Status', 'automatic-youtube-gallery' ); ?></th>
420 </tr>
421 </thead>
422 <tbody>
423 <?php foreach ( $logs as $index => $log ) : ?>
424 <tr>
425 <th scope="row" class="column-number"><?php echo (int) $index + 1; ?></th>
426 <td class="column-date column-primary" data-colname="<?php esc_attr_e( 'Date', 'automatic-youtube-gallery' ); ?>">
427 <?php echo esc_html( ! empty( $log['date'] ) ? wp_date( $date_format, strtotime( $log['date'] ) ) : '' ); ?>
428 <button type="button" class="toggle-row"><span class="screen-reader-text"><?php esc_html_e( 'Show more details', 'automatic-youtube-gallery' ); ?></span></button>
429 </td>
430 <td class="column-videos" data-colname="<?php esc_attr_e( 'Videos', 'automatic-youtube-gallery' ); ?>">
431 <ul>
432 <li>
433 <span><?php esc_html_e( 'Imported', 'automatic-youtube-gallery' ); ?>:</span>
434 <span class="ayg-text-info"><?php echo isset( $log['imported'] ) ? (int) $log['imported'] : 0; ?></span>
435 </li>
436 <?php if ( ! empty( $log['updated'] ) ) : ?>
437 <li>
438 <span><?php esc_html_e( 'Updated', 'automatic-youtube-gallery' ); ?>:</span>
439 <span class="ayg-text-info"><?php echo (int) $log['updated']; ?></span>
440 </li>
441 <?php endif; ?>
442 <?php if ( ! empty( $log['deleted'] ) ) : ?>
443 <li>
444 <span><?php esc_html_e( 'Deleted', 'automatic-youtube-gallery' ); ?>:</span>
445 <span class="ayg-text-info"><?php echo (int) $log['deleted']; ?></span>
446 </li>
447 <?php endif; ?>
448 </ul>
449 </td>
450 <td class="column-status" data-colname="<?php esc_attr_e( 'Status', 'automatic-youtube-gallery' ); ?>">
451 <?php
452 $log_status = isset( $log['status'] ) ? $log['status'] : 'idle';
453
454 // A recurring success is stored as 'idle'; render it with the green "completed"
455 // badge so both success rows match. Live-state 'idle' badges (KPI card, list) are
456 // unaffected — this mapping is local to the history table.
457 $log_badge_class = ( 'idle' === $log_status ) ? 'completed' : $log_status;
458 ?>
459 <span class="ayg-badge ayg-badge-<?php echo esc_attr( $log_badge_class ); ?>"><?php echo esc_html( ayg_get_import_status_label( $log_status, null, false, 'log' ) ); ?></span>
460 <?php if ( ! empty( $log['error'] ) ) : ?>
461 <p class="ayg-text-error"><?php echo esc_html( sanitize_text_field( $log['error'] ) ); ?></p>
462 <?php endif; ?>
463 </td>
464 </tr>
465 <?php endforeach; ?>
466 </tbody>
467 </table>
468 </div>
469 </details>
470 <?php endif; ?>
471
472 <?php if ( ! $is_new && ! in_array( $form_data['type'], $live_types, true ) ) : ?>
473 <p class="description">
474 <label>
475 <input type="checkbox" id="ayg-can-import-videos" checked />
476 <?php esc_html_e( 'Import videos from YouTube now, when you save — adds new videos, updates titles/descriptions, and removes deleted ones. Uncheck to save display settings only. This is a one-time import on save and is separate from the Import Schedule above.', 'automatic-youtube-gallery' ); ?>
477 </label>
478 </p>
479 <?php endif; ?>
480
481 <div class="ayg-form-actions">
482 <input type="hidden" name="gallery_id" value="<?php echo absint( $gallery_id ); ?>">
483
484 <button type="button" id="ayg-button-save-gallery" class="ayg-button ayg-button-save-gallery button button-primary button-hero" data-id="<?php echo absint( $gallery_id ); ?>">
485 <?php echo $is_new ? esc_html__( 'Create Gallery', 'automatic-youtube-gallery' ) : esc_html__( 'Update Gallery', 'automatic-youtube-gallery' ); ?>
486 </button>
487
488 <?php if ( ! $is_new ) : ?>
489 <button type="button" id="ayg-button-delete-gallery" class="ayg-button ayg-button-delete-gallery button button-hero" data-id="<?php echo absint( $gallery_id ); ?>">
490 <?php esc_html_e( 'Delete Gallery', 'automatic-youtube-gallery' ); ?>
491 </button>
492 <?php endif; ?>
493
494 <span class="ayg-form-status"></span>
495 </div>
496 </form>
497 </div>
498