| 1 |
<?php |
| 2 |
/** |
| 3 |
* Unified "SEO Suite" meta box. |
| 4 |
* |
| 5 |
* Consolidates MetaSync's separate Classic-editor meta boxes (SEO, Robots, |
| 6 |
* Canonical, Redirection, Social & Open Graph, Schema, Video Sitemap) into a |
| 7 |
* single tabbed box. Classic editor only — the block editor keeps its own SEO |
| 8 |
* sidebar and is left untouched. |
| 9 |
* |
| 10 |
* Presentation-only merge: this class does NOT reimplement any save logic. It |
| 11 |
* runs after MetaSync registers its own boxes, captures their render callbacks, |
| 12 |
* removes them from display, and renders the same fields (identical name/nonce |
| 13 |
* attributes) inside one tabbed container. The plugin's existing save_post |
| 14 |
* handlers persist everything unchanged. Schema is rendered via MetaSync's own |
| 15 |
* builder callback. Custom HTML settings stay in their standalone box. |
| 16 |
* |
| 17 |
* On LPS / custom-HTML pages (metasync_is_custom_or_lps_page) the box shows a |
| 18 |
* read-only notice and emits no nonces, so nothing here overwrites the |
| 19 |
* externally-managed SEO for those pages. |
| 20 |
* |
| 21 |
* @package Metasync |
| 22 |
*/ |
| 23 |
|
| 24 |
if (!defined('ABSPATH')) { |
| 25 |
exit; |
| 26 |
} |
| 27 |
|
| 28 |
class Metasync_Seo_Suite |
| 29 |
{ |
| 30 |
/** Original MetaSync meta-box IDs this box absorbs (Custom HTML is intentionally excluded). */ |
| 31 |
private $target_ids = array( |
| 32 |
'metasync-seo-meta', |
| 33 |
'metasync-seo-lps-notice', |
| 34 |
'common-robots-meta', |
| 35 |
'advance-robots-meta', |
| 36 |
'post-canonical-meta', |
| 37 |
'post-redirection-meta', |
| 38 |
'metasync_opengraph_meta_box', |
| 39 |
'metasync-schema-markup', |
| 40 |
'metasync-video-sitemap-meta', |
| 41 |
); |
| 42 |
|
| 43 |
/** @var array<string,bool> Which target boxes were present on the current screen. */ |
| 44 |
private $present = array(); |
| 45 |
|
| 46 |
/** @var array|null Captured Schema meta-box definition (rendered inside the Schema tab). */ |
| 47 |
private $schema_box = null; |
| 48 |
|
| 49 |
public function __construct() |
| 50 |
{ |
| 51 |
add_action('add_meta_boxes', array($this, 'unify'), 9999, 2); |
| 52 |
add_action('admin_enqueue_scripts', array($this, 'enqueue_assets')); |
| 53 |
} |
| 54 |
|
| 55 |
/** Load the media library for the OG/Twitter image pickers. */ |
| 56 |
public function enqueue_assets($hook) |
| 57 |
{ |
| 58 |
if (in_array($hook, array('post.php', 'post-new.php'), true)) { |
| 59 |
wp_enqueue_media(); |
| 60 |
} |
| 61 |
} |
| 62 |
|
| 63 |
/** |
| 64 |
* True for any request originating from the block editor. |
| 65 |
* |
| 66 |
* The block editor renders its meta-box area during the main page load |
| 67 |
* (is_block_editor() is true there) and re-posts that same form to |
| 68 |
* post.php?meta-box-loader=1 when saving. Both are treated as block-editor |
| 69 |
* context so this box never engages in either. |
| 70 |
*/ |
| 71 |
private function is_block_editor_request() |
| 72 |
{ |
| 73 |
if (!empty($_REQUEST['meta-box-loader'])) { |
| 74 |
return true; |
| 75 |
} |
| 76 |
$screen = get_current_screen(); |
| 77 |
return $screen && $screen->is_block_editor(); |
| 78 |
} |
| 79 |
|
| 80 |
/** |
| 81 |
* Runs after MetaSync registers its boxes (default priority). Captures the |
| 82 |
* target boxes, removes them from display, and registers the unified box. |
| 83 |
*/ |
| 84 |
public function unify($post_type, $post) |
| 85 |
{ |
| 86 |
/** Allow sites to opt out of the unified box and keep the classic separate boxes. */ |
| 87 |
if (!apply_filters('metasync_enable_seo_suite', true, $post_type, $post)) { |
| 88 |
return; |
| 89 |
} |
| 90 |
|
| 91 |
// Classic editor only. In the block editor the plugin's own SEO sidebar owns |
| 92 |
// these fields, and the SEO box is registered __back_compat_meta_box so it |
| 93 |
// never renders there at all. Returning before any remove_meta_box() call |
| 94 |
// leaves the block editor byte-for-byte as it is without this class. |
| 95 |
if ($this->is_block_editor_request()) { |
| 96 |
return; |
| 97 |
} |
| 98 |
|
| 99 |
global $wp_meta_boxes; |
| 100 |
if (empty($wp_meta_boxes[$post_type])) { |
| 101 |
return; |
| 102 |
} |
| 103 |
|
| 104 |
$this->present = array(); |
| 105 |
$this->schema_box = null; |
| 106 |
|
| 107 |
foreach ($wp_meta_boxes[$post_type] as $context => $priorities) { |
| 108 |
foreach ((array) $priorities as $boxes) { |
| 109 |
if (!is_array($boxes)) { |
| 110 |
continue; |
| 111 |
} |
| 112 |
foreach ($boxes as $box_id => $box) { |
| 113 |
if (in_array($box_id, $this->target_ids, true) && $box && !empty($box['callback'])) { |
| 114 |
$this->present[$box_id] = true; |
| 115 |
if ($box_id === 'metasync-schema-markup') { |
| 116 |
$this->schema_box = $box; |
| 117 |
} |
| 118 |
} |
| 119 |
} |
| 120 |
} |
| 121 |
foreach ($this->target_ids as $id) { |
| 122 |
remove_meta_box($id, $post_type, $context); |
| 123 |
} |
| 124 |
} |
| 125 |
|
| 126 |
if (empty($this->present)) { |
| 127 |
return; |
| 128 |
} |
| 129 |
|
| 130 |
if (empty($wp_meta_boxes[$post_type]['normal']['high']['metasync_seo_suite'])) { |
| 131 |
$plugin_name = class_exists('Metasync') ? Metasync::get_effective_plugin_name() : 'MetaSync'; |
| 132 |
add_meta_box( |
| 133 |
'metasync_seo_suite', |
| 134 |
sprintf('SEO Suite by %s', $plugin_name), |
| 135 |
array($this, 'render'), |
| 136 |
$post_type, |
| 137 |
'normal', |
| 138 |
'high' |
| 139 |
); |
| 140 |
} |
| 141 |
} |
| 142 |
|
| 143 |
/** True when the page's front-end output bypasses WordPress SEO (LPS / custom-HTML). */ |
| 144 |
private function is_managed_page($post_id) |
| 145 |
{ |
| 146 |
if (function_exists('metasync_is_custom_or_lps_page') && $post_id > 0 && metasync_is_custom_or_lps_page($post_id)) { |
| 147 |
return true; |
| 148 |
} |
| 149 |
// Fallbacks if the helper isn't loaded on this request. |
| 150 |
if (get_post_meta($post_id, '_metasync_lps_import', true)) { |
| 151 |
return true; |
| 152 |
} |
| 153 |
if (get_post_meta($post_id, '_metasync_is_custom_html_page', true) === '1' |
| 154 |
&& get_post_meta($post_id, '_metasync_raw_html_enabled', true) === '1') { |
| 155 |
return true; |
| 156 |
} |
| 157 |
return false; |
| 158 |
} |
| 159 |
|
| 160 |
private static function v($post_id, $key) |
| 161 |
{ |
| 162 |
$value = get_post_meta($post_id, $key, true); |
| 163 |
return is_array($value) ? '' : (string) $value; |
| 164 |
} |
| 165 |
|
| 166 |
private static function checked_attr($cond) |
| 167 |
{ |
| 168 |
return $cond ? ' checked' : ''; |
| 169 |
} |
| 170 |
|
| 171 |
/** A clean, "pretty" permalink for placeholders/preview (avoids ?p=ID on drafts). */ |
| 172 |
private static function pretty_permalink($post) |
| 173 |
{ |
| 174 |
$link = get_permalink($post->ID); |
| 175 |
if ($link |
| 176 |
&& strpos($link, '?p=') === false |
| 177 |
&& strpos($link, '?page_id=') === false |
| 178 |
&& strpos($link, 'preview=') === false) { |
| 179 |
return $link; |
| 180 |
} |
| 181 |
$slug = $post->post_name ? $post->post_name : sanitize_title(get_the_title($post->ID)); |
| 182 |
if (!$slug) { |
| 183 |
$slug = 'your-post'; |
| 184 |
} |
| 185 |
return user_trailingslashit(home_url('/' . $slug . '/')); |
| 186 |
} |
| 187 |
|
| 188 |
/** |
| 189 |
* Render the unified box. |
| 190 |
*/ |
| 191 |
public function render($post) |
| 192 |
{ |
| 193 |
$P = $this->present; |
| 194 |
$id = $post->ID; |
| 195 |
$a = 'esc_attr'; |
| 196 |
|
| 197 |
$managed = $this->is_managed_page($id); |
| 198 |
|
| 199 |
$has_seo = isset($P['metasync-seo-meta']) || isset($P['metasync-seo-lps-notice']); |
| 200 |
$has_crob = isset($P['common-robots-meta']); |
| 201 |
$has_arob = isset($P['advance-robots-meta']); |
| 202 |
$has_robots = $has_crob || $has_arob; |
| 203 |
$has_canon = isset($P['post-canonical-meta']); |
| 204 |
$has_redir = isset($P['post-redirection-meta']); |
| 205 |
$has_social = isset($P['metasync_opengraph_meta_box']); |
| 206 |
$has_schema = isset($P['metasync-schema-markup']); |
| 207 |
$has_video = isset($P['metasync-video-sitemap-meta']); |
| 208 |
|
| 209 |
// Current values. |
| 210 |
$seo_title = self::v($id, '_metasync_seo_title'); |
| 211 |
$seo_desc = self::v($id, '_metasync_seo_desc'); |
| 212 |
$otto_title = self::v($id, '_metasync_otto_title'); |
| 213 |
$otto_desc = self::v($id, '_metasync_otto_description'); |
| 214 |
$otto_kw = self::v($id, '_metasync_otto_keywords'); |
| 215 |
|
| 216 |
// Robots: post meta first, falling back to the site-wide defaults exactly as |
| 217 |
// the standalone Common/Advance Robots boxes do (new option spelling first, |
| 218 |
// then the legacy "mata" spelling). |
| 219 |
$cr = get_post_meta($id, 'metasync_common_robots', true); |
| 220 |
if (!$cr && class_exists('Metasync')) { |
| 221 |
$cr = Metasync::get_option('common_robots_meta') ?? Metasync::get_option('common_robots_mata') ?? ''; |
| 222 |
} |
| 223 |
if (!is_array($cr)) { |
| 224 |
$cr = array(); |
| 225 |
} |
| 226 |
$ar = get_post_meta($id, 'metasync_advance_robots', true); |
| 227 |
if (!$ar && class_exists('Metasync')) { |
| 228 |
$ar = Metasync::get_option('advance_robots_meta') ?? Metasync::get_option('advance_robots_mata') ?? ''; |
| 229 |
} |
| 230 |
if (!is_array($ar)) { |
| 231 |
$ar = array(); |
| 232 |
} |
| 233 |
$ar_snip_e = isset($ar['max-snippet']['enable']) ? $ar['max-snippet']['enable'] : ''; |
| 234 |
$ar_snip_l = isset($ar['max-snippet']['length']) ? $ar['max-snippet']['length'] : ''; |
| 235 |
$ar_vid_e = isset($ar['max-video-preview']['enable']) ? $ar['max-video-preview']['enable'] : ''; |
| 236 |
$ar_vid_l = isset($ar['max-video-preview']['length']) ? $ar['max-video-preview']['length'] : ''; |
| 237 |
$ar_img_e = isset($ar['max-image-preview']['enable']) ? $ar['max-image-preview']['enable'] : ''; |
| 238 |
$ar_img_l = isset($ar['max-image-preview']['length']) ? $ar['max-image-preview']['length'] : ''; |
| 239 |
|
| 240 |
// Canonical: same sanitise-and-repair path as the standalone Canonical box. |
| 241 |
// A bare reset() here would re-corrupt nested-array rows to the string "Array". |
| 242 |
$raw_canonical = get_post_meta($id, 'meta_canonical', true); |
| 243 |
if (class_exists('Metasync_Canonical_Sanitizer')) { |
| 244 |
$canon = Metasync_Canonical_Sanitizer::sanitize($raw_canonical); |
| 245 |
if (is_array($raw_canonical) || Metasync_Canonical_Sanitizer::is_corrupted($raw_canonical)) { |
| 246 |
if ($canon !== '') { |
| 247 |
update_post_meta($id, 'meta_canonical', $canon); |
| 248 |
} else { |
| 249 |
delete_post_meta($id, 'meta_canonical'); |
| 250 |
} |
| 251 |
} elseif ($canon === '' && is_string($raw_canonical) && trim($raw_canonical) !== '') { |
| 252 |
// Stored value the validator doesn't recognise: show it as-is so a |
| 253 |
// routine post save doesn't silently wipe it. |
| 254 |
$canon = trim($raw_canonical); |
| 255 |
} |
| 256 |
} else { |
| 257 |
$canon = is_array($raw_canonical) ? '' : (string) $raw_canonical; |
| 258 |
} |
| 259 |
$pretty = self::pretty_permalink($post); |
| 260 |
|
| 261 |
$rd = get_post_meta($id, 'metasync_post_redirection_meta', true); |
| 262 |
if (!is_array($rd)) { |
| 263 |
$rd = array(); |
| 264 |
} |
| 265 |
$rd_en = (isset($rd['enable']) ? $rd['enable'] : '') === 'true'; |
| 266 |
$rd_type = isset($rd['type']) ? $rd['type'] : '301'; |
| 267 |
$rd_url = isset($rd['url']) ? $rd['url'] : ''; |
| 268 |
|
| 269 |
// The standalone Open Graph box defaults this setting to enabled when |
| 270 |
// no value has been saved yet. Preserve that behaviour: only an |
| 271 |
// explicit '0' represents an editor opting out. |
| 272 |
$og_en_value = get_post_meta($id, '_metasync_og_enabled', true); |
| 273 |
$og_en = ($og_en_value !== '0'); |
| 274 |
// Match the standalone Open Graph box exactly: its computed defaults are |
| 275 |
// real form values (and are therefore persisted on save), not placeholders. |
| 276 |
$og_defaults = array('title' => '', 'description' => '', 'image' => ''); |
| 277 |
$opengraph = class_exists('Metasync_OpenGraph') ? Metasync_OpenGraph::get_instance() : null; |
| 278 |
if ($opengraph) { |
| 279 |
$og_defaults = $opengraph->get_default_og_values($id); |
| 280 |
} |
| 281 |
$og_title = self::v($id, '_metasync_og_title') ?: $og_defaults['title']; |
| 282 |
$og_desc = self::v($id, '_metasync_og_description') ?: $og_defaults['description']; |
| 283 |
$og_image = self::v($id, '_metasync_og_image') ?: $og_defaults['image']; |
| 284 |
$og_type = self::v($id, '_metasync_og_type') ?: 'article'; |
| 285 |
$og_url = self::v($id, '_metasync_og_url'); |
| 286 |
if ($og_url === '') { |
| 287 |
$og_url = $opengraph ? $opengraph->get_canonical_url($post) : $pretty; |
| 288 |
} |
| 289 |
$tw_card = self::v($id, '_metasync_twitter_card') ?: 'summary_large_image'; |
| 290 |
$tw_site = self::v($id, '_metasync_twitter_site'); |
| 291 |
$tw_title = self::v($id, '_metasync_twitter_title') ?: $og_title; |
| 292 |
$tw_desc = self::v($id, '_metasync_twitter_description') ?: $og_desc; |
| 293 |
$tw_image = self::v($id, '_metasync_twitter_image') ?: $og_image; |
| 294 |
$tw_alt = self::v($id, '_metasync_twitter_image_alt'); |
| 295 |
$tw_app_iphone = self::v($id, '_metasync_twitter_app_id_iphone'); |
| 296 |
$tw_app_ipad = self::v($id, '_metasync_twitter_app_id_ipad'); |
| 297 |
$tw_app_gp = self::v($id, '_metasync_twitter_app_id_googleplay'); |
| 298 |
$tw_app_url_iphone = self::v($id, '_metasync_twitter_app_url_iphone'); |
| 299 |
$tw_app_url_ipad = self::v($id, '_metasync_twitter_app_url_ipad'); |
| 300 |
$tw_app_url_gp = self::v($id, '_metasync_twitter_app_url_googleplay'); |
| 301 |
$tw_app_country = self::v($id, '_metasync_twitter_app_country'); |
| 302 |
$tw_player = self::v($id, '_metasync_twitter_player'); |
| 303 |
$tw_player_w = self::v($id, '_metasync_twitter_player_width'); |
| 304 |
$tw_player_h = self::v($id, '_metasync_twitter_player_height'); |
| 305 |
$tw_app_disabled = $tw_card === 'app' ? '' : ' disabled'; |
| 306 |
$tw_player_disabled = $tw_card === 'player' ? '' : ' disabled'; |
| 307 |
|
| 308 |
$v_url = self::v($id, '_metasync_video_url'); |
| 309 |
$v_thumb = self::v($id, '_metasync_video_thumbnail'); |
| 310 |
$v_title = self::v($id, '_metasync_video_title'); |
| 311 |
$v_desc = self::v($id, '_metasync_video_description'); |
| 312 |
$v_dur = self::v($id, '_metasync_video_duration'); |
| 313 |
|
| 314 |
$host = strtoupper((string) wp_parse_url(home_url(), PHP_URL_HOST)); |
| 315 |
$host_lc = strtolower($host); |
| 316 |
$prev_url_disp = preg_replace('#^https?://#', '', (string) $pretty); |
| 317 |
$site = get_bloginfo('name'); |
| 318 |
if ($site === '') { |
| 319 |
$site = $host; |
| 320 |
} |
| 321 |
$avatar = strtoupper(function_exists('mb_substr') ? mb_substr($site, 0, 1) : substr($site, 0, 1)); |
| 322 |
$handle = sanitize_title($site) ?: 'site'; |
| 323 |
|
| 324 |
$this->styles(); |
| 325 |
?> |
| 326 |
<div id="mss-root" data-theme="light"<?php echo $managed ? ' class="lps"' : ''; ?>> |
| 327 |
<?php |
| 328 |
// On managed pages (LPS / custom-HTML) we emit NO nonces, so nothing here can |
| 329 |
// overwrite the externally-managed SEO for those pages. |
| 330 |
if (!$managed) { |
| 331 |
if ($has_seo) { wp_nonce_field('metasync_seo_meta_nonce', 'metasync_seo_meta_nonce'); } |
| 332 |
if ($has_crob) { wp_nonce_field('metasync_common_robots_nonce', 'metasync_common_robots_nonce'); } |
| 333 |
if ($has_arob) { wp_nonce_field('metasync_advance_robots_nonce', 'metasync_advance_robots_nonce'); } |
| 334 |
if ($has_canon) { wp_nonce_field('metasync_post_canonical_nonce', 'metasync_post_canonical_nonce'); } |
| 335 |
if ($has_redir) { wp_nonce_field('metasync_post_redirection_nonce', 'metasync_post_redirection_nonce'); } |
| 336 |
if ($has_social) { wp_nonce_field('metasync_opengraph_nonce', 'metasync_opengraph_nonce'); } |
| 337 |
if ($has_video) { wp_nonce_field('metasync_video_sitemap_meta_nonce', 'metasync_video_sitemap_meta_nonce'); } |
| 338 |
} |
| 339 |
?> |
| 340 |
<div class="metabox"> |
| 341 |
<div class="mb-head"> |
| 342 |
<div class="badge">M</div> |
| 343 |
<div class="t"><b>SEO Suite</b><span>On-page SEO for this post</span></div> |
| 344 |
<div class="mss-actions"> |
| 345 |
<button type="button" class="theme-toggle" onclick="mssTheme(this)"><span class="ti">🌙</span> <span class="tl">Dark</span></button> |
| 346 |
</div> |
| 347 |
</div> |
| 348 |
|
| 349 |
<div class="mss-lockable"> |
| 350 |
<div class="mb-body"<?php echo $managed ? ' inert' : ''; ?>> |
| 351 |
<div class="rail"> |
| 352 |
<?php |
| 353 |
$first = true; |
| 354 |
$tab = function ($key, $icon, $label) use (&$first) { |
| 355 |
echo '<div class="nav' . ($first ? ' active' : '') . '" role="button" tabindex="0" onclick="mssGo(this,\'' . esc_attr($key) . '\')" onkeydown="mssKey(event,this)"><span class="ic">' . $icon . '</span> ' . $label . '</div>'; |
| 356 |
$first = false; |
| 357 |
}; |
| 358 |
if ($has_seo) { $tab('seo', '🔍', 'SEO'); } |
| 359 |
if ($has_robots) { $tab('robots', '🤖', 'Robots'); } |
| 360 |
if ($has_canon) { $tab('canonical', '🔗', 'Canonical'); } |
| 361 |
if ($has_redir) { $tab('redirect', '↪️', 'Redirection'); } |
| 362 |
if ($has_social) { $tab('social', '📢', 'Social & OG'); } |
| 363 |
if ($has_schema) { $tab('schema', '📐', 'Schema'); } |
| 364 |
if ($has_video) { $tab('video', '🎬', 'Video'); } |
| 365 |
?> |
| 366 |
</div> |
| 367 |
|
| 368 |
<div class="panel-wrap"> |
| 369 |
<?php |
| 370 |
$pfirst = true; |
| 371 |
$pcls = function () use (&$pfirst) { |
| 372 |
$c = 'panel' . ($pfirst ? ' active' : ''); |
| 373 |
$pfirst = false; |
| 374 |
return $c; |
| 375 |
}; |
| 376 |
?> |
| 377 |
|
| 378 |
<?php if ($has_seo): ?> |
| 379 |
<div class="<?php echo $pcls(); ?>" data-p="seo"> |
| 380 |
<h2 class="p-title">🔍 Search Appearance</h2> |
| 381 |
<p class="p-sub">Set the SEO Title and Meta Description. Leave blank to use the OTTO suggestion.</p> |
| 382 |
<div class="field"> |
| 383 |
<div class="lbl"><span>SEO Title</span><span class="cc"><span class="tC">0</span>/60</span></div> |
| 384 |
<input class="ctrl seoT" name="metasync_seo_title" value="<?php echo $a($seo_title); ?>" placeholder="<?php echo $a($otto_title); ?>" oninput="mssRc()"> |
| 385 |
</div> |
| 386 |
<div class="field"> |
| 387 |
<div class="lbl"><span>Meta Description</span><span class="cc"><span class="dC">0</span>/160</span></div> |
| 388 |
<textarea class="ctrl seoD" name="metasync_seo_desc" placeholder="<?php echo $a($otto_desc); ?>" oninput="mssRc()"><?php echo esc_textarea($seo_desc); ?></textarea> |
| 389 |
</div> |
| 390 |
<?php if ($otto_kw !== ''): ?> |
| 391 |
<div class="field"> |
| 392 |
<div class="lbl"><span>Focus Keyword</span><span class="ro-badge">Managed by OTTO</span></div> |
| 393 |
<div class="mss-ro"><span class="lock">🔒</span> <?php echo esc_html($otto_kw); ?></div> |
| 394 |
<div class="hint">Set in Search Atlas — shown here for reference. Read-only.</div> |
| 395 |
</div> |
| 396 |
<?php endif; ?> |
| 397 |
<div class="sec">Preview</div> |
| 398 |
<div class="gprev"> |
| 399 |
<div class="u"><?php echo esc_html($prev_url_disp); ?></div> |
| 400 |
<div class="ti gT"><?php echo esc_html($seo_title ?: ($otto_title ?: get_the_title($id))); ?></div> |
| 401 |
<div class="de gD"><?php echo esc_html($seo_desc ?: ($otto_desc ?: 'No description set.')); ?></div> |
| 402 |
</div> |
| 403 |
</div> |
| 404 |
<?php endif; ?> |
| 405 |
|
| 406 |
<?php if ($has_robots): ?> |
| 407 |
<div class="<?php echo $pcls(); ?>" data-p="robots"> |
| 408 |
<h2 class="p-title">🤖 Robots Meta</h2> |
| 409 |
<p class="p-sub">Crawler directives for this post. These are independent flags — combine as needed.</p> |
| 410 |
<?php if ($has_crob): ?> |
| 411 |
<div class="sec">Common directives</div> |
| 412 |
<div class="chips"> |
| 413 |
<?php |
| 414 |
$common = array( |
| 415 |
'index' => array('Index', 'Allow search engines to index this page'), |
| 416 |
'noindex' => array('No Index', 'Keep this page out of results'), |
| 417 |
'nofollow' => array('No Follow', "Don't follow links on this page"), |
| 418 |
'noarchive' => array('No Archive', 'No cached copy'), |
| 419 |
'noimageindex' => array('No Image Index', 'Exclude images from image search'), |
| 420 |
'nosnippet' => array('No Snippet', 'No text snippet in results'), |
| 421 |
); |
| 422 |
foreach ($common as $key => $c): ?> |
| 423 |
<label class="chip"> |
| 424 |
<input type="checkbox" name="common_robots_meta[<?php echo $a($key); ?>]" value="<?php echo $a($key); ?>"<?php echo isset($cr[$key]) ? self::checked_attr($cr[$key] === $key) : ''; ?>> |
| 425 |
<span class="box">✓</span><div><?php echo esc_html($c[0]); ?><small><?php echo esc_html($c[1]); ?></small></div> |
| 426 |
</label> |
| 427 |
<?php endforeach; ?> |
| 428 |
</div> |
| 429 |
<?php endif; ?> |
| 430 |
<?php if ($has_arob): ?> |
| 431 |
<div class="sec">Advanced limits <span class="sec-note">— tick a limit to apply it</span></div> |
| 432 |
<div class="row"> |
| 433 |
<div class="field"> |
| 434 |
<label class="chip mss-advchip"><input type="checkbox" name="advanced_robots_meta[max-snippet][enable]" value="1"<?php checked('1', $ar_snip_e); ?>><span class="box">✓</span><div>Max Snippet</div></label> |
| 435 |
<input class="ctrl" type="number" name="advanced_robots_meta[max-snippet][length]" value="<?php echo $a($ar_snip_l); ?>" min="-1" placeholder="e.g. 160"> |
| 436 |
<div class="hint">Max snippet length in characters.</div></div> |
| 437 |
<div class="field"> |
| 438 |
<label class="chip mss-advchip"><input type="checkbox" name="advanced_robots_meta[max-video-preview][enable]" value="1"<?php checked('1', $ar_vid_e); ?>><span class="box">✓</span><div>Max Video Preview</div></label> |
| 439 |
<input class="ctrl" type="number" name="advanced_robots_meta[max-video-preview][length]" value="<?php echo $a($ar_vid_l); ?>" min="-1" placeholder="e.g. -1"> |
| 440 |
<div class="hint">Max preview duration in seconds.</div></div> |
| 441 |
</div> |
| 442 |
<div class="field"> |
| 443 |
<label class="chip mss-advchip"><input type="checkbox" name="advanced_robots_meta[max-image-preview][enable]" value="1"<?php checked('1', $ar_img_e); ?>><span class="box">✓</span><div>Max Image Preview</div></label> |
| 444 |
<select class="ctrl" name="advanced_robots_meta[max-image-preview][length]"> |
| 445 |
<option value="large"<?php selected($ar_img_l, 'large'); ?>>Large</option> |
| 446 |
<option value="standard"<?php selected($ar_img_l, 'standard'); ?>>Standard</option> |
| 447 |
<option value="none"<?php selected($ar_img_l, 'none'); ?>>None</option> |
| 448 |
</select></div> |
| 449 |
<?php endif; ?> |
| 450 |
</div> |
| 451 |
<?php endif; ?> |
| 452 |
|
| 453 |
<?php if ($has_canon): ?> |
| 454 |
<div class="<?php echo $pcls(); ?>" data-p="canonical"> |
| 455 |
<h2 class="p-title">🔗 Canonical URL</h2> |
| 456 |
<p class="p-sub">Point search engines to the preferred version of this content.</p> |
| 457 |
<div class="field"> |
| 458 |
<div class="lbl"><span>Canonical URL</span></div> |
| 459 |
<input class="ctrl" type="text" name="post_canonical_url_meta" value="<?php echo $a($canon); ?>" placeholder="<?php echo $a($pretty); ?>"> |
| 460 |
<div class="hint">Leave blank to use this post's own URL.</div> |
| 461 |
</div> |
| 462 |
</div> |
| 463 |
<?php endif; ?> |
| 464 |
|
| 465 |
<?php if ($has_redir): ?> |
| 466 |
<div class="<?php echo $pcls(); ?>" data-p="redirect"> |
| 467 |
<h2 class="p-title">↪️ Redirection</h2> |
| 468 |
<p class="p-sub">Send visitors of this post somewhere else.</p> |
| 469 |
<div class="switch-card"> |
| 470 |
<label class="switch"><input type="checkbox" name="post_redirect_meta[enable]" value="true"<?php echo self::checked_attr($rd_en); ?>></label> |
| 471 |
<div class="m"><b>Enable redirection</b><span>Send visitors of this post to another URL</span></div> |
| 472 |
</div> |
| 473 |
<div class="row"> |
| 474 |
<div class="field"><div class="lbl"><span>Type</span></div> |
| 475 |
<select class="ctrl" name="post_redirect_meta[type]"> |
| 476 |
<option value="301"<?php selected($rd_type, '301'); ?>>301 Permanent Move</option> |
| 477 |
<option value="302"<?php selected($rd_type, '302'); ?>>302 Temporary Move</option> |
| 478 |
<option value="307"<?php selected($rd_type, '307'); ?>>307 Temporary Redirect</option> |
| 479 |
<option value="410"<?php selected($rd_type, '410'); ?>>410 Content Deleted</option> |
| 480 |
<option value="451"<?php selected($rd_type, '451'); ?>>451 Content Unavailable</option> |
| 481 |
</select></div> |
| 482 |
<div class="field"><div class="lbl"><span>Destination URL</span></div> |
| 483 |
<input class="ctrl" type="text" name="post_redirect_meta[url]" value="<?php echo $a($rd_url); ?>" placeholder="https://example.com/new-url/"></div> |
| 484 |
</div> |
| 485 |
</div> |
| 486 |
<?php endif; ?> |
| 487 |
|
| 488 |
<?php if ($has_social): ?> |
| 489 |
<div class="<?php echo $pcls(); ?>" data-p="social"> |
| 490 |
<h2 class="p-title">📢 Social & Open Graph</h2> |
| 491 |
<p class="p-sub">How this post looks when shared on social platforms.</p> |
| 492 |
<div class="switch-card"> |
| 493 |
<label class="switch"><input type="checkbox" name="_metasync_og_enabled" value="1"<?php echo self::checked_attr($og_en); ?>></label> |
| 494 |
<div class="m"><b>Enable Open Graph & Social Media Tags</b><span>Adds Open Graph + Twitter Card tags for better sharing</span></div> |
| 495 |
</div> |
| 496 |
|
| 497 |
<div class="subhead"><span class="sq"></span> Open Graph</div> |
| 498 |
<div class="field"><div class="lbl"><span>Title (og:title)</span></div><input class="ctrl" name="_metasync_og_title" maxlength="60" value="<?php echo $a($og_title); ?>" placeholder="<?php echo $a(get_the_title($id)); ?>" oninput="mssSocial()"></div> |
| 499 |
<div class="field"><div class="lbl"><span>Description (og:description)</span></div><textarea class="ctrl" name="_metasync_og_description" maxlength="155" placeholder="Post excerpt…" oninput="mssSocial()"><?php echo esc_textarea($og_desc); ?></textarea></div> |
| 500 |
<div class="field"><div class="lbl"><span>Image (og:image)</span></div> |
| 501 |
<div class="mss-imgrow"><input class="ctrl ogimg" type="url" name="_metasync_og_image" value="<?php echo $a($og_image); ?>" placeholder="https://example.com/image.jpg" oninput="mssSocial()"><button class="btn ghost sm mss-pick" data-target=".ogimg" type="button">Select</button></div> |
| 502 |
<div class="hint">Recommended 1200×630px.</div></div> |
| 503 |
<div class="row"> |
| 504 |
<div class="field"><div class="lbl"><span>Type (og:type)</span></div> |
| 505 |
<select class="ctrl" name="_metasync_og_type"> |
| 506 |
<?php foreach (array('article', 'website', 'blog', 'product', 'video', 'music') as $t): ?> |
| 507 |
<option value="<?php echo $a($t); ?>"<?php selected($og_type, $t); ?>><?php echo esc_html(ucfirst($t)); ?></option> |
| 508 |
<?php endforeach; ?> |
| 509 |
</select></div> |
| 510 |
<div class="field"><div class="lbl"><span>URL (og:url)</span></div><input class="ctrl" type="url" name="_metasync_og_url" value="<?php echo $a($og_url); ?>" placeholder="<?php echo $a($pretty); ?>"<?php echo $post->post_status === 'auto-draft' ? ' disabled' : ''; ?>></div> |
| 511 |
</div> |
| 512 |
|
| 513 |
<div class="subhead"><span class="sq"></span> Twitter Card</div> |
| 514 |
<div class="field"><div class="lbl"><span>Card Type</span></div> |
| 515 |
<select class="ctrl mssTw" name="_metasync_twitter_card" onchange="mssTwT(this)"> |
| 516 |
<option value="summary"<?php selected($tw_card, 'summary'); ?>>Summary</option> |
| 517 |
<option value="summary_large_image"<?php selected($tw_card, 'summary_large_image'); ?>>Summary Large Image</option> |
| 518 |
<option value="app"<?php selected($tw_card, 'app'); ?>>App</option> |
| 519 |
<option value="player"<?php selected($tw_card, 'player'); ?>>Player</option> |
| 520 |
</select></div> |
| 521 |
<div class="row"> |
| 522 |
<div class="field"><div class="lbl"><span>Twitter Site</span></div><input class="ctrl" name="_metasync_twitter_site" value="<?php echo $a($tw_site); ?>" placeholder="@yoursite"></div> |
| 523 |
<div class="field"><div class="lbl"><span>Twitter Title</span></div><input class="ctrl" name="_metasync_twitter_title" maxlength="70" value="<?php echo $a($tw_title); ?>" placeholder="Falls back to OG title" oninput="mssSocial()"></div> |
| 524 |
</div> |
| 525 |
<div class="field"><div class="lbl"><span>Twitter Description</span></div><textarea class="ctrl" name="_metasync_twitter_description" maxlength="200" placeholder="Falls back to OG description" oninput="mssSocial()"><?php echo esc_textarea($tw_desc); ?></textarea></div> |
| 526 |
<div class="row"> |
| 527 |
<div class="field"><div class="lbl"><span>Twitter Image</span></div> |
| 528 |
<div class="mss-imgrow"><input class="ctrl twimg" type="url" name="_metasync_twitter_image" value="<?php echo $a($tw_image); ?>" placeholder="Falls back to OG image" oninput="mssSocial()"><button class="btn ghost sm mss-pick" data-target=".twimg" type="button">Select</button></div></div> |
| 529 |
<div class="field"><div class="lbl"><span>Image Alt</span></div><input class="ctrl" name="_metasync_twitter_image_alt" maxlength="420" value="<?php echo $a($tw_alt); ?>" placeholder="Accessibility description"></div> |
| 530 |
</div> |
| 531 |
|
| 532 |
<div class="mssTwApp" style="display:<?php echo $tw_card === 'app' ? 'block' : 'none'; ?>"> |
| 533 |
<div class="subhead"><span class="sq"></span> App Card</div> |
| 534 |
<div class="row"> |
| 535 |
<div class="field"><div class="lbl"><span>iPhone App ID</span></div><input class="ctrl" name="_metasync_twitter_app_id_iphone" value="<?php echo $a($tw_app_iphone); ?>" placeholder="307234931"<?php echo $tw_app_disabled; ?>></div> |
| 536 |
<div class="field"><div class="lbl"><span>iPad App ID</span></div><input class="ctrl" name="_metasync_twitter_app_id_ipad" value="<?php echo $a($tw_app_ipad); ?>" placeholder="307234931"<?php echo $tw_app_disabled; ?>></div> |
| 537 |
</div> |
| 538 |
<div class="field"><div class="lbl"><span>Google Play App ID</span></div><input class="ctrl" name="_metasync_twitter_app_id_googleplay" value="<?php echo $a($tw_app_gp); ?>" placeholder="com.android.app"<?php echo $tw_app_disabled; ?>></div> |
| 539 |
<div class="row"> |
| 540 |
<div class="field"><div class="lbl"><span>iPhone Custom URL</span></div><input class="ctrl" type="url" name="_metasync_twitter_app_url_iphone" value="<?php echo $a($tw_app_url_iphone); ?>" placeholder="myapp://"<?php echo $tw_app_disabled; ?>></div> |
| 541 |
<div class="field"><div class="lbl"><span>iPad Custom URL</span></div><input class="ctrl" type="url" name="_metasync_twitter_app_url_ipad" value="<?php echo $a($tw_app_url_ipad); ?>" placeholder="myapp://"<?php echo $tw_app_disabled; ?>></div> |
| 542 |
</div> |
| 543 |
<div class="row"> |
| 544 |
<div class="field"><div class="lbl"><span>Google Play Custom URL</span></div><input class="ctrl" type="url" name="_metasync_twitter_app_url_googleplay" value="<?php echo $a($tw_app_url_gp); ?>" placeholder="myapp://"<?php echo $tw_app_disabled; ?>></div> |
| 545 |
<div class="field"><div class="lbl"><span>App Store Country</span></div> |
| 546 |
<select class="ctrl" name="_metasync_twitter_app_country"<?php echo $tw_app_disabled; ?>> |
| 547 |
<option value=""<?php selected($tw_app_country, ''); ?>>US (Default)</option> |
| 548 |
<?php foreach (array('GB' => 'United Kingdom', 'CA' => 'Canada', 'AU' => 'Australia', 'DE' => 'Germany', 'FR' => 'France', 'JP' => 'Japan', 'IN' => 'India', 'BR' => 'Brazil', 'MX' => 'Mexico') as $code => $country): ?> |
| 549 |
<option value="<?php echo $a($code); ?>"<?php selected($tw_app_country, $code); ?>><?php echo esc_html($country); ?></option> |
| 550 |
<?php endforeach; ?> |
| 551 |
</select> |
| 552 |
<div class="hint">Required if your app is not available in the US App Store.</div> |
| 553 |
</div> |
| 554 |
</div> |
| 555 |
</div> |
| 556 |
<div class="mssTwPlayer" style="display:<?php echo $tw_card === 'player' ? 'block' : 'none'; ?>"> |
| 557 |
<div class="subhead"><span class="sq"></span> Player Card</div> |
| 558 |
<div class="field"><div class="lbl"><span>Player URL</span></div><input class="ctrl" type="url" name="_metasync_twitter_player" value="<?php echo $a($tw_player); ?>" placeholder="https://example.com/player"<?php echo $tw_player_disabled; ?>></div> |
| 559 |
<div class="row"> |
| 560 |
<div class="field"><div class="lbl"><span>Width (px)</span></div><input class="ctrl short" type="number" name="_metasync_twitter_player_width" min="1" value="<?php echo $a($tw_player_w); ?>" placeholder="1280"<?php echo $tw_player_disabled; ?>></div> |
| 561 |
<div class="field"><div class="lbl"><span>Height (px)</span></div><input class="ctrl short" type="number" name="_metasync_twitter_player_height" min="1" value="<?php echo $a($tw_player_h); ?>" placeholder="720"<?php echo $tw_player_disabled; ?>></div> |
| 562 |
</div> |
| 563 |
</div> |
| 564 |
|
| 565 |
<div class="subhead"><span class="sq"></span> Social preview</div> |
| 566 |
<div class="mss-sptabs"> |
| 567 |
<button type="button" class="on" onclick="mssSpTab(this,'facebook')">Facebook</button> |
| 568 |
<button type="button" onclick="mssSpTab(this,'twitter')">Twitter / X</button> |
| 569 |
<button type="button" onclick="mssSpTab(this,'linkedin')">LinkedIn</button> |
| 570 |
</div> |
| 571 |
<div class="spwrap"> |
| 572 |
<div class="spcard fb on" data-plat="facebook"> |
| 573 |
<div class="sp-head"><span class="sp-av"><?php echo esc_html($avatar); ?></span><div class="sp-meta"><b><?php echo esc_html($site); ?></b><span>2 hours ago · 🌐</span></div></div> |
| 574 |
<div class="sp-img"><span class="sp-noimg">No image selected</span></div> |
| 575 |
<div class="sp-body"> |
| 576 |
<div class="sp-url"><?php echo esc_html($host); ?></div> |
| 577 |
<div class="sp-title spT"></div> |
| 578 |
<div class="sp-desc spD"></div> |
| 579 |
</div> |
| 580 |
</div> |
| 581 |
<div class="spcard tw" data-plat="twitter"> |
| 582 |
<div class="sp-head"><span class="sp-av"><?php echo esc_html($avatar); ?></span><div class="sp-meta"><b><?php echo esc_html($site); ?></b><span>@<?php echo esc_html($handle); ?> · now</span></div></div> |
| 583 |
<div class="tw-card"> |
| 584 |
<div class="sp-img"><span class="sp-noimg">No image selected</span></div> |
| 585 |
<div class="sp-body"> |
| 586 |
<div class="sp-title spT"></div> |
| 587 |
<div class="sp-desc spD"></div> |
| 588 |
<div class="sp-url"><?php echo esc_html($host_lc); ?></div> |
| 589 |
</div> |
| 590 |
</div> |
| 591 |
</div> |
| 592 |
<div class="spcard li" data-plat="linkedin"> |
| 593 |
<div class="sp-head"><span class="sp-av"><?php echo esc_html($avatar); ?></span><div class="sp-meta"><b><?php echo esc_html($site); ?></b><span>Promoted</span></div></div> |
| 594 |
<div class="sp-img"><span class="sp-noimg">No image selected</span></div> |
| 595 |
<div class="sp-body"> |
| 596 |
<div class="sp-title spT"></div> |
| 597 |
<div class="sp-url"><?php echo esc_html($host_lc); ?> · 1 min read</div> |
| 598 |
</div> |
| 599 |
</div> |
| 600 |
</div> |
| 601 |
</div> |
| 602 |
<?php endif; ?> |
| 603 |
|
| 604 |
<?php if ($has_schema): ?> |
| 605 |
<div class="<?php echo $pcls(); ?>" data-p="schema"> |
| 606 |
<h2 class="p-title">📐 Schema Markup</h2> |
| 607 |
<div class="mss-native"> |
| 608 |
<?php |
| 609 |
if (!empty($this->schema_box['callback'])) { |
| 610 |
call_user_func($this->schema_box['callback'], $post, $this->schema_box); |
| 611 |
} else { |
| 612 |
echo '<p class="p-sub">Schema builder unavailable on this screen.</p>'; |
| 613 |
} |
| 614 |
?> |
| 615 |
</div> |
| 616 |
</div> |
| 617 |
<?php endif; ?> |
| 618 |
|
| 619 |
<?php if ($has_video): ?> |
| 620 |
<div class="<?php echo $pcls(); ?>" data-p="video"> |
| 621 |
<h2 class="p-title">🎬 Video Sitemap</h2> |
| 622 |
<p class="p-sub">Override auto-detected video data. Leave blank to use auto-detection.</p> |
| 623 |
<div class="field"><div class="lbl"><span>Video URL</span></div><input class="ctrl" type="url" name="metasync_video_url" value="<?php echo $a($v_url); ?>" placeholder="https://www.youtube.com/watch?v=..."></div> |
| 624 |
<div class="field"><div class="lbl"><span>Thumbnail URL</span></div><input class="ctrl" type="url" name="metasync_video_thumbnail" value="<?php echo $a($v_thumb); ?>" placeholder="https://img.youtube.com/vi/.../hqdefault.jpg"></div> |
| 625 |
<div class="field"><div class="lbl"><span>Video Title</span></div><input class="ctrl" name="metasync_video_title" value="<?php echo $a($v_title); ?>" placeholder="Defaults to post title"></div> |
| 626 |
<div class="field"><div class="lbl"><span>Video Description</span></div><textarea class="ctrl" name="metasync_video_description" placeholder="Defaults to post excerpt"><?php echo esc_textarea($v_desc); ?></textarea></div> |
| 627 |
<div class="field"><div class="lbl"><span>Duration (seconds)</span></div><input class="ctrl short" type="number" name="metasync_video_duration" min="0" step="1" value="<?php echo $a($v_dur); ?>" placeholder="300"></div> |
| 628 |
</div> |
| 629 |
<?php endif; ?> |
| 630 |
|
| 631 |
</div> |
| 632 |
</div> |
| 633 |
|
| 634 |
<div class="mb-foot"> |
| 635 |
<span class="mss-foot-hint">Changes are saved when you update the post.</span> |
| 636 |
</div> |
| 637 |
|
| 638 |
<?php if ($managed): ?> |
| 639 |
<div class="mss-lps-overlay"> |
| 640 |
<div class="mss-lps-card"> |
| 641 |
<div class="mss-lps-icon">🔒</div> |
| 642 |
<h3>SEO managed by WebStudio</h3> |
| 643 |
<p>This page's content is served as pre-built HTML before WordPress renders its <code><head></code>, so these SEO Suite settings won't apply. SEO for this page is managed by <b>WebStudio</b> (or OTTO, if enabled) to keep everything in sync.</p> |
| 644 |
<div class="mss-lps-hint">Editing is disabled here to avoid conflicting values.</div> |
| 645 |
</div> |
| 646 |
</div> |
| 647 |
<?php endif; ?> |
| 648 |
</div> |
| 649 |
</div> |
| 650 |
</div> |
| 651 |
|
| 652 |
<script> |
| 653 |
(function(){ |
| 654 |
var root=document.getElementById('mss-root'); if(!root) return; |
| 655 |
function byName(n){return root.querySelector('[name="'+n+'"]');} |
| 656 |
function mssFld(n){var e=byName(n);return e?e.value.trim():'';} |
| 657 |
window.mssKey=function(e,el){ if(e.key==='Enter'||e.key===' '){ e.preventDefault(); el.click(); } }; |
| 658 |
window.mssGo=function(el,p){ |
| 659 |
el.parentElement.querySelectorAll('.nav').forEach(function(n){n.classList.remove('active')}); |
| 660 |
el.classList.add('active'); |
| 661 |
root.querySelectorAll('.panel').forEach(function(pn){pn.classList.remove('active')}); |
| 662 |
var t=root.querySelector('.panel[data-p="'+p+'"]'); if(t)t.classList.add('active'); |
| 663 |
}; |
| 664 |
window.mssRc=function(){ |
| 665 |
var ti=root.querySelector('.seoT'), de=root.querySelector('.seoD'); if(!ti) return; |
| 666 |
root.querySelector('.tC').textContent=ti.value.length; |
| 667 |
root.querySelector('.dC').textContent=de.value.length; |
| 668 |
root.querySelector('.gT').textContent=ti.value||ti.getAttribute('placeholder')||'Untitled'; |
| 669 |
root.querySelector('.gD').textContent=de.value||de.getAttribute('placeholder')||'No description set.'; |
| 670 |
}; |
| 671 |
window.mssTwT=function(sel){ |
| 672 |
var isApp=sel.value==='app', isPlayer=sel.value==='player'; |
| 673 |
var appSection=root.querySelector('.mssTwApp'), playerSection=root.querySelector('.mssTwPlayer'); |
| 674 |
if(appSection){ |
| 675 |
appSection.style.display=isApp?'block':'none'; |
| 676 |
appSection.querySelectorAll('input,select,textarea').forEach(function(field){field.disabled=!isApp;}); |
| 677 |
} |
| 678 |
if(playerSection){ |
| 679 |
playerSection.style.display=isPlayer?'block':'none'; |
| 680 |
playerSection.querySelectorAll('input,select,textarea').forEach(function(field){field.disabled=!isPlayer;}); |
| 681 |
} |
| 682 |
}; |
| 683 |
window.mssTheme=function(btn){ |
| 684 |
var dark=root.getAttribute('data-theme')==='dark'; |
| 685 |
root.setAttribute('data-theme',dark?'light':'dark'); |
| 686 |
btn.querySelector('.ti').textContent=dark?'\u{1F319}':'☀️'; |
| 687 |
btn.querySelector('.tl').textContent=dark?'Dark':'Light'; |
| 688 |
}; |
| 689 |
window.mssSpTab=function(btn,p){ |
| 690 |
btn.parentElement.querySelectorAll('button').forEach(function(b){b.classList.remove('on')}); |
| 691 |
btn.classList.add('on'); |
| 692 |
root.querySelectorAll('.spcard').forEach(function(c){c.classList.toggle('on', c.getAttribute('data-plat')===p)}); |
| 693 |
}; |
| 694 |
window.mssSocial=function(){ |
| 695 |
var seoT=root.querySelector('.seoT'), seoD=root.querySelector('.seoD'); |
| 696 |
var ogTitleEl=byName('_metasync_og_title'); |
| 697 |
var baseTitle=mssFld('_metasync_og_title') || (ogTitleEl&&ogTitleEl.getAttribute('placeholder')) || (seoT&&seoT.value.trim()) || 'Untitled'; |
| 698 |
var baseDesc =mssFld('_metasync_og_description') || (seoD&&seoD.value.trim()) || 'No description set.'; |
| 699 |
var baseImg =mssFld('_metasync_og_image'); |
| 700 |
var twTitle=mssFld('_metasync_twitter_title'); |
| 701 |
var twDesc =mssFld('_metasync_twitter_description'); |
| 702 |
var twImg =mssFld('_metasync_twitter_image'); |
| 703 |
root.querySelectorAll('.spcard').forEach(function(c){ |
| 704 |
var isTw=c.getAttribute('data-plat')==='twitter'; |
| 705 |
var T=isTw?(twTitle||baseTitle):baseTitle; |
| 706 |
var D=isTw?(twDesc||baseDesc):baseDesc; |
| 707 |
var I=isTw?(twImg||baseImg):baseImg; |
| 708 |
var et=c.querySelector('.spT'); if(et)et.textContent=T; |
| 709 |
var ed=c.querySelector('.spD'); if(ed)ed.textContent=D; |
| 710 |
var eb=c.querySelector('.sp-img'); if(eb){ if(I){eb.style.backgroundImage='url("'+I.replace(/"/g,'')+'")';eb.classList.add('has');}else{eb.style.backgroundImage='';eb.classList.remove('has');} } |
| 711 |
}); |
| 712 |
}; |
| 713 |
root.querySelectorAll('.mss-pick').forEach(function(btn){ |
| 714 |
btn.addEventListener('click',function(e){e.preventDefault();if(typeof wp==='undefined'||!wp.media)return; |
| 715 |
var target=root.querySelector(btn.getAttribute('data-target')); |
| 716 |
var frame=wp.media({title:'Select image',button:{text:'Use image'},multiple:false}); |
| 717 |
frame.on('select',function(){var img=frame.state().get('selection').first().toJSON();if(target){target.value=img.url;mssSocial();}}); |
| 718 |
frame.open();}); |
| 719 |
}); |
| 720 |
['_metasync_og_title','_metasync_og_description','_metasync_og_image','_metasync_twitter_title','_metasync_twitter_description','_metasync_twitter_image'].forEach(function(n){ |
| 721 |
var e=byName(n); if(e) e.addEventListener('input',mssSocial); |
| 722 |
}); |
| 723 |
var twitterCard=byName('_metasync_twitter_card'); if(twitterCard)mssTwT(twitterCard); mssRc(); mssSocial(); |
| 724 |
})(); |
| 725 |
</script> |
| 726 |
<?php |
| 727 |
} |
| 728 |
|
| 729 |
private function styles() |
| 730 |
{ |
| 731 |
static $done = false; |
| 732 |
if ($done) { |
| 733 |
return; |
| 734 |
} |
| 735 |
$done = true; |
| 736 |
?> |
| 737 |
<style> |
| 738 |
#mss-root[data-theme="light"]{--card:#fff;--card-2:#f1f3f5;--rail:#fbfbfd;--text:#1a1f26;--muted:#6b7280;--faint:#9ca3af;--border:#e5e7eb;--border-soft:#eef0f3;--accent:#667eea;--purple:#764ba2;--grad:linear-gradient(135deg,#667eea 0%,#764ba2 100%);--grad-hover:linear-gradient(135deg,#5568d3 0%,#653f8c 100%);--grad-soft:linear-gradient(135deg,rgba(102,126,234,.10) 0%,rgba(118,75,162,.06) 100%);--success:#10b981;--warning:#f59e0b;--error:#ef4444;--field-bg:#fff;--shadow:0 4px 24px rgba(17,24,39,.08);--shadow-sm:0 1px 3px rgba(17,24,39,.06)} |
| 739 |
#mss-root[data-theme="dark"]{--card:#1a1f26;--card-2:#222831;--rail:#171c23;--text:#fff;--muted:#9ca3af;--faint:#8b93a3;--border:#374151;--border-soft:#283242;--accent:#8ea2f0;--purple:#764ba2;--grad:linear-gradient(135deg,#667eea 0%,#764ba2 100%);--grad-hover:linear-gradient(135deg,#5568d3 0%,#653f8c 100%);--grad-soft:linear-gradient(135deg,rgba(102,126,234,.16) 0%,rgba(118,75,162,.10) 100%);--success:#10b981;--warning:#f59e0b;--error:#ef4444;--field-bg:#11161d;--shadow:0 8px 30px rgba(0,0,0,.45);--shadow-sm:0 1px 3px rgba(0,0,0,.4)} |
| 740 |
#mss-root,#mss-root *{box-sizing:border-box} |
| 741 |
#mss-root{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Inter,Oxygen,Ubuntu,sans-serif;color:var(--text);font-size:13.5px;line-height:1.55;margin:-6px -12px -12px;background:var(--card);overflow:hidden} |
| 742 |
#mss-root .mb-head{display:flex;align-items:center;gap:12px;padding:16px 20px;border-bottom:1px solid var(--border-soft)} |
| 743 |
#mss-root .mb-head .badge{width:30px;height:30px;border-radius:9px;background:var(--grad);display:flex;align-items:center;justify-content:center;color:#fff;font-weight:800;font-size:15px} |
| 744 |
#mss-root .mb-head .t b{font-size:14.5px;color:var(--text)} |
| 745 |
#mss-root .mb-head .t span{display:block;color:var(--muted);font-size:11.5px} |
| 746 |
#mss-root .mss-actions{margin-left:auto;display:flex;gap:8px} |
| 747 |
#mss-root .theme-toggle{display:flex;align-items:center;gap:7px;background:var(--grad);border:0;color:#fff;border-radius:20px;padding:6px 13px;cursor:pointer;font-size:12px;font-weight:600} |
| 748 |
#mss-root .mb-body{display:grid;grid-template-columns:212px 1fr;min-height:430px} |
| 749 |
@media (max-width:900px){#mss-root .mb-body{grid-template-columns:1fr}} |
| 750 |
#mss-root .rail{background:var(--rail);border-right:1px solid var(--border-soft);padding:12px 10px;display:flex;flex-direction:column;gap:3px} |
| 751 |
@media (max-width:900px){#mss-root .rail{flex-direction:row;overflow-x:auto;border-right:0;border-bottom:1px solid var(--border-soft)}} |
| 752 |
#mss-root .nav{display:flex;align-items:center;gap:11px;padding:10px 12px;border-radius:10px;cursor:pointer;color:var(--muted);font-weight:600;font-size:13px;border:1px solid transparent;white-space:nowrap;transition:.15s;position:relative} |
| 753 |
#mss-root .nav:hover{background:var(--card-2);color:var(--text)} |
| 754 |
#mss-root .nav.active{background:var(--grad-soft);color:var(--accent);border-color:rgba(102,126,234,.35)} |
| 755 |
#mss-root .nav.active::before{content:"";position:absolute;left:0;top:8px;bottom:8px;width:3px;border-radius:3px;background:var(--grad)} |
| 756 |
#mss-root .nav .ic{width:20px;height:20px;flex:none;display:flex;align-items:center;justify-content:center;font-size:14px} |
| 757 |
#mss-root .panel-wrap{padding:24px 26px;position:relative} |
| 758 |
#mss-root .panel{display:none;animation:mssfade .22s ease} |
| 759 |
#mss-root .panel.active{display:block} |
| 760 |
@keyframes mssfade{from{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}} |
| 761 |
#mss-root .p-title{font-size:16px;font-weight:700;margin:0 0 3px;display:flex;align-items:center;gap:9px;color:var(--text)} |
| 762 |
#mss-root .p-sub{color:var(--muted);font-size:12.5px;margin:0 0 20px} |
| 763 |
#mss-root .sec{font-size:11px;font-weight:700;letter-spacing:.07em;text-transform:uppercase;color:var(--faint);margin:24px 0 13px;display:flex;align-items:center;gap:8px} |
| 764 |
#mss-root .sec::after{content:"";flex:1;height:1px;background:var(--border-soft)} |
| 765 |
#mss-root .sec-note{text-transform:none;letter-spacing:0;font-weight:500;color:var(--faint)} |
| 766 |
#mss-root .subhead{font-size:14px;font-weight:700;color:var(--text);margin:24px 0 14px;display:flex;align-items:center;gap:9px;padding-bottom:9px;border-bottom:2px solid var(--border-soft)} |
| 767 |
#mss-root .subhead .sq{width:9px;height:16px;border-radius:3px;background:var(--grad);flex:none} |
| 768 |
#mss-root .field{margin:0 0 17px} |
| 769 |
#mss-root .field:last-child{margin-bottom:0} |
| 770 |
#mss-root .field .lbl{display:flex;justify-content:space-between;align-items:baseline;font-weight:600;margin-bottom:6px;font-size:12.5px;color:var(--text)} |
| 771 |
#mss-root .field .lbl .cc{color:var(--faint);font-weight:600;font-size:11px} |
| 772 |
#mss-root .ctrl{width:100%;padding:10px 12px;border:1.5px solid var(--border);border-radius:9px;font-size:13px;background:var(--field-bg);color:var(--text);transition:.15s;font-family:inherit;line-height:1.4;min-height:0;box-shadow:none} |
| 773 |
#mss-root .ctrl:focus{outline:none;border-color:var(--accent);box-shadow:0 0 0 3px rgba(102,126,234,.16)} |
| 774 |
#mss-root textarea.ctrl{min-height:78px;resize:vertical} |
| 775 |
#mss-root input.short{max-width:140px} |
| 776 |
#mss-root .mss-imgrow{display:flex;gap:9px} |
| 777 |
#mss-root .hint{color:var(--faint);font-size:11.5px;margin-top:5px;line-height:1.5} |
| 778 |
#mss-root .row{display:grid;grid-template-columns:1fr 1fr;gap:15px} |
| 779 |
@media (max-width:560px){#mss-root .row{grid-template-columns:1fr}} |
| 780 |
#mss-root .switch-card{display:flex;align-items:center;gap:13px;padding:13px 15px;background:var(--card-2);border:1px solid var(--border-soft);border-radius:11px;margin-bottom:18px} |
| 781 |
#mss-root .switch{width:42px;height:24px;border-radius:24px;background:var(--border);position:relative;flex:none;cursor:pointer;transition:.18s;display:inline-block} |
| 782 |
#mss-root .switch input{position:absolute;opacity:0;width:0;height:0} |
| 783 |
#mss-root .switch::after{content:"";position:absolute;width:18px;height:18px;border-radius:50%;background:#fff;top:3px;left:3px;transition:.18s;box-shadow:0 1px 2px rgba(0,0,0,.3)} |
| 784 |
#mss-root .switch:has(input:checked){background:var(--grad)} |
| 785 |
#mss-root .switch:has(input:checked)::after{left:21px} |
| 786 |
#mss-root .switch-card .m b{display:block;font-size:13px;color:var(--text)} |
| 787 |
#mss-root .switch-card .m span{color:var(--muted);font-size:11.5px} |
| 788 |
#mss-root .chips{display:flex;flex-wrap:wrap;gap:9px} |
| 789 |
#mss-root .chip{display:flex;align-items:center;gap:8px;padding:9px 13px;border:1.5px solid var(--border);border-radius:10px;cursor:pointer;font-size:12.5px;font-weight:600;background:var(--field-bg);transition:.15s;user-select:none;color:var(--text)} |
| 790 |
#mss-root .chip input{position:absolute;opacity:0;width:0;height:0} |
| 791 |
#mss-root .chip:hover{border-color:var(--accent)} |
| 792 |
#mss-root .chip:has(input:checked){background:var(--grad-soft);border-color:var(--accent);color:var(--accent)} |
| 793 |
#mss-root .chip .box{width:15px;height:15px;border-radius:4px;border:1.5px solid var(--border);display:flex;align-items:center;justify-content:center;font-size:10px;color:transparent;flex:none} |
| 794 |
#mss-root .chip:has(input:checked) .box{background:var(--accent);border-color:var(--accent);color:#fff} |
| 795 |
#mss-root .chip small{display:block;font-weight:500;color:var(--muted);font-size:10.5px;margin-top:2px;max-width:160px;line-height:1.35} |
| 796 |
#mss-root .chip:has(input:checked) small{color:var(--text)} |
| 797 |
#mss-root .mss-advchip{display:inline-flex;margin-bottom:7px} |
| 798 |
#mss-root .gprev{border:1px solid var(--border);border-radius:11px;padding:15px 17px;background:var(--field-bg)} |
| 799 |
#mss-root .gprev .u{color:var(--muted);font-size:12px} |
| 800 |
#mss-root .gprev .ti{color:#1a0dab;font-size:18px;margin:3px 0;font-weight:400} |
| 801 |
#mss-root[data-theme="dark"] .gprev .ti{color:#8ab4f8} |
| 802 |
#mss-root .gprev .de{color:var(--muted);font-size:12.5px} |
| 803 |
#mss-root .btn{background:var(--grad);color:#fff;border:0;padding:9px 17px;border-radius:9px;cursor:pointer;font-size:13px;font-weight:600;box-shadow:var(--shadow-sm);transition:.15s;height:auto;line-height:1.3} |
| 804 |
#mss-root .btn:hover{background:var(--grad-hover);color:#fff} |
| 805 |
#mss-root .btn.ghost{background:transparent;color:var(--accent);border:1.5px solid rgba(102,126,234,.45);box-shadow:none} |
| 806 |
#mss-root .btn.ghost:hover{background:var(--grad-soft)} |
| 807 |
#mss-root .btn.sm{padding:6px 12px;font-size:12px} |
| 808 |
#mss-root .mss-sptabs{display:flex;gap:2px;margin-bottom:13px;border-bottom:1px solid var(--border-soft)} |
| 809 |
#mss-root .mss-sptabs button{background:none;border:0;padding:8px 13px;font-size:12.5px;font-weight:600;color:var(--muted);cursor:pointer;border-bottom:2px solid transparent;margin-bottom:-1px} |
| 810 |
#mss-root .mss-sptabs button.on{color:var(--accent);border-bottom-color:var(--accent)} |
| 811 |
#mss-root .spcard{display:none;border:1px solid var(--border);border-radius:11px;overflow:hidden;background:var(--field-bg);max-width:524px} |
| 812 |
#mss-root .spcard.on{display:block} |
| 813 |
#mss-root .sp-head{display:flex;align-items:center;gap:10px;padding:11px 13px} |
| 814 |
#mss-root .sp-av{width:34px;height:34px;border-radius:50%;background:var(--grad);color:#fff;display:flex;align-items:center;justify-content:center;font-weight:800;font-size:14px;flex:none} |
| 815 |
#mss-root .sp-meta b{font-size:13px;color:var(--text);display:block;line-height:1.3} |
| 816 |
#mss-root .sp-meta span{font-size:11px;color:var(--faint)} |
| 817 |
#mss-root .sp-img{height:210px;background:var(--card-2) center/cover no-repeat;display:flex;align-items:center;justify-content:center} |
| 818 |
#mss-root .sp-img.has .sp-noimg{display:none} |
| 819 |
#mss-root .sp-noimg{color:var(--faint);font-size:12px} |
| 820 |
#mss-root .sp-body{padding:11px 14px;border-top:1px solid var(--border-soft);background:var(--card-2)} |
| 821 |
#mss-root[data-theme="dark"] .sp-body{background:var(--card)} |
| 822 |
#mss-root .sp-url{font-size:10.5px;text-transform:uppercase;color:var(--faint);letter-spacing:.03em} |
| 823 |
#mss-root .sp-title{font-size:15px;font-weight:700;color:var(--text);margin:3px 0} |
| 824 |
#mss-root .sp-desc{font-size:12.5px;color:var(--muted)} |
| 825 |
#mss-root .spcard.tw .tw-card{margin:0 13px 14px;border:1px solid var(--border);border-radius:15px;overflow:hidden} |
| 826 |
#mss-root .spcard.tw .sp-body{border-top:0;background:var(--field-bg);display:flex;flex-direction:column} |
| 827 |
#mss-root .spcard.tw .sp-title{font-size:14px;margin:0 0 3px;order:1} |
| 828 |
#mss-root .spcard.tw .sp-desc{order:2} |
| 829 |
#mss-root .spcard.tw .sp-url{order:0;text-transform:none;margin-bottom:4px} |
| 830 |
#mss-root .spcard.li .sp-title{font-size:14.5px} |
| 831 |
#mss-root .mb-foot{display:flex;align-items:center;gap:14px;padding:13px 26px;border-top:1px solid var(--border-soft);background:var(--rail)} |
| 832 |
#mss-root .mss-foot-hint{font-size:12px;color:var(--muted)} |
| 833 |
#mss-root .mss-lockable{position:relative} |
| 834 |
#mss-root .mss-lps-overlay{position:absolute;inset:0;display:none;align-items:center;justify-content:center;padding:26px;z-index:6;background:rgba(248,249,250,.62);backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px)} |
| 835 |
#mss-root[data-theme="dark"] .mss-lps-overlay{background:rgba(15,20,25,.66)} |
| 836 |
#mss-root.lps .mss-lps-overlay{display:flex} |
| 837 |
#mss-root .mss-lps-card{max-width:440px;text-align:center;background:var(--card);border:1px solid var(--border);border-radius:18px;box-shadow:var(--shadow);padding:32px 30px} |
| 838 |
#mss-root .mss-lps-icon{width:58px;height:58px;margin:0 auto 16px;border-radius:16px;background:var(--grad);display:flex;align-items:center;justify-content:center;font-size:27px;box-shadow:var(--shadow-sm)} |
| 839 |
#mss-root .mss-lps-card h3{margin:0 0 9px;font-size:18px;color:var(--text)} |
| 840 |
#mss-root .mss-lps-card p{margin:0 0 20px;color:var(--muted);font-size:13px;line-height:1.65} |
| 841 |
#mss-root .mss-lps-card p b{color:var(--text)} |
| 842 |
#mss-root .mss-lps-card p code{background:var(--card-2);padding:1px 5px;border-radius:4px;font-size:11px} |
| 843 |
#mss-root .mss-lps-hint{margin-top:15px;font-size:11.5px;color:var(--faint)} |
| 844 |
#mss-root .mss-ro{width:100%;padding:10px 12px;border:1.5px dashed var(--border);border-radius:9px;background:var(--card-2);color:var(--text);font-size:13px;font-weight:600;display:flex;align-items:center;gap:8px} |
| 845 |
#mss-root .ro-badge{font-weight:600;font-size:10.5px;color:var(--accent);background:var(--grad-soft);border:1px solid rgba(102,126,234,.30);border-radius:20px;padding:2px 9px} |
| 846 |
#mss-root .mss-native input[type=text],#mss-root .mss-native input[type=url],#mss-root .mss-native input[type=number],#mss-root .mss-native textarea,#mss-root .mss-native select{border-radius:8px !important} |
| 847 |
/* The builder's own `.schema-field input {width:100%}` also hits checkboxes and radios, |
| 848 |
stretching them into a full-width block. Core styles these with |
| 849 |
-webkit-appearance:none, so they have NO intrinsic size and depend entirely on an |
| 850 |
explicit width/height — restate core's 1rem box rather than using width:auto, which |
| 851 |
would collapse the control to nothing while unchecked (the checked state only stays |
| 852 |
visible because core paints a ::before glyph over it). */ |
| 853 |
#mss-root .mss-native input[type=checkbox], |
| 854 |
#mss-root .mss-native input[type=radio]{width:1rem !important;min-width:1rem !important;max-width:1rem !important;height:1rem !important;flex:0 0 auto;padding:0 !important;margin:0 7px 0 0;vertical-align:middle} |
| 855 |
#mss-root .mss-native input[type=radio]{border-radius:50% !important} |
| 856 |
#mss-root .mss-native .schema-field label:has(input[type=checkbox]), |
| 857 |
#mss-root .mss-native .schema-field label:has(input[type=radio]){display:flex;align-items:center;gap:2px} |
| 858 |
/* Dark mode: theme the embedded native Schema builder. Every surface the builder paints |
| 859 |
light — whether from its stylesheet or an inline style — is listed here. Text is only |
| 860 |
forced light on surfaces this block also darkens, so nothing ends up light-on-light. */ |
| 861 |
#mss-root[data-theme="dark"] .mss-native{color:var(--text)} |
| 862 |
#mss-root[data-theme="dark"] .mss-native h1,#mss-root[data-theme="dark"] .mss-native h2,#mss-root[data-theme="dark"] .mss-native h3,#mss-root[data-theme="dark"] .mss-native h4,#mss-root[data-theme="dark"] .mss-native h5,#mss-root[data-theme="dark"] .mss-native label,#mss-root[data-theme="dark"] .mss-native strong,#mss-root[data-theme="dark"] .mss-native p{color:var(--text) !important} |
| 863 |
#mss-root[data-theme="dark"] .mss-native .description,#mss-root[data-theme="dark"] .mss-native small{color:var(--muted) !important} |
| 864 |
/* Light surfaces → dark. Class/ID list mirrors schema-markup-admin.css; the [style*=] |
| 865 |
matchers catch the builder's inline backgrounds (#f5f5f5, #f9f9f9, #fff, white). */ |
| 866 |
#mss-root[data-theme="dark"] .mss-native .schema-types-container, |
| 867 |
#mss-root[data-theme="dark"] .mss-native .schema-types-header, |
| 868 |
#mss-root[data-theme="dark"] .mss-native .schema-type-item, |
| 869 |
#mss-root[data-theme="dark"] .mss-native .schema-type-header, |
| 870 |
#mss-root[data-theme="dark"] .mss-native .schema-type-content, |
| 871 |
#mss-root[data-theme="dark"] .mss-native .schema-fields-container, |
| 872 |
#mss-root[data-theme="dark"] .mss-native .schema-field, |
| 873 |
#mss-root[data-theme="dark"] .mss-native .schema-field-group, |
| 874 |
#mss-root[data-theme="dark"] .mss-native .schema-override-header, |
| 875 |
#mss-root[data-theme="dark"] .mss-native .schema-override-content, |
| 876 |
#mss-root[data-theme="dark"] .mss-native .no-schema-types, |
| 877 |
#mss-root[data-theme="dark"] .mss-native .faq-item, |
| 878 |
#mss-root[data-theme="dark"] .mss-native .instruction-item, |
| 879 |
#mss-root[data-theme="dark"] .mss-native .logo-upload-container, |
| 880 |
#mss-root[data-theme="dark"] .mss-native .logo-preview, |
| 881 |
#mss-root[data-theme="dark"] .mss-native #schema-preview-output, |
| 882 |
#mss-root[data-theme="dark"] .mss-native #schema-type-modal > div, |
| 883 |
#mss-root[data-theme="dark"] .mss-native [style*="background: #fff"], |
| 884 |
#mss-root[data-theme="dark"] .mss-native [style*="background:#fff"], |
| 885 |
#mss-root[data-theme="dark"] .mss-native [style*="background: white"], |
| 886 |
#mss-root[data-theme="dark"] .mss-native [style*="background:white"], |
| 887 |
#mss-root[data-theme="dark"] .mss-native [style*="background: #f9f9f9"], |
| 888 |
#mss-root[data-theme="dark"] .mss-native [style*="background:#f9f9f9"], |
| 889 |
#mss-root[data-theme="dark"] .mss-native [style*="background: #f5f5f5"], |
| 890 |
#mss-root[data-theme="dark"] .mss-native [style*="background:#f5f5f5"], |
| 891 |
#mss-root[data-theme="dark"] .mss-native [style*="#ffffff"]{background-color:var(--card-2) !important;border-color:var(--border) !important} |
| 892 |
/* Notices keep their semantic colour instead of being flattened to a grey surface. */ |
| 893 |
#mss-root[data-theme="dark"] .mss-native .metasync-schema-validation-warning, |
| 894 |
#mss-root[data-theme="dark"] .mss-native [style*="background: #fff3cd"], |
| 895 |
#mss-root[data-theme="dark"] .mss-native [style*="background:#fff3cd"]{background-color:rgba(245,158,11,.14) !important;border-color:rgba(245,158,11,.45) !important} |
| 896 |
#mss-root[data-theme="dark"] .mss-native .metasync-schema-validation-warning, |
| 897 |
#mss-root[data-theme="dark"] .mss-native .metasync-schema-validation-warning *, |
| 898 |
#mss-root[data-theme="dark"] .mss-native [style*="#fff3cd"] *, |
| 899 |
#mss-root[data-theme="dark"] .mss-native [style*="color: #856404"], |
| 900 |
#mss-root[data-theme="dark"] .mss-native [style*="color:#856404"]{color:#fcd34d !important} |
| 901 |
#mss-root[data-theme="dark"] .mss-native .metasync-schema-requirements-info, |
| 902 |
#mss-root[data-theme="dark"] .mss-native [style*="background: #e7f3ff"], |
| 903 |
#mss-root[data-theme="dark"] .mss-native [style*="background:#e7f3ff"]{background-color:rgba(102,126,234,.14) !important;border-color:rgba(102,126,234,.45) !important} |
| 904 |
#mss-root[data-theme="dark"] .mss-native .metasync-schema-requirements-info, |
| 905 |
#mss-root[data-theme="dark"] .mss-native .metasync-schema-requirements-info *{color:#c7d2fe !important} |
| 906 |
/* Dark inline text on the surfaces darkened above → readable. */ |
| 907 |
#mss-root[data-theme="dark"] .mss-native [style*="color: #333"], |
| 908 |
#mss-root[data-theme="dark"] .mss-native [style*="color:#333"], |
| 909 |
#mss-root[data-theme="dark"] .mss-native [style*="color: #000"], |
| 910 |
#mss-root[data-theme="dark"] .mss-native [style*="color:#000"], |
| 911 |
#mss-root[data-theme="dark"] .mss-native [style*="color: #666"], |
| 912 |
#mss-root[data-theme="dark"] .mss-native [style*="color:#666"]{color:var(--text) !important} |
| 913 |
#mss-root[data-theme="dark"] .mss-native input[type=text],#mss-root[data-theme="dark"] .mss-native input[type=url],#mss-root[data-theme="dark"] .mss-native input[type=number],#mss-root[data-theme="dark"] .mss-native input[type=email],#mss-root[data-theme="dark"] .mss-native textarea,#mss-root[data-theme="dark"] .mss-native select{background:var(--field-bg) !important;color:var(--text) !important;border-color:var(--border) !important} |
| 914 |
/* Checkboxes/radios: core paints them white-on-dark-border, which glares against this |
| 915 |
box. Unchecked gets the field surface with a visible border; checked gets the brand |
| 916 |
accent, which keeps enough contrast for core's white ::before tick. */ |
| 917 |
#mss-root[data-theme="dark"] .mss-native input[type=checkbox], |
| 918 |
#mss-root[data-theme="dark"] .mss-native input[type=radio]{background:var(--field-bg) !important;border-color:#6b7280 !important} |
| 919 |
#mss-root[data-theme="dark"] .mss-native input[type=checkbox]:checked, |
| 920 |
#mss-root[data-theme="dark"] .mss-native input[type=radio]:checked{background:var(--accent) !important;border-color:var(--accent) !important} |
| 921 |
/* Core's .button is painted light by wp-admin; keep it legible on the dark surface. |
| 922 |
Destructive buttons (the builder paints them red) are left alone. */ |
| 923 |
#mss-root[data-theme="dark"] .mss-native .button, |
| 924 |
#mss-root[data-theme="dark"] .mss-native .button-secondary{background:var(--card-2) !important;color:var(--accent) !important;border-color:rgba(102,126,234,.45) !important;text-shadow:none !important} |
| 925 |
#mss-root[data-theme="dark"] .mss-native .button:hover, |
| 926 |
#mss-root[data-theme="dark"] .mss-native .button-secondary:hover{background:var(--grad-soft) !important;color:var(--text) !important} |
| 927 |
#mss-root[data-theme="dark"] .mss-native .button-primary{background:var(--grad) !important;color:#fff !important;border-color:transparent !important} |
| 928 |
/* .remove-schema-type is a text-style .button (red text, no fill) — keep it red rather |
| 929 |
than letting the .button rule above recolour it. .remove-faq-item / .remove-item are |
| 930 |
solid-red fills with white text and are deliberately left untouched. */ |
| 931 |
#mss-root[data-theme="dark"] .mss-native .remove-schema-type, |
| 932 |
#mss-root[data-theme="dark"] .mss-native .remove-schema-type .dashicons{color:#f87171 !important;border-color:rgba(248,113,113,.45) !important} |
| 933 |
</style> |
| 934 |
<?php |
| 935 |
} |
| 936 |
} |
| 937 |
|