PluginProbe
Search Atlas SEO – OTTO AI SEO Automation for WordPress / 2.6.8
Search Atlas SEO – OTTO AI SEO Automation for WordPress v2.6.8
2.6.26 2.6.25 2.6.24 2.6.23 2.6.22 2.6.21 2.6.20 2.6.19 2.6.18 2.6.17 2.6.16 2.6.15 2.6.14 2.6.13 2.6.12 2.6.11 2.6.10 2.6.9 2.6.8 2.6.7 2.6.6 2.6.5 2.6.4 2.6.3 2.5.23 All 138 releases
metasync / views / metasync-xml-sitemap.php

metasync-xml-sitemap.php in Search Atlas SEO – OTTO AI SEO Automation for WordPress 2.6.8, at views/metasync-xml-sitemap.php

734 lines 42.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * The XML Sitemap admin page view
4 *
5 * @link https://searchatlas.com
6 * @since 1.0.0
7 *
8 * @package Metasync
9 * @subpackage Metasync/views
10 */
11
12 if (!defined('ABSPATH')) {
13 exit; // Exit if accessed directly
14 }
15 ?>
16
17 <?php $this->render_layout_open('XML Sitemap', 'xml_sitemap', 'Manage your XML sitemap settings and status.'); ?>
18
19 <div class="metasync-sitemap-tabs">
20 <ul class="metasync-tab-nav">
21 <li>
22 <a href="<?php echo esc_url(admin_url('admin.php?page=' . Metasync_Admin::$page_slug . '-xml-sitemap&tab=general')); ?>"
23 data-tab="general">
24 <?php esc_html_e('General', 'metasync'); ?>
25 </a>
26 </li>
27 <li>
28 <a href="<?php echo esc_url(admin_url('admin.php?page=' . Metasync_Admin::$page_slug . '-xml-sitemap&tab=news')); ?>"
29 data-tab="news">
30 <?php esc_html_e('News Sitemap', 'metasync'); ?>
31 </a>
32 </li>
33 <li>
34 <a href="<?php echo esc_url(admin_url('admin.php?page=' . Metasync_Admin::$page_slug . '-xml-sitemap&tab=video')); ?>"
35 data-tab="video">
36 <?php esc_html_e('Video Sitemap', 'metasync'); ?>
37 </a>
38 </li>
39 </ul>
40 </div>
41
42 <!-- General Tab -->
43 <div id="metasync-sitemap-general" class="metasync-sitemap-tab-content">
44
45 <div class="metasync-sitemap-outer">
46 <div class="metasync-sitemap-container">
47
48 <!-- Sitemap Status Card -->
49 <div class="dashboard-card metasync-sitemap-status-card">
50 <h2>Sitemap Status</h2>
51 <p style="color: var(--dashboard-text-secondary); margin-bottom: 20px;">Monitor your sitemap generation and status.</p>
52
53 <?php
54 $sitemap_files = $sitemap_generator->get_sitemap_files();
55 $sitemap_count = count($sitemap_files);
56
57 // Check news/video sitemap status
58 $news_sm_enabled = !empty($news_settings['enabled']);
59 $video_sm_enabled = !empty($video_settings['enabled']);
60 $news_sm_exists = false !== get_transient('metasync_vsm_' . md5('news-sitemap.xml'))
61 || file_exists(ABSPATH . 'news-sitemap.xml');
62 $video_sm_exists = false !== get_transient('metasync_vsm_' . md5('video-sitemap.xml'))
63 || file_exists(ABSPATH . 'video-sitemap.xml');
64 $extra_sitemap_count = ($news_sm_exists ? 1 : 0) + ($video_sm_exists ? 1 : 0);
65 $total_sitemap_count = $sitemap_count + $extra_sitemap_count;
66
67 // Count URLs in news/video sitemaps for total
68 $news_url_count = 0;
69 $video_url_count = 0;
70 if ($news_sm_exists) {
71 $news_xml = get_transient('metasync_vsm_' . md5('news-sitemap.xml'));
72 if (!$news_xml && file_exists(ABSPATH . 'news-sitemap.xml')) {
73 $news_xml = file_get_contents(ABSPATH . 'news-sitemap.xml');
74 }
75 if ($news_xml) {
76 $news_url_count = substr_count($news_xml, '<url>');
77 }
78 }
79 if ($video_sm_exists) {
80 $video_xml = get_transient('metasync_vsm_' . md5('video-sitemap.xml'));
81 if (!$video_xml && file_exists(ABSPATH . 'video-sitemap.xml')) {
82 $video_xml = file_get_contents(ABSPATH . 'video-sitemap.xml');
83 }
84 if ($video_xml) {
85 $video_url_count = substr_count($video_xml, '<url>');
86 }
87 }
88 $total_url_count = $url_count + $news_url_count + $video_url_count;
89 ?>
90
91 <div class="metasync-sitemap-status-grid">
92 <div class="metasync-sitemap-stat">
93 <div class="stat-icon"><span class="dashicons dashicons-media-default"></span></div>
94 <div class="stat-content">
95 <div class="stat-label">Status</div>
96 <div class="stat-value <?php echo $sitemap_exists ? 'status-active' : 'status-inactive'; ?>">
97 <?php
98 echo $sitemap_exists ? 'Generated' : 'Not Generated';
99 if ($sitemap_exists && $sitemap_generator->is_virtual_mode()): ?>
100 <span style="color: #2271b1; font-size: 12px; margin-left: 5px;">(Virtual)</span>
101 <?php endif; ?>
102 </div>
103 </div>
104 </div>
105
106 <div class="metasync-sitemap-stat">
107 <div class="stat-icon"><span class="dashicons dashicons-admin-links"></span></div>
108 <div class="stat-content">
109 <div class="stat-label">Total URLs</div>
110 <div class="stat-value"><?php echo number_format($total_url_count); ?></div>
111 </div>
112 </div>
113
114 <div class="metasync-sitemap-stat">
115 <div class="stat-icon"><span class="dashicons dashicons-list-view"></span></div>
116 <div class="stat-content">
117 <div class="stat-label">Sitemap Files</div>
118 <div class="stat-value"><?php echo $total_sitemap_count; ?></div>
119 </div>
120 </div>
121
122 <div class="metasync-sitemap-stat">
123 <div class="stat-icon"><span class="dashicons dashicons-update"></span></div>
124 <div class="stat-content">
125 <div class="stat-label">Auto-Update</div>
126 <div class="stat-value <?php echo $auto_update_enabled ? 'status-active' : 'status-inactive'; ?>">
127 <?php echo $auto_update_enabled ? 'Enabled' : 'Disabled'; ?>
128 </div>
129 </div>
130 </div>
131
132 <div class="metasync-sitemap-stat">
133 <div class="stat-icon"><span class="dashicons dashicons-clock"></span></div>
134 <div class="stat-content">
135 <div class="stat-label">Last Generated</div>
136 <div class="stat-value stat-value-small">
137 <?php
138 if ($last_generated) {
139 $time_diff = human_time_diff(strtotime($last_generated), current_time('timestamp'));
140 echo esc_html($time_diff) . ' ago';
141 } else {
142 echo 'Never';
143 }
144 ?>
145 </div>
146 </div>
147 </div>
148 </div>
149
150 <?php if ($sitemap_exists): ?>
151 <div class="metasync-sitemap-url-box">
152 <strong>Sitemap Index URL:</strong>
153 <a href="<?php echo esc_url($sitemap_url); ?>" target="_blank" class="metasync-sitemap-link">
154 <?php echo esc_url($sitemap_url); ?>
155 <span class="dashicons dashicons-external"></span>
156 </a>
157 <p style="margin: 10px 0 0 0; color: var(--dashboard-text-secondary); font-size: 13px;">
158 <em>Submit this URL to Google Search Console for indexing.</em>
159 </p>
160 </div>
161 <?php endif; ?>
162 </div>
163
164 <?php if (!empty($active_sitemap_plugins)): ?>
165 <!-- Info notice about other sitemap plugins -->
166 <div class="dashboard-card metasync-sitemap-info-notice">
167 <div class="metasync-info-notice-content">
168 <span class="dashicons dashicons-info" style="font-size: 20px; color: var(--dashboard-text-secondary);"></span>
169 <div>
170 <strong>Other Sitemap Plugins Detected:</strong>
171 <p style="margin: 5px 0 0 0; color: var(--dashboard-text-secondary); font-size: 14px;">
172 <?php
173 $plugin_names = array_values($active_sitemap_plugins);
174 echo esc_html(implode(', ', $plugin_names));
175 ?>
176 <?php if (count($active_sitemap_plugins) === 1): ?>
177 is active. This plugin's sitemap will be automatically disabled when you generate the sitemap below.
178 <?php else: ?>
179 are active. These plugins' sitemaps will be automatically disabled when you generate the sitemap below.
180 <?php endif; ?>
181 </p>
182 </div>
183 </div>
184 </div>
185 <?php endif; ?>
186
187 <!-- Generate Sitemap Card -->
188 <div class="dashboard-card metasync-sitemap-actions-card">
189 <h2>Sitemap Actions</h2>
190 <p style="color: var(--dashboard-text-secondary); margin-bottom: 20px;">
191 Generate or manage your XML sitemap with the controls below.
192 </p>
193
194
195
196 <div class="metasync-sitemap-actions-grid">
197 <form method="post" action="" class="metasync-sitemap-action-form">
198 <?php wp_nonce_field('metasync_sitemap_action', 'metasync_sitemap_nonce'); ?>
199 <button type="submit" name="generate_sitemap" class="button button-primary button-hero metasync-sitemap-button-large">
200 <span class="dashicons dashicons-update"></span>
201 Generate Sitemap Now
202 </button>
203 <p class="metasync-button-description">
204 <?php
205 $urls_per_sitemap = $sitemap_generator->get_urls_per_sitemap();
206 if (!empty($active_sitemap_plugins)): ?>
207 Creates sitemap files (split into <?php echo number_format($urls_per_sitemap); ?> URLs each) and disables conflicting sitemaps.
208 <?php else: ?>
209 Creates sitemap index and individual sitemap files (split into <?php echo number_format($urls_per_sitemap); ?> URLs each).
210 <?php endif; ?>
211 </p>
212 </form>
213
214 <form method="post" action="" class="metasync-sitemap-action-form">
215 <?php wp_nonce_field('metasync_sitemap_action', 'metasync_sitemap_nonce'); ?>
216 <?php if ($auto_update_enabled): ?>
217 <button type="submit" name="disable_auto_update" class="button button-secondary button-hero metasync-sitemap-button-large">
218 <span class="dashicons dashicons-no"></span>
219 Disable Auto-Update
220 </button>
221 <p class="metasync-button-description">
222 Currently enabled - sitemap updates automatically when posts change.
223 </p>
224 <?php else: ?>
225 <button type="submit" name="enable_auto_update" class="button button-secondary button-hero metasync-sitemap-button-large">
226 <span class="dashicons dashicons-yes"></span>
227 Enable Auto-Update
228 </button>
229 <p class="metasync-button-description">
230 Automatically regenerate sitemap when posts are created or updated.
231 </p>
232 <?php endif; ?>
233 </form>
234
235 <?php if ($sitemap_exists): ?>
236 <form method="post" action="" class="metasync-sitemap-action-form" onsubmit="return confirm('Are you sure you want to delete all sitemap files? This action cannot be undone.');">
237 <?php wp_nonce_field('metasync_sitemap_action', 'metasync_sitemap_nonce'); ?>
238 <button type="submit" name="delete_sitemap" class="button button-secondary button-hero metasync-sitemap-button-large" style="border-color: #dc3232; color: #dc3232;">
239 <span class="dashicons dashicons-trash"></span>
240 Delete All Sitemaps
241 </button>
242 <p class="metasync-button-description">
243 Permanently delete all sitemap files from your server.
244 </p>
245 </form>
246 <?php endif; ?>
247
248 <?php if (!empty($active_sitemap_plugins)): ?>
249 <form method="post" action="" class="metasync-sitemap-action-form">
250 <?php wp_nonce_field('metasync_sitemap_action', 'metasync_sitemap_nonce'); ?>
251 <button type="submit" name="enable_other_sitemaps" class="button button-secondary button-hero metasync-sitemap-button-large" style="border-color: #00a32a; color: #00a32a;">
252 <span class="dashicons dashicons-controls-repeat"></span>
253 Re-enable Other Sitemaps
254 </button>
255 <p class="metasync-button-description">
256 Re-enable sitemap generation from <?php echo esc_html(implode(', ', array_values($active_sitemap_plugins))); ?>.
257 </p>
258 </form>
259 <?php endif; ?>
260
261 <!-- Import from SEO Plugins Button (Always visible) -->
262 <div >
263 <a href="<?php echo esc_url(admin_url('admin.php?page=' . Metasync_Admin::$page_slug . '-import-external&tab=sitemap')); ?>" class="button button-secondary button-hero metasync-sitemap-button-large">
264 <span class="dashicons dashicons-download" style="margin-top:3px;font-size:15px;width:15px;height:15px;"></span> Import from SEO Plugins
265 </a>
266 <p class="metasync-button-description">
267 Import sitemap settings from other SEO plugins like Yoast, Rank Math, or AIOSEO.
268 </p>
269 </div>
270 </div>
271
272 </div>
273
274 <?php if ($sitemap_exists && !empty($sitemap_files)): ?>
275 <!-- Sitemap Files List Card -->
276 <div class="dashboard-card metasync-sitemap-files-card">
277 <h2>Sitemap Files</h2>
278 <p style="color: var(--dashboard-text-secondary); margin-bottom: 20px;">
279 Your sitemap has <?php echo $total_sitemap_count; ?> file<?php echo $total_sitemap_count > 1 ? 's' : ''; ?> <?php echo $sitemap_count; ?> main (up to <?php echo number_format($sitemap_generator->get_urls_per_sitemap()); ?> URLs each)<?php
280 if ($news_sm_exists || $video_sm_exists) {
281 $extras = [];
282 if ($news_sm_exists) $extras[] = 'news';
283 if ($video_sm_exists) $extras[] = 'video';
284 echo ', plus ' . implode(' &amp; ', $extras);
285 }
286 ?>.
287 </p>
288
289 <table class="metasync-sitemap-table">
290 <thead>
291 <tr>
292 <th><?php esc_html_e('Sitemap File', 'metasync'); ?></th>
293 <th><?php esc_html_e('URLs', 'metasync'); ?></th>
294 <th><?php esc_html_e('Last Modified', 'metasync'); ?></th>
295 <th><?php esc_html_e('Actions', 'metasync'); ?></th>
296 </tr>
297 </thead>
298 <tbody>
299 <?php
300 $urls_per_file = $sitemap_generator->get_urls_per_sitemap();
301 $total_urls = $url_count;
302 foreach ($sitemap_files as $index => $sitemap_file):
303 // Calculate URLs in this file
304 $start_url = ($index * $urls_per_file) + 1;
305 $end_url = min(($index + 1) * $urls_per_file, $total_urls);
306 $urls_in_file = $end_url - $start_url + 1;
307 ?>
308 <tr>
309 <td>
310 <div class="sitemap-filename"><?php echo esc_html($sitemap_file['filename']); ?></div>
311 <div class="sitemap-url-range">
312 URLs <?php echo number_format($start_url); ?> - <?php echo number_format($end_url); ?>
313 </div>
314 </td>
315 <td><?php echo number_format($urls_in_file); ?></td>
316 <td>
317 <?php
318 if ($last_generated) {
319 echo esc_html(date('M j, Y g:i A', strtotime($last_generated)));
320 } else {
321 echo '';
322 }
323 ?>
324 </td>
325 <td>
326 <a href="<?php echo esc_url($sitemap_file['url']); ?>" target="_blank" class="button-view">
327 <span class="dashicons dashicons-external"></span>
328 View
329 </a>
330 </td>
331 </tr>
332 <?php endforeach; ?>
333
334 <?php if ($news_sm_exists): ?>
335 <tr>
336 <td>
337 <div class="sitemap-filename">news-sitemap.xml</div>
338 <div class="sitemap-url-range"><?php esc_html_e('Google News Sitemap', 'metasync'); ?></div>
339 </td>
340 <td><?php echo $news_url_count; ?></td>
341 <td><?php echo $last_generated ? esc_html(date('M j, Y g:i A', strtotime($last_generated))) : ''; ?></td>
342 <td>
343 <a href="<?php echo esc_url(home_url('/news-sitemap.xml')); ?>" target="_blank" class="button-view">
344 <span class="dashicons dashicons-external"></span>
345 View
346 </a>
347 </td>
348 </tr>
349 <?php endif; ?>
350
351 <?php if ($video_sm_exists): ?>
352 <tr>
353 <td>
354 <div class="sitemap-filename">video-sitemap.xml</div>
355 <div class="sitemap-url-range"><?php esc_html_e('Video Sitemap', 'metasync'); ?></div>
356 </td>
357 <td><?php echo $video_url_count; ?></td>
358 <td><?php echo $last_generated ? esc_html(date('M j, Y g:i A', strtotime($last_generated))) : ''; ?></td>
359 <td>
360 <a href="<?php echo esc_url(home_url('/video-sitemap.xml')); ?>" target="_blank" class="button-view">
361 <span class="dashicons dashicons-external"></span>
362 View
363 </a>
364 </td>
365 </tr>
366 <?php endif; ?>
367 </tbody>
368 </table>
369 </div>
370
371 <!-- Sitemap Index Preview Card -->
372 <div class="dashboard-card metasync-sitemap-preview-card">
373 <h2>Sitemap Index Preview</h2>
374 <p style="color: var(--dashboard-text-secondary); margin-bottom: 20px;">
375 Preview the sitemap index file that references all individual sitemaps.
376 </p>
377
378 <div class="metasync-sitemap-preview-container">
379 <div class="metasync-sitemap-preview-header">
380 <span class="metasync-preview-label">sitemap_index.xml</span>
381 <a href="<?php echo esc_url($sitemap_url); ?>" target="_blank" class="button button-small">
382 <span class="dashicons dashicons-external"></span>
383 View Sitemap Index
384 </a>
385 </div>
386 <div class="metasync-sitemap-code-block">
387 <pre><?php
388 $content = $sitemap_generator->get_sitemap_content();
389 if ($content) {
390 $lines = explode("\n", $content);
391 $preview_lines = array_slice($lines, 0, 50);
392 echo esc_html(implode("\n", $preview_lines));
393 if (count($lines) > 50) {
394 echo "\n... [" . (count($lines) - 50) . " more lines]";
395 }
396 } else {
397 echo "Unable to read sitemap index content.";
398 }
399 ?></pre>
400 </div>
401 </div>
402 </div>
403 <?php endif; ?>
404
405 </div>
406 </div>
407 </div><!-- /#metasync-sitemap-general -->
408
409 <!-- News Sitemap Tab -->
410 <div id="metasync-sitemap-news" class="metasync-sitemap-tab-content">
411 <div class="metasync-sitemap-outer">
412 <div class="metasync-sitemap-container">
413
414 <?php
415 require_once plugin_dir_path(dirname(__FILE__)) . 'sitemap/class-metasync-sitemap-news.php';
416 $news_checker = new Metasync_Sitemap_News();
417 $news_conflicts = $news_checker->get_conflict_notices();
418 $news_has_content = false !== get_transient('metasync_vsm_' . md5('news-sitemap.xml'))
419 || file_exists(ABSPATH . 'news-sitemap.xml');
420 ?>
421
422 <!-- News Sitemap Status -->
423 <div class="dashboard-card" style="margin-bottom: 20px;">
424 <h2><?php esc_html_e('News Sitemap Status', 'metasync'); ?></h2>
425 <div style="display: flex; gap: 24px; align-items: center; margin-top: 16px; flex-wrap: wrap;">
426 <div style="display: flex; align-items: center; gap: 10px;">
427 <span style="font-size: 20px;">📄</span>
428 <div>
429 <div style="color: var(--dashboard-text-secondary); font-size: 12px; text-transform: uppercase; letter-spacing: 0.05em;"><?php esc_html_e('Status', 'metasync'); ?></div>
430 <?php if (!empty($news_settings['enabled']) && $news_has_content && empty($news_conflicts)): ?>
431 <div style="color: var(--dashboard-success, #10b981); font-weight: 600;"><?php esc_html_e('Generated', 'metasync'); ?></div>
432 <?php elseif (!empty($news_settings['enabled']) && !$news_has_content && empty($news_conflicts)): ?>
433 <div style="color: var(--dashboard-warning, #f59e0b); font-weight: 600;"><?php esc_html_e('Not Generated', 'metasync'); ?></div>
434 <?php elseif (!empty($news_conflicts)): ?>
435 <div style="color: var(--dashboard-error, #ef4444); font-weight: 600;"><?php esc_html_e('Conflict Detected', 'metasync'); ?></div>
436 <?php else: ?>
437 <div style="color: var(--dashboard-text-secondary); font-weight: 600;"><?php esc_html_e('Disabled', 'metasync'); ?></div>
438 <?php endif; ?>
439 </div>
440 </div>
441 <?php if (!empty($news_settings['enabled']) && $news_has_content && empty($news_conflicts)): ?>
442 <div style="display: flex; align-items: center; gap: 10px;">
443 <span style="font-size: 20px;">🔗</span>
444 <div>
445 <div style="color: var(--dashboard-text-secondary); font-size: 12px; text-transform: uppercase; letter-spacing: 0.05em;"><?php esc_html_e('URL', 'metasync'); ?></div>
446 <a href="<?php echo esc_url(home_url('/news-sitemap.xml')); ?>" target="_blank" style="color: var(--dashboard-accent, #3b82f6); font-weight: 500; text-decoration: none;">
447 <?php echo esc_html(home_url('/news-sitemap.xml')); ?>
448 <span class="dashicons dashicons-external" style="font-size: 14px; width: 14px; height: 14px; vertical-align: middle;"></span>
449 </a>
450 </div>
451 </div>
452 <?php endif; ?>
453 </div>
454
455 <?php if (!empty($news_settings['enabled']) && empty($news_conflicts)): ?>
456 <div style="margin-top: 20px;">
457 <form method="post" style="display: inline;">
458 <?php wp_nonce_field('metasync_news_sitemap_action', 'metasync_news_sitemap_nonce'); ?>
459 <button type="submit" name="generate_news_sitemap" class="button button-primary button-hero metasync-sitemap-button-large">
460 <span class="dashicons dashicons-update"></span>
461 <?php $news_has_content ? esc_html_e('Regenerate News Sitemap', 'metasync') : esc_html_e('Generate News Sitemap Now', 'metasync'); ?>
462 </button>
463 </form>
464 <p style="margin-top: 8px; color: var(--dashboard-text-secondary); font-size: 13px;">
465 <?php esc_html_e('Generates the news sitemap with articles from the last 2 days (max 1,000 URLs).', 'metasync'); ?>
466 </p>
467 </div>
468 <?php endif; ?>
469 </div>
470
471 <?php foreach ($news_conflicts as $notice) {
472 $notice_type = (strpos($notice, 'can coexist') !== false) ? 'notice-info' : 'notice-warning';
473 echo '<div class="notice ' . $notice_type . ' inline" style="margin-bottom: 12px; padding: 12px 16px; border-radius: 8px; background: rgba(255, 152, 0, 0.1); border-left: 4px solid var(--dashboard-warning, #f59e0b); color: var(--dashboard-text-primary, #fff);"><p style="margin: 0;">&#9888; ' . esc_html($notice) . '</p></div>';
474 } ?>
475
476 <div class="dashboard-card">
477 <h2><?php esc_html_e('News Sitemap Settings', 'metasync'); ?></h2>
478 <p style="color: var(--dashboard-text-secondary); margin-bottom: 20px;">
479 <?php esc_html_e('Configure the Google News Sitemap. Only articles published within the last 2 days will be included (max 1,000 URLs).', 'metasync'); ?>
480 </p>
481
482 <form method="post">
483 <?php wp_nonce_field('metasync_news_sitemap_action', 'metasync_news_sitemap_nonce'); ?>
484
485 <table class="form-table">
486 <tr>
487 <th scope="row"><?php esc_html_e('Enable News Sitemap', 'metasync'); ?></th>
488 <td>
489 <label>
490 <input type="checkbox" name="news_enabled" value="1" <?php checked(!empty($news_settings['enabled'])); ?> />
491 <?php esc_html_e('Enable Google News Sitemap at /news-sitemap.xml', 'metasync'); ?>
492 </label>
493 </td>
494 </tr>
495 <tr>
496 <th scope="row"><?php esc_html_e('Post Types', 'metasync'); ?></th>
497 <td>
498 <?php
499 $public_post_types = get_post_types(['public' => true], 'objects');
500 $filtered_pts = [];
501 foreach ($public_post_types as $pt) {
502 if ($pt->name !== 'attachment') $filtered_pts[] = $pt;
503 }
504 $selected_post_types = isset($news_settings['post_types']) ? (array) $news_settings['post_types'] : ['post'];
505 $pts_scrollable = count($filtered_pts) > 10;
506 if ($pts_scrollable) : ?>
507 <input type="text" class="metasync-checkbox-search" placeholder="<?php esc_attr_e('Filter post types...', 'metasync'); ?>">
508 <?php endif; ?>
509 <div class="<?php echo $pts_scrollable ? 'metasync-checkbox-scroll' : ''; ?>">
510 <?php foreach ($filtered_pts as $pt) : ?>
511 <label>
512 <input type="checkbox" name="news_post_types[]" value="<?php echo esc_attr($pt->name); ?>"
513 <?php checked(in_array($pt->name, $selected_post_types, true)); ?> />
514 <?php echo esc_html($pt->label); ?>
515 </label>
516 <?php endforeach; ?>
517 <p class="metasync-no-results"><?php esc_html_e('No post types match your search.', 'metasync'); ?></p>
518 </div>
519 </td>
520 </tr>
521 <tr>
522 <th scope="row">
523 <?php esc_html_e('Categories', 'metasync'); ?>
524 <?php $categories = get_categories(['hide_empty' => false]); ?>
525 <span class="metasync-checkbox-count">(<?php echo count($categories); ?>)</span>
526 </th>
527 <td>
528 <?php
529 $selected_cats = isset($news_settings['categories']) ? (array) $news_settings['categories'] : [];
530 $cats_scrollable = count($categories) > 10;
531 if ($cats_scrollable) : ?>
532 <input type="text" class="metasync-checkbox-search" placeholder="<?php esc_attr_e('Filter categories...', 'metasync'); ?>">
533 <?php endif; ?>
534 <div class="<?php echo $cats_scrollable ? 'metasync-checkbox-scroll' : ''; ?>">
535 <?php foreach ($categories as $cat) : ?>
536 <label>
537 <input type="checkbox" name="news_categories[]" value="<?php echo esc_attr($cat->term_id); ?>"
538 <?php checked(in_array($cat->term_id, $selected_cats)); ?> />
539 <?php echo esc_html($cat->name); ?>
540 </label>
541 <?php endforeach; ?>
542 <p class="metasync-no-results"><?php esc_html_e('No categories match your search.', 'metasync'); ?></p>
543 </div>
544 <p class="description"><?php esc_html_e('Leave empty to include all categories.', 'metasync'); ?></p>
545 </td>
546 </tr>
547 <tr>
548 <th scope="row">
549 <?php esc_html_e('Tags', 'metasync'); ?>
550 <?php $tags = get_tags(['hide_empty' => false]); ?>
551 <span class="metasync-checkbox-count">(<?php echo count($tags); ?>)</span>
552 </th>
553 <td>
554 <?php
555 $selected_tags = isset($news_settings['tags']) ? (array) $news_settings['tags'] : [];
556 if (!empty($tags)) :
557 $tags_scrollable = count($tags) > 10;
558 if ($tags_scrollable) : ?>
559 <input type="text" class="metasync-checkbox-search" placeholder="<?php esc_attr_e('Filter tags...', 'metasync'); ?>">
560 <?php endif; ?>
561 <div class="<?php echo $tags_scrollable ? 'metasync-checkbox-scroll' : ''; ?>">
562 <?php foreach ($tags as $tag) : ?>
563 <label>
564 <input type="checkbox" name="news_tags[]" value="<?php echo esc_attr($tag->term_id); ?>"
565 <?php checked(in_array($tag->term_id, $selected_tags)); ?> />
566 <?php echo esc_html($tag->name); ?>
567 </label>
568 <?php endforeach; ?>
569 <p class="metasync-no-results"><?php esc_html_e('No tags match your search.', 'metasync'); ?></p>
570 </div>
571 <?php else : ?>
572 <p class="description"><?php esc_html_e('No tags found.', 'metasync'); ?></p>
573 <?php endif; ?>
574 <p class="description"><?php esc_html_e('Leave empty to include all tags.', 'metasync'); ?></p>
575 </td>
576 </tr>
577 <tr>
578 <th scope="row"><?php esc_html_e('Publication Name', 'metasync'); ?></th>
579 <td>
580 <input type="text" name="publication_name" class="regular-text"
581 value="<?php echo esc_attr(!empty($news_settings['publication_name']) ? $news_settings['publication_name'] : get_bloginfo('name')); ?>" />
582 <p class="description"><?php esc_html_e('Defaults to your site name.', 'metasync'); ?></p>
583 </td>
584 </tr>
585 <tr>
586 <th scope="row"><?php esc_html_e('Publication Language', 'metasync'); ?></th>
587 <td>
588 <input type="text" name="publication_language" class="small-text"
589 value="<?php echo esc_attr(!empty($news_settings['publication_language']) ? $news_settings['publication_language'] : substr(get_locale(), 0, 2)); ?>" />
590 <p class="description"><?php esc_html_e('ISO 639 language code (e.g. en, fr, de). Defaults to site language.', 'metasync'); ?></p>
591 </td>
592 </tr>
593 </table>
594
595 <?php submit_button(esc_html__('Save News Sitemap Settings', 'metasync'), 'primary', 'save_news_sitemap'); ?>
596 </form>
597 </div>
598 </div>
599 </div>
600 </div><!-- /#metasync-sitemap-news -->
601
602 <!-- Video Sitemap Tab -->
603 <div id="metasync-sitemap-video" class="metasync-sitemap-tab-content">
604 <div class="metasync-sitemap-outer">
605 <div class="metasync-sitemap-container">
606
607 <?php
608 require_once plugin_dir_path(dirname(__FILE__)) . 'sitemap/class-metasync-sitemap-video.php';
609 $video_checker = new Metasync_Sitemap_Video();
610 $video_conflicts = $video_checker->get_conflict_notices();
611 $video_has_content = false !== get_transient('metasync_vsm_' . md5('video-sitemap.xml'))
612 || file_exists(ABSPATH . 'video-sitemap.xml');
613 ?>
614
615 <!-- Video Sitemap Status -->
616 <div class="dashboard-card" style="margin-bottom: 20px;">
617 <h2><?php esc_html_e('Video Sitemap Status', 'metasync'); ?></h2>
618 <div style="display: flex; gap: 24px; align-items: center; margin-top: 16px; flex-wrap: wrap;">
619 <div style="display: flex; align-items: center; gap: 10px;">
620 <span style="font-size: 20px;">📄</span>
621 <div>
622 <div style="color: var(--dashboard-text-secondary); font-size: 12px; text-transform: uppercase; letter-spacing: 0.05em;"><?php esc_html_e('Status', 'metasync'); ?></div>
623 <?php if (!empty($video_settings['enabled']) && $video_has_content && empty($video_conflicts)): ?>
624 <div style="color: var(--dashboard-success, #10b981); font-weight: 600;"><?php esc_html_e('Generated', 'metasync'); ?></div>
625 <?php elseif (!empty($video_settings['enabled']) && !$video_has_content && empty($video_conflicts)): ?>
626 <div style="color: var(--dashboard-warning, #f59e0b); font-weight: 600;"><?php esc_html_e('Not Generated', 'metasync'); ?></div>
627 <?php elseif (!empty($video_conflicts)): ?>
628 <div style="color: var(--dashboard-error, #ef4444); font-weight: 600;"><?php esc_html_e('Conflict Detected', 'metasync'); ?></div>
629 <?php else: ?>
630 <div style="color: var(--dashboard-text-secondary); font-weight: 600;"><?php esc_html_e('Disabled', 'metasync'); ?></div>
631 <?php endif; ?>
632 </div>
633 </div>
634 <?php if (!empty($video_settings['enabled']) && $video_has_content && empty($video_conflicts)): ?>
635 <div style="display: flex; align-items: center; gap: 10px;">
636 <span style="font-size: 20px;">🔗</span>
637 <div>
638 <div style="color: var(--dashboard-text-secondary); font-size: 12px; text-transform: uppercase; letter-spacing: 0.05em;"><?php esc_html_e('URL', 'metasync'); ?></div>
639 <a href="<?php echo esc_url(home_url('/video-sitemap.xml')); ?>" target="_blank" style="color: var(--dashboard-accent, #3b82f6); font-weight: 500; text-decoration: none;">
640 <?php echo esc_html(home_url('/video-sitemap.xml')); ?>
641 <span class="dashicons dashicons-external" style="font-size: 14px; width: 14px; height: 14px; vertical-align: middle;"></span>
642 </a>
643 </div>
644 </div>
645 <?php endif; ?>
646 </div>
647
648 <?php if (!empty($video_settings['enabled']) && empty($video_conflicts)): ?>
649 <div style="margin-top: 20px;">
650 <form method="post" style="display: inline;">
651 <?php wp_nonce_field('metasync_video_sitemap_action', 'metasync_video_sitemap_nonce'); ?>
652 <button type="submit" name="generate_video_sitemap" class="button button-primary button-hero metasync-sitemap-button-large">
653 <span class="dashicons dashicons-update"></span>
654 <?php $video_has_content ? esc_html_e('Regenerate Video Sitemap', 'metasync') : esc_html_e('Generate Video Sitemap Now', 'metasync'); ?>
655 </button>
656 </form>
657 <p style="margin-top: 8px; color: var(--dashboard-text-secondary); font-size: 13px;">
658 <?php esc_html_e('Scans all posts for embedded videos and generates the video sitemap.', 'metasync'); ?>
659 </p>
660 </div>
661 <?php endif; ?>
662 </div>
663
664 <?php foreach ($video_conflicts as $notice) {
665 $notice_type = (strpos($notice, 'can coexist') !== false) ? 'notice-info' : 'notice-warning';
666 echo '<div class="notice ' . $notice_type . ' inline" style="margin-bottom: 12px; padding: 12px 16px; border-radius: 8px; background: rgba(255, 152, 0, 0.1); border-left: 4px solid var(--dashboard-warning, #f59e0b); color: var(--dashboard-text-primary, #fff);"><p style="margin: 0;">&#9888; ' . esc_html($notice) . '</p></div>';
667 } ?>
668
669 <div class="dashboard-card">
670 <h2><?php esc_html_e('Video Sitemap Settings', 'metasync'); ?></h2>
671 <p style="color: var(--dashboard-text-secondary); margin-bottom: 20px;">
672 <?php esc_html_e('Configure the Video Sitemap. Auto-detects YouTube, Vimeo, VideoPress, and self-hosted videos in your content.', 'metasync'); ?>
673 </p>
674
675 <form method="post">
676 <?php wp_nonce_field('metasync_video_sitemap_action', 'metasync_video_sitemap_nonce'); ?>
677
678 <table class="form-table">
679 <tr>
680 <th scope="row"><?php esc_html_e('Enable Video Sitemap', 'metasync'); ?></th>
681 <td>
682 <label>
683 <input type="checkbox" name="video_enabled" value="1" <?php checked(!empty($video_settings['enabled'])); ?> />
684 <?php esc_html_e('Enable Video Sitemap at /video-sitemap.xml', 'metasync'); ?>
685 </label>
686 </td>
687 </tr>
688 <tr>
689 <th scope="row"><?php esc_html_e('Post Types', 'metasync'); ?></th>
690 <td>
691 <?php
692 $public_post_types = get_post_types(['public' => true], 'objects');
693 $vid_filtered_pts = [];
694 foreach ($public_post_types as $pt) {
695 if ($pt->name !== 'attachment') $vid_filtered_pts[] = $pt;
696 }
697 $selected_video_pts = isset($video_settings['post_types']) ? (array) $video_settings['post_types'] : ['post', 'page'];
698 $vid_pts_scrollable = count($vid_filtered_pts) > 10;
699 if ($vid_pts_scrollable) : ?>
700 <input type="text" class="metasync-checkbox-search" placeholder="<?php esc_attr_e('Filter post types...', 'metasync'); ?>">
701 <?php endif; ?>
702 <div class="<?php echo $vid_pts_scrollable ? 'metasync-checkbox-scroll' : ''; ?>">
703 <?php foreach ($vid_filtered_pts as $pt) : ?>
704 <label>
705 <input type="checkbox" name="video_post_types[]" value="<?php echo esc_attr($pt->name); ?>"
706 <?php checked(in_array($pt->name, $selected_video_pts, true)); ?> />
707 <?php echo esc_html($pt->label); ?>
708 </label>
709 <?php endforeach; ?>
710 <p class="metasync-no-results"><?php esc_html_e('No post types match your search.', 'metasync'); ?></p>
711 </div>
712 </td>
713 </tr>
714 <tr>
715 <th scope="row"><?php esc_html_e('Auto-Detect Videos', 'metasync'); ?></th>
716 <td>
717 <label>
718 <input type="checkbox" name="auto_detect" value="1" <?php checked(!empty($video_settings['auto_detect'])); ?> />
719 <?php esc_html_e('Automatically detect embedded videos from post content', 'metasync'); ?>
720 </label>
721 <p class="description"><?php esc_html_e('Detects YouTube, Vimeo, VideoPress, and self-hosted &lt;video&gt; tags.', 'metasync'); ?></p>
722 </td>
723 </tr>
724 </table>
725
726 <?php submit_button(esc_html__('Save Video Sitemap Settings', 'metasync'), 'primary', 'save_video_sitemap'); ?>
727 </form>
728 </div>
729 </div>
730 </div>
731 </div><!-- /#metasync-sitemap-video -->
732
733 <?php $this->render_layout_close(); ?>
734