| @@ -217,10 +217,15 @@ | ||
| 217 | 217 | // ------------------------------------------------------------------ |
| 218 | 218 | |
| 219 | 219 | public function create_admin_settings_page() |
| 220 | 220 | { |
| 221 | - $active_tab = isset($_GET['tab']) ? sanitize_key( wp_unslash( $_GET['tab'] ) ) : 'general'; | |
| 221 | + if (isset($_REQUEST['metasync_password_reset'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- routing check, the reset form verifies its own nonce | |
| 222 | + Metasync_Admin_Ajax::instance()->render_password_reset_page(); | |
| 223 | + return; | |
| 224 | + } | |
| 222 | 225 | |
| 226 | + $active_tab = isset($_GET['tab']) ? sanitize_key( wp_unslash( $_GET['tab'] ) ) : 'general'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only tab selection | |
| 227 | + | |
| 223 | 228 | $whitelabel_settings = Metasync::get_whitelabel_settings(); |
| 224 | 229 | |
| 225 | 230 | $user_password = $whitelabel_settings['settings_password'] ?? ''; |
| 226 | 231 | $hide_settings_enabled = !empty($whitelabel_settings['hide_settings']); |
| @@ -245,9 +250,9 @@ | ||
| 245 | 250 | |
| 246 | 251 | $auth = new Metasync_Auth_Manager('whitelabel', 1800); |
| 247 | 252 | $password_validated = $auth->has_access(); |
| 248 | 253 | |
| 249 | - if (isset($_POST['whitelabel_password_submit']) && !$password_validated) { | |
| 254 | + if (isset($_POST['whitelabel_password_submit']) && !$password_validated) { // phpcs:ignore WordPress.Security.NonceVerification.Missing -- read-only access check for a display message | |
| 250 | 255 | $password_error = 'Incorrect password. Please try again.'; |
| 251 | 256 | } |
| 252 | 257 | } |
| 253 | 258 | |
| @@ -333,8 +338,9 @@ | ||
| 333 | 338 | </button> |
| 334 | 339 | </div> |
| 335 | 340 | </form> |
| 336 | 341 | |
| 342 | + <?php if (current_user_can('manage_options')): ?> | |
| 337 | 343 | <div style="text-align: center; margin-top: 20px;"> |
| 338 | 344 | <a href="#" id="metasync-forgot-password-link" style="color: #2271b1; text-decoration: none; font-size: 14px;"> |
| 339 | 345 | Forgot Password? |
| 340 | 346 | </a> |
| @@ -339,64 +345,12 @@ | ||
| 339 | 345 | Forgot Password? |
| 340 | 346 | </a> |
| 341 | 347 | <div id="metasync-recovery-message" style="margin-top: 15px; padding: 12px; border-radius: 6px; display: none;"></div> |
| 342 | 348 | </div> |
| 349 | + <?php endif; ?> | |
| 343 | 350 | |
| 344 | 351 | </div> |
| 345 | 352 | |
| 346 | - <script> | |
| 347 | - jQuery(document).ready(function($) { | |
| 348 | - $('#whitelabel_password').focus(); | |
| 349 | - | |
| 350 | - $('#whitelabel_password').on('keypress', function(e) { | |
| 351 | - if (e.which === 13) { | |
| 352 | - $(this).closest('form').submit(); | |
| 353 | - } | |
| 354 | - }); | |
| 355 | - | |
| 356 | - $('#metasync-forgot-password-link').on('click', function(e) { | |
| 357 | - e.preventDefault(); | |
| 358 | - | |
| 359 | - var $link = $(this); | |
| 360 | - var $message = $('#metasync-recovery-message'); | |
| 361 | - | |
| 362 | - $link.css('pointer-events', 'none').css('opacity', '0.6'); | |
| 363 | - $message.removeClass('success error').hide(); | |
| 364 | - $message.html('⏳ Sending recovery email...').css('background', '#f0f6fc').css('color', '#0c5ba5').css('border', '1px solid #cfe2f3').fadeIn(200); | |
| 365 | - | |
| 366 | - $.ajax({ | |
| 367 | - url: ajaxurl, | |
| 368 | - type: 'POST', | |
| 369 | - data: { | |
| 370 | - action: 'metasync_recover_password', | |
| 371 | - nonce: '<?php echo wp_create_nonce('metasync_recover_password_nonce'); ?>' | |
| 372 | - }, | |
| 373 | - success: function(response) { | |
| 374 | - $link.css('pointer-events', 'auto').css('opacity', '1'); | |
| 375 | - | |
| 376 | - if (response.success) { | |
| 377 | - $message.addClass('success').html('✅ ' + response.data.message) | |
| 378 | - .css('background', '#d4edda') | |
| 379 | - .css('color', '#155724') | |
| 380 | - .css('border', '1px solid #c3e6cb'); | |
| 381 | - } else { | |
| 382 | - $message.addClass('error').html('❌ ' + response.data.message) | |
| 383 | - .css('background', '#f8d7da') | |
| 384 | - .css('color', '#721c24') | |
| 385 | - .css('border', '1px solid #f5c6cb'); | |
| 386 | - } | |
| 387 | - }, | |
| 388 | - error: function() { | |
| 389 | - $link.css('pointer-events', 'auto').css('opacity', '1'); | |
| 390 | - $message.addClass('error').html('❌ An error occurred. Please try again.') | |
| 391 | - .css('background', '#f8d7da') | |
| 392 | - .css('color', '#721c24') | |
| 393 | - .css('border', '1px solid #f5c6cb'); | |
| 394 | - } | |
| 395 | - }); | |
| 396 | - }); | |
| 397 | - }); | |
| 398 | - </script> | |
| 399 | 353 | <?php |
| 400 | 354 | return; |
| 401 | 355 | } elseif (!$password_protection_enabled) { |
| 402 | 356 | ?> |
| @@ -410,8 +364,9 @@ | ||
| 410 | 364 | } |
| 411 | 365 | ?> |
| 412 | 366 | |
| 413 | 367 | <form method="post" action="options.php?tab=<?php echo esc_attr( $active_tab ); ?>" id="metaSyncGeneralSetting"> |
| 368 | + <input type="hidden" name="metasync_pw_reset_generation" value="<?php echo esc_attr((string) (int) get_option('metasync_pw_reset_generation', 0)); ?>" /> | |
| 414 | 369 | <?php |
| 415 | 370 | settings_fields(Metasync_Admin::option_group); |
| 416 | 371 | |
| 417 | 372 | wp_nonce_field('meta_sync_general_setting_nonce', 'meta_sync_nonce'); |
| @@ -439,14 +394,17 @@ | ||
| 439 | 394 | |
| 440 | 395 | <?php |
| 441 | 396 | $this->admin->render_accordion_sections(Metasync_Admin::$page_slug . '_general'); |
| 442 | 397 | ?> |
| 398 | + <p style="margin: 20px 0 0 0; font-size: 13px; color: var(--dashboard-text-secondary);"> | |
| 399 | + Breadcrumb settings now live on their own page: <a href="<?php echo esc_url(admin_url('admin.php?page=' . Metasync_Admin::$page_slug . '-breadcrumbs')); ?>">Breadcrumbs</a>. | |
| 400 | + </p> | |
| 443 | 401 | </div> |
| 444 | 402 | |
| 445 | 403 | <div class="dashboard-card"> |
| 446 | - <h2>Content Genius Synchronization</h2> | |
| 404 | + <h2>Content Genius Synchronization<?php Metasync::render_tooltip_icon('cg_sync_section', sprintf('Syncing sends this site\'s categories and authors to %s, so Content Genius can assign the right category and author when publishing articles to this site.', Metasync::get_effective_plugin_name())); ?></h2> | |
| 447 | 405 | <p style="color: var(--dashboard-text-secondary); margin-bottom: 20px;">Sync your categories and user/author data with <?php echo esc_html(Metasync::get_effective_plugin_name()); ?>.</p> |
| 448 | - <button type="button" class="button button-primary" id="sendAuthToken" data-toggle="tooltip" data-placement="top" title="Sync Categories and User"> | |
| 406 | + <button type="button" class="button button-primary" id="sendAuthToken"> | |
| 449 | 407 | Sync Now |
| 450 | 408 | </button> |
| 451 | 409 | </div> |
| 452 | 410 | |
| @@ -919,42 +877,8 @@ | ||
| 919 | 877 | $('#metasync-custom-modal').fadeOut(200); |
| 920 | 878 | } |
| 921 | 879 | }); |
| 922 | 880 | |
| 923 | - $('#metasync-export-whitelabel-btn').on('click', function(e) { | |
| 924 | - e.preventDefault(); | |
| 925 | - | |
| 926 | - var $button = $(this); | |
| 927 | - var originalText = $button.html(); | |
| 928 | - | |
| 929 | - $button.prop('disabled', true).html('⏳ Exporting...'); | |
| 930 | - | |
| 931 | - var form = $('<form>', { | |
| 932 | - 'method': 'POST', | |
| 933 | - 'action': '<?php echo esc_js(admin_url('admin-post.php')); ?>', | |
| 934 | - 'target': '_blank' | |
| 935 | - }); | |
| 936 | - | |
| 937 | - form.append($('<input>', { | |
| 938 | - 'type': 'hidden', | |
| 939 | - 'name': 'action', | |
| 940 | - 'value': 'metasync_export_whitelabel_settings' | |
| 941 | - })); | |
| 942 | - | |
| 943 | - form.append($('<input>', { | |
| 944 | - 'type': 'hidden', | |
| 945 | - 'name': '_wpnonce', | |
| 946 | - 'value': '<?php echo wp_create_nonce('metasync_export_whitelabel'); ?>' | |
| 947 | - })); | |
| 948 | - | |
| 949 | - $('body').append(form); | |
| 950 | - form.submit(); | |
| 951 | - | |
| 952 | - setTimeout(function() { | |
| 953 | - form.remove(); | |
| 954 | - $button.prop('disabled', false).html(originalText); | |
| 955 | - }, 2000); | |
| 956 | - }); | |
| 957 | 881 | }); |
| 958 | 882 | </script> |
| 959 | 883 | <?php |
| 960 | 884 | } elseif ($active_tab == 'advanced') { |
| @@ -984,10 +908,10 @@ | ||
| 984 | 908 | </div> |
| 985 | 909 | <?php endif; ?> |
| 986 | 910 | |
| 987 | 911 | <?php |
| 988 | - if (isset($_GET['debug_mode_enabled']) && $_GET['debug_mode_enabled'] == '1'): | |
| 989 | - $indefinite = isset($_GET['indefinite']) && $_GET['indefinite'] == '1'; | |
| 912 | + if (isset($_GET['debug_mode_enabled']) && $_GET['debug_mode_enabled'] == '1'): // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only result flag for a static notice | |
| 913 | + $indefinite = isset($_GET['indefinite']) && $_GET['indefinite'] == '1'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only result flag for a static notice | |
| 990 | 914 | ?> |
| 991 | 915 | <div class="notice notice-success inline" style="margin-bottom: 20px;"> |
| 992 | 916 | <p> |
| 993 | 917 | <strong>✅ Success!</strong> Debug mode has been enabled<?php echo $indefinite ? ' indefinitely' : ' for 24 hours'; ?>. |
| @@ -994,9 +918,9 @@ | ||
| 994 | 918 | </p> |
| 995 | 919 | </div> |
| 996 | 920 | <?php endif; ?> |
| 997 | 921 | |
| 998 | - <?php if (isset($_GET['debug_mode_disabled']) && $_GET['debug_mode_disabled'] == '1'): ?> | |
| 922 | + <?php if (isset($_GET['debug_mode_disabled']) && $_GET['debug_mode_disabled'] == '1'): // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only result flag for a static notice ?> | |
| 999 | 923 | <div class="notice notice-info inline" style="margin-bottom: 20px;"> |
| 1000 | 924 | <p> |
| 1001 | 925 | <strong>ℹ️ Debug Mode Disabled:</strong> Debug mode has been successfully disabled. |
| 1002 | 926 | </p> |
| @@ -1002,9 +926,9 @@ | ||
| 1002 | 926 | </p> |
| 1003 | 927 | </div> |
| 1004 | 928 | <?php endif; ?> |
| 1005 | 929 | |
| 1006 | - <?php if (isset($_GET['debug_mode_extended']) && $_GET['debug_mode_extended'] == '1'): ?> | |
| 930 | + <?php if (isset($_GET['debug_mode_extended']) && $_GET['debug_mode_extended'] == '1'): // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only result flag for a static notice ?> | |
| 1007 | 931 | <div class="notice notice-success inline" style="margin-bottom: 20px;"> |
| 1008 | 932 | <p> |
| 1009 | 933 | <strong>✅ Extended!</strong> Debug mode has been extended for another 24 hours. |
| 1010 | 934 | </p> |
| @@ -1010,9 +934,9 @@ | ||
| 1010 | 934 | </p> |
| 1011 | 935 | </div> |
| 1012 | 936 | <?php endif; ?> |
| 1013 | 937 | |
| 1014 | - <?php if (isset($_GET['debug_error']) && $_GET['debug_error'] == '1'): ?> | |
| 938 | + <?php if (isset($_GET['debug_error']) && $_GET['debug_error'] == '1'): // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only result flag for a static notice ?> | |
| 1015 | 939 | <div class="notice notice-error inline" style="margin-bottom: 20px;"> |
| 1016 | 940 | <p> |
| 1017 | 941 | <strong>❌ Error:</strong> Unable to perform the debug mode operation. Please try again. |
| 1018 | 942 | </p> |
| @@ -1193,22 +1117,22 @@ | ||
| 1193 | 1117 | var blockedClass = result.blocked ? 'blocked' : 'allowed'; |
| 1194 | 1118 | |
| 1195 | 1119 | html += '<div class="test-result-item ' + statusClass + '">'; |
| 1196 | 1120 | html += '<div class="test-result-header">'; |
| 1197 | - html += '<h4>' + statusIcon + ' ' + result.method + ' Request - ' + blockedStatus + '</h4>'; | |
| 1121 | + html += '<h4>' + statusIcon + ' ' + escapeHtml(result.method) + ' Request - ' + blockedStatus + '</h4>'; | |
| 1198 | 1122 | html += '<span class="test-status ' + blockedClass + '">' + blockedStatus + '</span>'; |
| 1199 | 1123 | html += '</div>'; |
| 1200 | 1124 | |
| 1201 | 1125 | html += '<div class="test-result-details">'; |
| 1202 | - html += '<p><strong>Response Time:</strong> ' + result.response_time + '</p>'; | |
| 1203 | - html += '<p><strong>Status:</strong> ' + result.status + '</p>'; | |
| 1126 | + html += '<p><strong>Response Time:</strong> ' + escapeHtml(result.response_time) + '</p>'; | |
| 1127 | + html += '<p><strong>Status:</strong> ' + escapeHtml(result.status) + '</p>'; | |
| 1204 | 1128 | |
| 1205 | 1129 | if (result.status_code) { |
| 1206 | - html += '<p><strong>HTTP Status Code:</strong> <span class="status-code">' + result.status_code + '</span></p>'; | |
| 1130 | + html += '<p><strong>HTTP Status Code:</strong> <span class="status-code">' + escapeHtml(result.status_code) + '</span></p>'; | |
| 1207 | 1131 | } |
| 1208 | 1132 | |
| 1209 | 1133 | if (result.error) { |
| 1210 | - html += '<p><strong>Error:</strong> <span class="error-message">' + result.error + '</span></p>'; | |
| 1134 | + html += '<p><strong>Error:</strong> <span class="error-message">' + escapeHtml(result.error) + '</span></p>'; | |
| 1211 | 1135 | } |
| 1212 | 1136 | |
| 1213 | 1137 | if (result.body) { |
| 1214 | 1138 | html += '<p><strong>Response Body:</strong></p>'; |
| @@ -1218,9 +1142,9 @@ | ||
| 1218 | 1142 | if (result.headers && Object.keys(result.headers).length > 0) { |
| 1219 | 1143 | html += '<p><strong>Response Headers:</strong></p>'; |
| 1220 | 1144 | html += '<pre class="response-headers">'; |
| 1221 | 1145 | Object.keys(result.headers).forEach(function(key) { |
| 1222 | - html += key + ': ' + result.headers[key] + '\n'; | |
| 1146 | + html += escapeHtml(key) + ': ' + escapeHtml(result.headers[key]) + '\n'; | |
| 1223 | 1147 | }); |
| 1224 | 1148 | html += '</pre>'; |
| 1225 | 1149 | } |
| 1226 | 1150 | |
| @@ -1233,9 +1157,9 @@ | ||
| 1233 | 1157 | html += '<p><strong>Parsed Response:</strong></p>'; |
| 1234 | 1158 | html += '<pre class="parsed-response">' + escapeHtml(JSON.stringify(result.parsed_response, null, 2)) + '</pre>'; |
| 1235 | 1159 | } |
| 1236 | 1160 | |
| 1237 | - html += '<p><strong>Details:</strong> ' + result.details + '</p>'; | |
| 1161 | + html += '<p><strong>Details:</strong> ' + escapeHtml(result.details) + '</p>'; | |
| 1238 | 1162 | html += '</div>'; |
| 1239 | 1163 | html += '</div>'; |
| 1240 | 1164 | }); |
| 1241 | 1165 | |
| @@ -1250,9 +1174,9 @@ | ||
| 1250 | 1174 | '>': '>', |
| 1251 | 1175 | '"': '"', |
| 1252 | 1176 | '\'': ''' |
| 1253 | 1177 | }; |
| 1254 | - return text.replace(/[&<>"']/g, function(m) { return map[m]; }); | |
| 1178 | + return String(text).replace(/[&<>"']/g, function(m) { return map[m]; }); | |
| 1255 | 1179 | } |
| 1256 | 1180 | }); |
| 1257 | 1181 | </script> |
| 1258 | 1182 | |
| @@ -1385,41 +1309,41 @@ | ||
| 1385 | 1309 | } |
| 1386 | 1310 | </style> |
| 1387 | 1311 | |
| 1388 | 1312 | <?php if ($active_tab === 'advanced'): ?> |
| 1389 | - <?php if (isset($_GET['settings_cleared']) && $_GET['settings_cleared'] == '1'): ?> | |
| 1313 | + <?php if (isset($_GET['settings_cleared']) && $_GET['settings_cleared'] == '1'): // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only result flag for a static notice ?> | |
| 1390 | 1314 | <div class="notice notice-success is-dismissible"> |
| 1391 | 1315 | <p><strong>✅ Success!</strong> All plugin settings have been cleared successfully and a new Plugin Auth Token has been generated. Please reconfigure the plugin as needed.</p> |
| 1392 | 1316 | </div> |
| 1393 | 1317 | <?php endif; ?> |
| 1394 | 1318 | |
| 1395 | - <?php if (isset($_GET['clear_settings_error']) && $_GET['clear_settings_error'] == '1'): ?> | |
| 1319 | + <?php if (isset($_GET['clear_settings_error']) && $_GET['clear_settings_error'] == '1'): // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only result flag for a static notice ?> | |
| 1396 | 1320 | <div class="notice notice-error is-dismissible"> |
| 1397 | 1321 | <p><strong>❌ Error!</strong> Failed to clear settings due to a security check failure. Please try again.</p> |
| 1398 | 1322 | </div> |
| 1399 | 1323 | <?php endif; ?> |
| 1400 | 1324 | |
| 1401 | - <?php if (isset($_GET['log_cleared']) && $_GET['log_cleared'] == '1'): ?> | |
| 1325 | + <?php if (isset($_GET['log_cleared']) && $_GET['log_cleared'] == '1'): // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only result flag for a static notice ?> | |
| 1402 | 1326 | <div class="notice notice-success is-dismissible"> |
| 1403 | 1327 | <p><strong>✅ Success!</strong> Error logs have been cleared successfully.</p> |
| 1404 | 1328 | </div> |
| 1405 | 1329 | <?php endif; ?> |
| 1406 | 1330 | |
| 1407 | - <?php if (isset($_GET['clear_error']) && $_GET['clear_error'] == '1'): ?> | |
| 1331 | + <?php if (isset($_GET['clear_error']) && $_GET['clear_error'] == '1'): // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only result flag for a static notice ?> | |
| 1408 | 1332 | <div class="notice notice-error is-dismissible"> |
| 1409 | 1333 | <p><strong>❌ Error!</strong> Failed to clear error logs due to a security check failure. Please try again.</p> |
| 1410 | 1334 | </div> |
| 1411 | 1335 | <?php endif; ?> |
| 1412 | 1336 | |
| 1413 | - <?php if (isset($_GET['access_roles_saved']) && $_GET['access_roles_saved'] == '1'): ?> | |
| 1337 | + <?php if (isset($_GET['access_roles_saved']) && $_GET['access_roles_saved'] == '1'): // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only result flag for a static notice ?> | |
| 1414 | 1338 | <div class="notice notice-success is-dismissible"> |
| 1415 | 1339 | <p><strong>✅ Success!</strong> Plugin access roles have been saved successfully.</p> |
| 1416 | 1340 | </div> |
| 1417 | 1341 | <?php endif; ?> |
| 1418 | 1342 | |
| 1419 | - <?php if (isset($_GET['access_roles_error']) && $_GET['access_roles_error'] == '1'): ?> | |
| 1343 | + <?php if (isset($_GET['access_roles_error']) && $_GET['access_roles_error'] == '1'): // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only result flag for a static notice ?> | |
| 1420 | 1344 | <div class="notice notice-error is-dismissible"> |
| 1421 | - <p><strong>❌ Error!</strong> Failed to save plugin access roles. <?php echo isset($_GET['message']) ? esc_html(urldecode($_GET['message'])) : 'Please try again.'; ?></p> | |
| 1345 | + <p><strong>❌ Error!</strong> Failed to save plugin access roles. <?php echo isset($_GET['message']) ? esc_html(urldecode($_GET['message'])) : 'Please try again.'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only error text, escaped on output ?></p> | |
| 1422 | 1346 | </div> |
| 1423 | 1347 | <?php endif; ?> |
| 1424 | 1348 | |
| 1425 | 1349 | <?php endif; ?> |
| @@ -1453,8 +1377,15 @@ | ||
| 1453 | 1377 | } |
| 1454 | 1378 | |
| 1455 | 1379 | public function create_admin_robots_txt_page() |
| 1456 | 1380 | { |
| 1381 | + // The form below rewrites the site's physical robots.txt — restrict | |
| 1382 | + // that to site admins, not just anyone who can open the page via | |
| 1383 | + // plugin_access_roles. The nonce is CSRF protection, not authorization. | |
| 1384 | + if (!empty($_POST) && !current_user_can('manage_options')) { | |
| 1385 | + wp_die(esc_html__('Sorry, you are not allowed to manage robots.txt settings.', 'metasync')); | |
| 1386 | + } | |
| 1387 | + | |
| 1457 | 1388 | ?> |
| 1458 | 1389 | <?php $this->admin->render_layout_open('Robots.txt', 'robots_txt', 'Control which pages search engines can crawl.'); ?> |
| 1459 | 1390 | |
| 1460 | 1391 | <?php |
| @@ -1499,9 +1430,11 @@ | ||
| 1499 | 1430 | echo '<div class="notice notice-error"><p>' . esc_html($current_content->get_error_message()) . '</p></div>'; |
| 1500 | 1431 | $current_content = ''; |
| 1501 | 1432 | } |
| 1502 | 1433 | |
| 1503 | - $backups = $robots_txt->get_backup_history(10); | |
| 1434 | + // First page of backups; the Backup History panel is paginated so the | |
| 1435 | + // list always reflects the full stored state and its true total. | |
| 1436 | + $backups = $robots_txt->get_backup_history(Metasync_Robots_Txt_Database::BACKUPS_PER_PAGE, 0); | |
| 1504 | 1437 | |
| 1505 | 1438 | $file_exists = $robots_txt->file_exists(); |
| 1506 | 1439 | $is_writable = $robots_txt->is_writable(); |
| 1507 | 1440 | |
| @@ -1515,82 +1448,8 @@ | ||
| 1515 | 1448 | { |
| 1516 | 1449 | require_once plugin_dir_path(dirname(__FILE__)) . 'views/metasync-report-issue.php'; |
| 1517 | 1450 | } |
| 1518 | 1451 | |
| 1519 | - public function create_admin_xml_sitemap_page() | |
| 1520 | - { | |
| 1521 | - require_once plugin_dir_path(dirname(__FILE__)) . 'sitemap/class-metasync-sitemap-generator.php'; | |
| 1522 | - | |
| 1523 | - $sitemap_generator = new Metasync_Sitemap_Generator(); | |
| 1524 | - | |
| 1525 | - if (isset($_POST['metasync_sitemap_nonce'])) { | |
| 1526 | - check_admin_referer('metasync_sitemap_action', 'metasync_sitemap_nonce'); | |
| 1527 | - | |
| 1528 | - if (isset($_POST['generate_sitemap'])) { | |
| 1529 | - $disabled_plugins = $sitemap_generator->disable_other_sitemap_generators(); | |
| 1530 | - | |
| 1531 | - $result = $sitemap_generator->generate_sitemap(); | |
| 1532 | - | |
| 1533 | - if (is_wp_error($result)) { | |
| 1534 | - error_log('[MetaSync] Sitemap generation failed: ' . $result->get_error_message()); | |
| 1535 | - echo '<div class="notice notice-error"><p>' . esc_html__('Sitemap generation failed. Please try again or check the error logs.', 'metasync') . '</p></div>'; | |
| 1536 | - } else { | |
| 1537 | - $message = esc_html__('Sitemap generated successfully!', 'metasync'); | |
| 1538 | - if ($disabled_plugins) { | |
| 1539 | - $message .= ' ' . esc_html__('Conflicting sitemap generators have been automatically disabled.', 'metasync'); | |
| 1540 | - } | |
| 1541 | - | |
| 1542 | - $robots_result = get_transient('metasync_sitemap_robots_updated'); | |
| 1543 | - if ($robots_result && $robots_result['success']) { | |
| 1544 | - if ($robots_result['action'] === 'added') { | |
| 1545 | - $message .= ' ' . esc_html__('Sitemap URL has been added to robots.txt.', 'metasync'); | |
| 1546 | - } elseif ($robots_result['action'] === 'updated') { | |
| 1547 | - $message .= ' ' . esc_html__('Sitemap URL has been updated in robots.txt.', 'metasync'); | |
| 1548 | - } elseif ($robots_result['action'] === 'created') { | |
| 1549 | - $message .= ' ' . esc_html__('robots.txt file has been created with sitemap URL.', 'metasync'); | |
| 1550 | - } | |
| 1551 | - delete_transient('metasync_sitemap_robots_updated'); | |
| 1552 | - } | |
| 1553 | - | |
| 1554 | - echo '<div class="notice notice-success"><p>' . esc_html($message) . '</p></div>'; | |
| 1555 | - } | |
| 1556 | - } elseif (isset($_POST['enable_auto_update'])) { | |
| 1557 | - update_option('metasync_sitemap_auto_update', true); | |
| 1558 | - $sitemap_generator->setup_auto_update_hooks(); | |
| 1559 | - echo '<div class="notice notice-success"><p>' . esc_html__('Auto-update enabled!', 'metasync') . '</p></div>'; | |
| 1560 | - } elseif (isset($_POST['disable_auto_update'])) { | |
| 1561 | - update_option('metasync_sitemap_auto_update', false); | |
| 1562 | - echo '<div class="notice notice-success"><p>' . esc_html__('Auto-update disabled!', 'metasync') . '</p></div>'; | |
| 1563 | - } elseif (isset($_POST['delete_sitemap'])) { | |
| 1564 | - $deleted = $sitemap_generator->delete_sitemap(); | |
| 1565 | - if ($deleted) { | |
| 1566 | - update_option('metasync_sitemap_auto_update', false); | |
| 1567 | - // Re-enable WP core sitemap so the site isn't left with zero sitemaps | |
| 1568 | - delete_option('metasync_disable_wp_sitemap'); | |
| 1569 | - echo '<div class="notice notice-success"><p>' . esc_html__('Sitemap deleted successfully!', 'metasync') . '</p></div>'; | |
| 1570 | - } else { | |
| 1571 | - echo '<div class="notice notice-error"><p>' . esc_html__('Failed to delete sitemap. The file may not exist or is not writable.', 'metasync') . '</p></div>'; | |
| 1572 | - } | |
| 1573 | - } elseif (isset($_POST['enable_other_sitemaps'])) { | |
| 1574 | - $enabled_plugins = $sitemap_generator->enable_other_sitemap_generators(); | |
| 1575 | - if ($enabled_plugins) { | |
| 1576 | - echo '<div class="notice notice-success"><p>' . esc_html__('Other sitemap plugins have been re-enabled successfully!', 'metasync') . '</p></div>'; | |
| 1577 | - } else { | |
| 1578 | - echo '<div class="notice notice-info"><p>' . esc_html__('No sitemap plugins were found to re-enable.', 'metasync') . '</p></div>'; | |
| 1579 | - } | |
| 1580 | - } | |
| 1581 | - } | |
| 1582 | - | |
| 1583 | - $sitemap_exists = $sitemap_generator->sitemap_exists(); | |
| 1584 | - $sitemap_url = $sitemap_generator->get_sitemap_url(); | |
| 1585 | - $url_count = $sitemap_generator->count_urls(); | |
| 1586 | - $last_generated = $sitemap_generator->get_last_generated_time(); | |
| 1587 | - $auto_update_enabled = get_option('metasync_sitemap_auto_update', false); | |
| 1588 | - $active_sitemap_plugins = $sitemap_generator->check_active_sitemap_plugins(); | |
| 1589 | - | |
| 1590 | - require_once plugin_dir_path(dirname(__FILE__)) . 'views/metasync-xml-sitemap.php'; | |
| 1591 | - } | |
| 1592 | - | |
| 1593 | 1452 | public function create_admin_custom_pages_page() |
| 1594 | 1453 | { |
| 1595 | 1454 | ?> |
| 1596 | 1455 | <?php $this->admin->render_layout_open('Custom Pages', 'custom_pages', 'Create blank canvas pages for Elementor, Divi, or Gutenberg.'); ?> |
| @@ -1641,12 +1500,14 @@ | ||
| 1641 | 1500 | } |
| 1642 | 1501 | |
| 1643 | 1502 | public function create_admin_breadcrumbs_page() |
| 1644 | 1503 | { |
| 1645 | - $page_slug = Metasync_Admin::$page_slug . '_breadcrumbs'; | |
| 1646 | 1504 | ?> |
| 1647 | 1505 | <?php $this->admin->render_layout_open('Breadcrumbs', 'breadcrumbs', 'Configure breadcrumb trail settings and placement.'); ?> |
| 1648 | 1506 | |
| 1507 | + <?php /* options.php redirects back here with ?settings-updated=true; without this call the save confirmation never prints */ ?> | |
| 1508 | + <?php settings_errors(); ?> | |
| 1509 | + | |
| 1649 | 1510 | <form method="post" action="options.php"> |
| 1650 | 1511 | <div class="dashboard-card"> |
| 1651 | 1512 | <h2>Breadcrumbs Settings</h2> |
| 1652 | 1513 | <p style="color: var(--dashboard-text-secondary); margin-bottom: 20px;">Configure how breadcrumb trails are displayed across your site.</p> |
| @@ -1651,9 +1512,9 @@ | ||
| 1651 | 1512 | <h2>Breadcrumbs Settings</h2> |
| 1652 | 1513 | <p style="color: var(--dashboard-text-secondary); margin-bottom: 20px;">Configure how breadcrumb trails are displayed across your site.</p> |
| 1653 | 1514 | <?php |
| 1654 | 1515 | settings_fields(Metasync_Admin::option_group); |
| 1655 | - do_settings_sections($page_slug); | |
| 1516 | + Metasync_Settings_Fields::instance()->render_breadcrumbs_section(); | |
| 1656 | 1517 | submit_button(); |
| 1657 | 1518 | ?> |
| 1658 | 1519 | </div> |
| 1659 | 1520 | </form> |
| @@ -1775,14 +1636,8 @@ | ||
| 1775 | 1636 | <?php $this->admin->render_layout_close(); ?> |
| 1776 | 1637 | <?php |
| 1777 | 1638 | } |
| 1778 | 1639 | |
| 1779 | - public function create_admin_google_instant_index_page() | |
| 1780 | - { | |
| 1781 | - // Delegates to the admin class which uses the shared credentials view | |
| 1782 | - $this->admin->create_admin_google_instant_index_page(); | |
| 1783 | - } | |
| 1784 | - | |
| 1785 | 1640 | public function create_admin_google_console_page() |
| 1786 | 1641 | { |
| 1787 | 1642 | $this->admin->render_layout_open('Google Console', 'google_console', 'View Google Search Console data and manage indexing requests.'); |
| 1788 | 1643 | $google = function_exists('google_index_direct') ? google_index_direct() : null; |
| @@ -1809,33 +1664,8 @@ | ||
| 1809 | 1664 | <?php $this->admin->render_layout_close(); ?> |
| 1810 | 1665 | <?php |
| 1811 | 1666 | } |
| 1812 | 1667 | |
| 1813 | - public function create_admin_optimal_settings_page() | |
| 1814 | - { | |
| 1815 | - ?> | |
| 1816 | - <?php $this->admin->render_layout_open('Optimal Settings', 'optimal_settings', 'Apply recommended SEO settings automatically.'); ?> | |
| 1817 | - | |
| 1818 | - <div class="dashboard-card"> | |
| 1819 | - <h2>Site Compatibility Status</h2> | |
| 1820 | - <p style="color: var(--dashboard-text-secondary); margin-bottom: 20px;">Check your site's compatibility with optimal <?php echo esc_html(Metasync::get_effective_plugin_name()); ?> settings.</p> | |
| 1821 | - <?php | |
| 1822 | - $optimal_settings = new Metasync_Optimal_Settings(); | |
| 1823 | - $optimal_settings->site_compatible_status_view(); | |
| 1824 | - ?> | |
| 1825 | - </div> | |
| 1826 | - | |
| 1827 | - <div class="dashboard-card"> | |
| 1828 | - <h2>Optimization Settings</h2> | |
| 1829 | - <p style="color: var(--dashboard-text-secondary); margin-bottom: 20px;">Configure optimization settings for best performance.</p> | |
| 1830 | - <?php | |
| 1831 | - $this->optimization_settings_options(); | |
| 1832 | - ?> | |
| 1833 | - </div> | |
| 1834 | - <?php $this->admin->render_layout_close(); ?> | |
| 1835 | - <?php | |
| 1836 | - } | |
| 1837 | - | |
| 1838 | 1668 | public function create_admin_global_settings_page() |
| 1839 | 1669 | { |
| 1840 | 1670 | $page_slug = Metasync_Admin::$page_slug . '_common-settings'; |
| 1841 | 1671 | ?> |
| @@ -1930,21 +1760,9 @@ | ||
| 1930 | 1760 | <?php $this->admin->render_layout_close(); ?> |
| 1931 | 1761 | <?php |
| 1932 | 1762 | } |
| 1933 | 1763 | |
| 1934 | - public function optimization_settings_options() | |
| 1935 | - { | |
| 1936 | - $page_slug = Metasync_Admin::$page_slug . '_optimal-settings'; | |
| 1937 | - $site_info_slug = Metasync_Admin::$page_slug . '_site-info-settings'; | |
| 1938 | 1764 | |
| 1939 | - printf('<form method="post" action="options.php">'); | |
| 1940 | - settings_fields(Metasync_Admin::option_group); | |
| 1941 | - do_settings_sections($page_slug); | |
| 1942 | - do_settings_sections($site_info_slug); | |
| 1943 | - submit_button(); | |
| 1944 | - printf('</form>'); | |
| 1945 | - } | |
| 1946 | - | |
| 1947 | 1765 | public function create_admin_error_logs_page() |
| 1948 | 1766 | { |
| 1949 | 1767 | ?> |
| 1950 | 1768 | <?php $this->admin->render_layout_open('Error Logs', 'general', ''); ?> |
| @@ -1986,177 +1804,15 @@ | ||
| 1986 | 1804 | <?php $this->admin->render_layout_close(); ?> |
| 1987 | 1805 | <?php |
| 1988 | 1806 | } |
| 1989 | 1807 | |
| 1990 | - public function create_admin_sync_log_page() | |
| 1991 | - { | |
| 1992 | - $sync_db = new Metasync_Sync_History_Database(); | |
| 1993 | - | |
| 1994 | - if (wp_doing_ajax()) { | |
| 1995 | - $this->handle_sync_log_ajax(); | |
| 1996 | - return; | |
| 1997 | - } | |
| 1998 | - | |
| 1999 | - $page = isset($_GET['paged']) ? max(1, intval($_GET['paged'])) : 1; | |
| 2000 | - $per_page = 10; | |
| 2001 | - $offset = ($page - 1) * $per_page; | |
| 2002 | - | |
| 2003 | - $filters = [ | |
| 2004 | - 'date_range' => isset($_GET['date_range']) ? sanitize_text_field($_GET['date_range']) : '', | |
| 2005 | - 'status' => isset($_GET['status']) ? sanitize_text_field($_GET['status']) : '', | |
| 2006 | - ]; | |
| 1808 | + // NOTE: The Changes Log (sync log) page is rendered by | |
| 1809 | + // Metasync_Admin::create_admin_sync_log_page() in | |
| 1810 | + // admin/class-metasync-admin.php, which is the callback registered in | |
| 1811 | + // class-metasync-admin-navigation.php. A former duplicate of that method | |
| 1812 | + // lived here but was never wired to a menu and has been removed to avoid | |
| 1813 | + // drift. | |
| 2007 | 1814 | |
| 2008 | - $date_range = $filters['date_range']; | |
| 2009 | - $wp_now_ts = current_time('timestamp'); | |
| 2010 | - $date_from = ''; | |
| 2011 | - $date_to = ''; | |
| 2012 | - | |
| 2013 | - if (!empty($date_range)) { | |
| 2014 | - $date_to = date('Y-m-d H:i:s', $wp_now_ts); | |
| 2015 | - | |
| 2016 | - if ($date_range === 'today') { | |
| 2017 | - $start_ts = strtotime('today', $wp_now_ts); | |
| 2018 | - $date_from = date('Y-m-d H:i:s', $start_ts); | |
| 2019 | - } elseif ($date_range === 'yesterday') { | |
| 2020 | - $start_ts = strtotime('yesterday', $wp_now_ts); | |
| 2021 | - $end_ts = strtotime('today', $wp_now_ts) - 1; | |
| 2022 | - $date_from = date('Y-m-d H:i:s', $start_ts); | |
| 2023 | - $date_to = date('Y-m-d H:i:s', $end_ts); | |
| 2024 | - } elseif ($date_range === 'this_week') { | |
| 2025 | - $start_of_week = (int) get_option('start_of_week', 1); | |
| 2026 | - $day_of_week = (int) date('w', $wp_now_ts); | |
| 2027 | - $delta_days = ($day_of_week - $start_of_week + 7) % 7; | |
| 2028 | - $start_ts = strtotime('-' . $delta_days . ' days', strtotime('today', $wp_now_ts)); | |
| 2029 | - $date_from = date('Y-m-d H:i:s', $start_ts); | |
| 2030 | - } elseif ($date_range === 'this_month') { | |
| 2031 | - $start_ts = strtotime(date('Y-m-01 00:00:00', $wp_now_ts)); | |
| 2032 | - $date_from = date('Y-m-d H:i:s', $start_ts); | |
| 2033 | - } elseif ($date_range === 'all') { | |
| 2034 | - // no bounds | |
| 2035 | - } | |
| 2036 | - } | |
| 2037 | - | |
| 2038 | - if (!empty($date_from)) { | |
| 2039 | - $filters['date_from'] = $date_from; | |
| 2040 | - } | |
| 2041 | - if (!empty($date_to)) { | |
| 2042 | - $filters['date_to'] = $date_to; | |
| 2043 | - } | |
| 2044 | - | |
| 2045 | - $filters = array_filter($filters); | |
| 2046 | - | |
| 2047 | - $sync_records = $sync_db->getAllRecords($per_page, $offset, $filters); | |
| 2048 | - $total_records = $sync_db->get_count($filters); | |
| 2049 | - $total_pages = ceil($total_records / $per_page); | |
| 2050 | - | |
| 2051 | - $stats = $sync_db->get_statistics(); | |
| 2052 | - | |
| 2053 | - ?> | |
| 2054 | - <?php $this->admin->render_layout_open('Changes Log', 'sync_log', 'Track all SEO changes made by the plugin.'); ?> | |
| 2055 | - | |
| 2056 | - <div class="dashboard-card"> | |
| 2057 | - <div class="sync-log-header"> | |
| 2058 | - <div class="sync-log-title-section"> | |
| 2059 | - <h2>Changes Log</h2> | |
| 2060 | - <p style="color: var(--dashboard-text-secondary); margin-bottom: 0;">Recent content synchronizations from external tools.</p> | |
| 2061 | - </div> | |
| 2062 | - | |
| 2063 | - <!-- Filters - Right aligned --> | |
| 2064 | - <div class="sync-log-filters"> | |
| 2065 | - <form method="get" class="sync-filters-form" onchange="this.submit()" style="display:flex;flex-direction:row;align-items:center;gap:12px;flex-wrap:nowrap;"> | |
| 2066 | - <input type="hidden" name="page" value="<?php echo esc_attr($_GET['page']); ?>"> | |
| 2067 | - | |
| 2068 | - <select name="date_range" class="sync-filter-select"> | |
| 2069 | - <option value="all" <?php selected($filters['date_range'] ?? 'all', 'all'); ?>> All Time</option> | |
| 2070 | - <option value="today" <?php selected($filters['date_range'] ?? '', 'today'); ?>>Today</option> | |
| 2071 | - <option value="yesterday" <?php selected($filters['date_range'] ?? '', 'yesterday'); ?>>Yesterday</option> | |
| 2072 | - <option value="this_week" <?php selected($filters['date_range'] ?? '', 'this_week'); ?>>This week</option> | |
| 2073 | - <option value="this_month" <?php selected($filters['date_range'] ?? '', 'this_month'); ?>>This month</option> | |
| 2074 | - </select> | |
| 2075 | - | |
| 2076 | - <select name="status" class="sync-filter-select"> | |
| 2077 | - <option value="" <?php selected($filters['status'] ?? '', ''); ?>>Status Filter</option> | |
| 2078 | - <option value="published" <?php selected($filters['status'] ?? '', 'published'); ?>>Published</option> | |
| 2079 | - <option value="draft" <?php selected($filters['status'] ?? '', 'draft'); ?>>Draft</option> | |
| 2080 | - </select> | |
| 2081 | - </form> | |
| 2082 | - </div> | |
| 2083 | - </div> | |
| 2084 | - | |
| 2085 | - <!-- Sync History List --> | |
| 2086 | - <div class="sync-log-list"> | |
| 2087 | - <?php if (empty($sync_records)): ?> | |
| 2088 | - <div class="sync-log-empty"> | |
| 2089 | - <div class="sync-log-empty-icon"><span class="dashicons dashicons-list-view" style="font-size:48px;width:48px;height:48px;color:var(--dashboard-text-secondary);"></span></div> | |
| 2090 | - <h3>No sync records found</h3> | |
| 2091 | - <p>Sync records will appear here when content/pages receive new updates.</p> | |
| 2092 | - </div> | |
| 2093 | - <?php else: ?> | |
| 2094 | - <?php foreach ($sync_records as $record): ?> | |
| 2095 | - <div class="sync-log-item"> | |
| 2096 | - <div class="sync-log-icon"> | |
| 2097 | - <div class="sync-icon-circle"> | |
| 2098 | - <span class="dashicons dashicons-media-default sync-icon"></span> | |
| 2099 | - </div> | |
| 2100 | - </div> | |
| 2101 | - | |
| 2102 | - <div class="sync-log-content"> | |
| 2103 | - <div class="sync-log-title"><?php echo esc_html($record->title); ?> | |
| 2104 | - <?php if (!empty($record->url)): ?> | |
| 2105 | - <a href="<?php echo esc_url($record->url); ?>" target="_blank" rel="noopener" title="Open URL" style="margin-left:8px; text-decoration:none;"><span class="dashicons dashicons-external" style="font-size:14px;width:14px;height:14px;vertical-align:middle;"></span></a> | |
| 2106 | - <?php endif; ?> | |
| 2107 | - </div> | |
| 2108 | - <div class="sync-log-meta"> | |
| 2109 | - <?php echo esc_html( $this->time_elapsed_string($record->created_at) ); ?> | |
| 2110 | - </div> | |
| 2111 | - </div> | |
| 2112 | - | |
| 2113 | - <div class="sync-log-status"> | |
| 2114 | - <?php if ($record->status === 'published' || $record->status === 'publish'): ?> | |
| 2115 | - <span class="sync-status-badge sync-status-published"> | |
| 2116 | - <span class="sync-status-icon">✓</span> | |
| 2117 | - Published | |
| 2118 | - </span> | |
| 2119 | - <?php else: ?> | |
| 2120 | - <span class="sync-status-badge sync-status-draft"> | |
| 2121 | - <span class="sync-status-icon">i</span> | |
| 2122 | - Draft | |
| 2123 | - </span> | |
| 2124 | - <?php endif; ?> | |
| 2125 | - </div> | |
| 2126 | - </div> | |
| 2127 | - <?php endforeach; ?> | |
| 2128 | - <?php endif; ?> | |
| 2129 | - </div> | |
| 2130 | - | |
| 2131 | - <!-- Pagination --> | |
| 2132 | - <?php if ($total_pages > 1): ?> | |
| 2133 | - <div class="sync-log-pagination"> | |
| 2134 | - <div class="sync-log-pagination-info"> | |
| 2135 | - Total records: <?php echo intval( $total_records ); ?> | Showing <?php echo intval( $offset ) + 1; ?>-<?php echo intval( min($offset + $per_page, $total_records) ); ?> | |
| 2136 | - </div> | |
| 2137 | - | |
| 2138 | - <div class="sync-log-pagination-controls"> | |
| 2139 | - <?php if ($page > 1): ?> | |
| 2140 | - <a href="?page=<?php echo esc_attr($_GET['page']); ?>&paged=<?php echo intval( $page ) - 1; ?><?php echo esc_html( $this->build_filter_query_string($filters) ); ?>" class="sync-pagination-btn">‹</a> | |
| 2141 | - <?php endif; ?> | |
| 2142 | - | |
| 2143 | - <?php for ($i = max(1, $page - 2); $i <= min($total_pages, $page + 2); $i++): ?> | |
| 2144 | - <a href="?page=<?php echo esc_attr($_GET['page']); ?>&paged=<?php echo intval( $i ); ?><?php echo esc_html( $this->build_filter_query_string($filters) ); ?>" | |
| 2145 | - class="sync-pagination-btn <?php echo $i === $page ? 'active' : ''; ?>"><?php echo intval( $i ); ?></a> | |
| 2146 | - <?php endfor; ?> | |
| 2147 | - | |
| 2148 | - <?php if ($page < $total_pages): ?> | |
| 2149 | - <a href="?page=<?php echo esc_attr($_GET['page']); ?>&paged=<?php echo intval( $page ) + 1; ?><?php echo esc_html( $this->build_filter_query_string($filters) ); ?>" class="sync-pagination-btn">›</a> | |
| 2150 | - <?php endif; ?> | |
| 2151 | - </div> | |
| 2152 | - </div> | |
| 2153 | - <?php endif; ?> | |
| 2154 | - </div> | |
| 2155 | - <?php $this->admin->render_layout_close(); ?> | |
| 2156 | - <?php | |
| 2157 | - } | |
| 2158 | - | |
| 2159 | 1815 | public function creat_error_Logs_List() |
| 2160 | 1816 | { |
| 2161 | 1817 | // printf('<h1> Error Logs </h1>'); |
| 2162 | 1818 | // $error_log = new Metasync_Error_Logs_Table($this->data_error_log_list); |
| @@ -2185,59 +1841,11 @@ | ||
| 2185 | 1841 | require_once plugin_dir_path(dirname(__FILE__)) . 'views/metasync-otto-bot-statistics.php'; |
| 2186 | 1842 | } |
| 2187 | 1843 | |
| 2188 | 1844 | // ------------------------------------------------------------------ |
| 2189 | - // Private helpers (copied from Metasync_Admin, used only by pages above) | |
| 1845 | + // Private helpers | |
| 2190 | 1846 | // ------------------------------------------------------------------ |
| 2191 | - | |
| 2192 | - private function time_elapsed_string($datetime, $full = false) | |
| 2193 | - { | |
| 2194 | - if(empty($datetime)){ | |
| 2195 | - return ""; | |
| 2196 | - } | |
| 2197 | - # Stored timestamps use current_time('mysql') which is WP local time | |
| 2198 | - # with no timezone marker. Defaulting DateTime to UTC produces a diff | |
| 2199 | - # equal to the WP timezone offset (QA: "4 hours ago" after a | |
| 2200 | - # 4-minute sync on non-UTC sites). | |
| 2201 | - $wp_tz = function_exists('wp_timezone') ? wp_timezone() : new DateTimeZone('UTC'); | |
| 2202 | - $now = new DateTime('now', $wp_tz); | |
| 2203 | - $ago = new DateTime($datetime, $wp_tz); | |
| 2204 | - | |
| 2205 | - $diff = $now->diff($ago); | |
| 2206 | - | |
| 2207 | - $string = [ | |
| 2208 | - 'y' => 'year', | |
| 2209 | - 'm' => 'month', | |
| 2210 | - 'w' => 'week', | |
| 2211 | - 'd' => 'day', | |
| 2212 | - 'h' => 'hour', | |
| 2213 | - 'i' => 'minute', | |
| 2214 | - 's' => 'second', | |
| 2215 | - ]; | |
| 2216 | - | |
| 2217 | - foreach ($string as $k => &$v) { | |
| 2218 | - if (isset($diff->$k) && $diff->$k) { | |
| 2219 | - $v = $diff->$k . ' ' . $v . ($diff->$k > 1 ? 's' : ''); | |
| 2220 | - } else { | |
| 2221 | - unset($string[$k]); | |
| 2222 | - } | |
| 2223 | - } | |
| 2224 | - if (!$full) $string = array_slice($string, 0, 1); | |
| 2225 | - return $string ? implode(', ', $string) . ' ago' : 'just now'; | |
| 2226 | - } | |
| 2227 | - | |
| 2228 | - private function build_filter_query_string($filters) | |
| 2229 | - { | |
| 2230 | - $query_parts = []; | |
| 2231 | - foreach ($filters as $key => $value) { | |
| 2232 | - if (!empty($value)) { | |
| 2233 | - $query_parts[] = $key . '=' . urlencode($value); | |
| 2234 | - } | |
| 2235 | - } | |
| 2236 | - return !empty($query_parts) ? '&' . implode('&', $query_parts) : ''; | |
| 2237 | - } | |
| 2238 | - | |
| 2239 | - private function handle_sync_log_ajax() | |
| 2240 | - { | |
| 2241 | - wp_die(); | |
| 2242 | - } | |
| 1847 | + // The former time_elapsed_string / build_filter_query_string / | |
| 1848 | + // handle_sync_log_ajax helpers here were only used by the dead | |
| 1849 | + // create_admin_sync_log_page() duplicate that has since been removed. The | |
| 1850 | + // live equivalents live on Metasync_Admin. | |
| 2243 | 1851 | } |