PluginProbe
Search Atlas SEO – OTTO AI SEO Automation for WordPress / 2.7.1
Search Atlas SEO – OTTO AI SEO Automation for WordPress v2.7.1
2.7.1 2.7.2 2.7.0 2.6.26 2.6.25 2.6.24 2.6.23 2.6.22 2.6.21 2.6.20 2.6.19 2.6.18 2.6.17 2.6.16 2.6.15 2.6.14 2.6.13 2.6.12 2.6.11 2.6.10 2.6.9 2.6.8 2.6.7 2.6.6 2.6.5 All 141 releases
← All changes | includes/class-metasync-seo-suite.php +109 -54 2.6.23 → 2.7.1 View file →
@@ -69,9 +69,9 @@
69 69 * context so this box never engages in either.
70 70 */
71 71 private function is_block_editor_request()
72 72 {
73 - if (!empty($_REQUEST['meta-box-loader'])) {
73 + if (!empty($_REQUEST['meta-box-loader'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only request flag for meta box registration
74 74 return true;
75 75 }
76 76 $screen = get_current_screen();
77 77 return $screen && $screen->is_block_editor();
@@ -170,10 +170,33 @@
170 170 if (method_exists('Metasync_OpenGraph', 'strip_auto_draft_title')
171 171 && defined('Metasync_OpenGraph::AUTO_DRAFT_PRONE_KEYS')
172 172 && in_array($key, Metasync_OpenGraph::AUTO_DRAFT_PRONE_KEYS, true)
173 173 ) {
174 - return Metasync_OpenGraph::strip_auto_draft_title($value);
174 + $value = Metasync_OpenGraph::strip_auto_draft_title($value);
175 175 }
176 + // A social title that merely mirrors the post title is the old pre-fill's
177 + // snapshot — stale the moment the post is renamed — not a customization.
178 + // Collapsed so the field renders empty (the default stays visible as the
179 + // placeholder) and the shared save handler stores nothing for it.
180 + // @phpstan-ignore-next-line function.alreadyNarrowedType
181 + if (method_exists('Metasync_OpenGraph', 'strip_title_snapshot')
182 + && defined('Metasync_OpenGraph::TITLE_DEFAULTED_KEYS')
183 + && in_array($key, Metasync_OpenGraph::TITLE_DEFAULTED_KEYS, true)
184 + && is_string($value)
185 + ) {
186 + $value = Metasync_OpenGraph::strip_title_snapshot($post_id, $key, $value);
187 + }
188 + // A social description that merely mirrors the resolved excerpt is the
189 + // same kind of snapshot — stale the moment the excerpt or content
190 + // changes — collapsed for the same reason as the title above.
191 + // @phpstan-ignore-next-line function.alreadyNarrowedType
192 + if (method_exists('Metasync_OpenGraph', 'strip_description_snapshot')
193 + && defined('Metasync_OpenGraph::DESCRIPTION_DEFAULTED_KEYS')
194 + && in_array($key, Metasync_OpenGraph::DESCRIPTION_DEFAULTED_KEYS, true)
195 + && is_string($value)
196 + ) {
197 + $value = Metasync_OpenGraph::strip_description_snapshot($post_id, $key, $value);
198 + }
176 199 return (string) $value;
177 200 }
178 201
179 202 private static function checked_attr($cond)
@@ -204,9 +227,8 @@
204 227 public function render($post)
205 228 {
206 229 $P = $this->present;
207 230 $id = $post->ID;
208 - $a = 'esc_attr';
209 231
210 232 $managed = $this->is_managed_page($id);
211 233
212 234 $has_seo = isset($P['metasync-seo-meta']) || isset($P['metasync-seo-lps-notice']);
@@ -221,12 +243,26 @@
221 243
222 244 // Current values.
223 245 $seo_title = self::v($id, '_metasync_seo_title');
224 246 $seo_desc = self::v($id, '_metasync_seo_desc');
225 - $otto_title = self::v($id, '_metasync_otto_title');
226 - $otto_desc = self::v($id, '_metasync_otto_description');
227 247 $otto_kw = self::v($id, '_metasync_otto_keywords');
228 248
249 + // The greyed-out value each field shows when left blank: OTTO's
250 + // suggestion, or the imported value where OTTO is silent. Which tier
251 + // that is — and whether OTTO counts at all, since the per-post "Disable
252 + // OTTO" toggle makes its stored suggestion dead data — is
253 + // Metasync_Seo_Precedence's call, not this screen's. Without a ghost the
254 + // fields look completely empty after an import and the customer
255 + // concludes it did nothing.
256 + $title_fallback = Metasync_Seo_Precedence::fallback($id, Metasync_Seo_Precedence::FIELD_TITLE);
257 + $desc_fallback = Metasync_Seo_Precedence::fallback($id, Metasync_Seo_Precedence::FIELD_DESCRIPTION);
258 +
259 + $ghost_title = $title_fallback['value'];
260 + $ghost_desc = $desc_fallback['value'];
261 +
262 + $show_imported_note = $title_fallback['source'] === Metasync_Seo_Precedence::SOURCE_IMPORTED
263 + || $desc_fallback['source'] === Metasync_Seo_Precedence::SOURCE_IMPORTED;
264 +
229 265 // Robots: post meta first, falling back to the site-wide defaults exactly as
230 266 // the standalone Common/Advance Robots boxes do (new option spelling first,
231 267 // then the legacy "mata" spelling).
232 268 $cr = get_post_meta($id, 'metasync_common_robots', true);
@@ -290,10 +326,15 @@
290 326 $opengraph = class_exists('Metasync_OpenGraph') ? Metasync_OpenGraph::get_instance() : null;
291 327 if ($opengraph) {
292 328 $og_defaults = $opengraph->get_default_og_values($id);
293 329 }
294 - $og_title = self::v($id, '_metasync_og_title') ?: $og_defaults['title'];
295 - $og_desc = self::v($id, '_metasync_og_description') ?: $og_defaults['description'];
330 + // Social titles and descriptions render placeholder-only: the default
331 + // (the post title, the resolved excerpt) stays visible in the
332 + // placeholder but is never a form value, so submitting the page cannot
333 + // persist a snapshot of it. Images keep their computed default as a
334 + // real value, matching the standalone OG box.
335 + $og_title = self::v($id, '_metasync_og_title');
336 + $og_desc = self::v($id, '_metasync_og_description');
296 337 $og_image = self::v($id, '_metasync_og_image') ?: $og_defaults['image'];
297 338 $og_type = self::v($id, '_metasync_og_type') ?: 'article';
298 339 $og_url = self::v($id, '_metasync_og_url');
299 340 if ($og_url === '') {
@@ -300,10 +341,17 @@
300 341 $og_url = $opengraph ? $opengraph->get_canonical_url($post) : $pretty;
301 342 }
302 343 $tw_card = self::v($id, '_metasync_twitter_card') ?: 'summary_large_image';
303 344 $tw_site = self::v($id, '_metasync_twitter_site');
304 - $tw_title = self::v($id, '_metasync_twitter_title') ?: $og_title;
305 - $tw_desc = self::v($id, '_metasync_twitter_description') ?: $og_desc;
345 + $tw_title = self::v($id, '_metasync_twitter_title');
346 + // Placeholder-only like the standalone box: when no twitter title is
347 + // stored the placeholder shows the og title if one is set, else the
348 + // default (post) title — the exact chain the standalone OG box uses.
349 + $tw_title_placeholder = ($og_title !== '') ? $og_title : $og_defaults['title'];
350 + // Same chain for the twitter description's placeholder: the og
351 + // description if one is set, else the resolved excerpt default.
352 + $tw_desc_placeholder = ($og_desc !== '') ? $og_desc : $og_defaults['description'];
353 + $tw_desc = self::v($id, '_metasync_twitter_description');
306 354 $tw_image = self::v($id, '_metasync_twitter_image') ?: $og_image;
307 355 $tw_alt = self::v($id, '_metasync_twitter_image_alt');
308 356 $tw_app_iphone = self::v($id, '_metasync_twitter_app_id_iphone');
309 357 $tw_app_ipad = self::v($id, '_metasync_twitter_app_id_ipad');
@@ -364,9 +412,9 @@
364 412 <div class="rail">
365 413 <?php
366 414 $first = true;
367 415 $tab = function ($key, $icon, $label) use (&$first) {
368 - 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>';
416 + echo '<div class="nav' . ($first ? ' active' : '') . '" role="button" tabindex="0" onclick="mssGo(this,\'' . esc_attr($key) . '\')" onkeydown="mssKey(event,this)"><span class="ic">' . esc_html($icon) . '</span> ' . esc_html($label) . '</div>';
369 417 $first = false;
370 418 };
371 419 if ($has_seo) { $tab('seo', '&#128269;', 'SEO'); }
372 420 if ($has_robots) { $tab('robots', '&#129302;', 'Robots'); }
@@ -388,18 +436,21 @@
388 436 };
389 437 ?>
390 438
391 439 <?php if ($has_seo): ?>
392 - <div class="<?php echo $pcls(); ?>" data-p="seo">
440 + <div class="<?php echo esc_attr($pcls()); ?>" data-p="seo">
393 441 <h2 class="p-title">&#128269; Search Appearance</h2>
394 442 <p class="p-sub">Set the SEO Title and Meta Description. Leave blank to use the OTTO suggestion.</p>
443 + <?php if ($show_imported_note): ?>
444 + <p class="p-sub">The greyed-out value below was imported from another SEO plugin. It is used only until OTTO has a suggestion for this page.</p>
445 + <?php endif; ?>
395 446 <div class="field">
396 447 <div class="lbl"><span>SEO Title</span><span class="cc"><span class="tC">0</span>/60</span></div>
397 - <input class="ctrl seoT" name="metasync_seo_title" value="<?php echo $a($seo_title); ?>" placeholder="<?php echo $a($otto_title); ?>" oninput="mssRc()">
448 + <input class="ctrl seoT" name="metasync_seo_title" value="<?php echo esc_attr($seo_title); ?>" placeholder="<?php echo esc_attr($ghost_title); ?>" oninput="mssRc()">
398 449 </div>
399 450 <div class="field">
400 451 <div class="lbl"><span>Meta Description</span><span class="cc"><span class="dC">0</span>/160</span></div>
401 - <textarea class="ctrl seoD" name="metasync_seo_desc" placeholder="<?php echo $a($otto_desc); ?>" oninput="mssRc()"><?php echo esc_textarea($seo_desc); ?></textarea>
452 + <textarea class="ctrl seoD" name="metasync_seo_desc" placeholder="<?php echo esc_attr($ghost_desc); ?>" oninput="mssRc()"><?php echo esc_textarea($seo_desc); ?></textarea>
402 453 </div>
403 454 <?php if ($otto_kw !== ''): ?>
404 455 <div class="field">
405 456 <div class="lbl"><span>Focus Keyword</span><span class="ro-badge">Managed by OTTO</span></div>
@@ -409,16 +460,16 @@
409 460 <?php endif; ?>
410 461 <div class="sec">Preview</div>
411 462 <div class="gprev">
412 463 <div class="u"><?php echo esc_html($prev_url_disp); ?></div>
413 - <div class="ti gT"><?php echo esc_html($seo_title ?: ($otto_title ?: get_the_title($id))); ?></div>
414 - <div class="de gD"><?php echo esc_html($seo_desc ?: ($otto_desc ?: 'No description set.')); ?></div>
464 + <div class="ti gT"><?php echo esc_html($seo_title ?: ($ghost_title ?: get_the_title($id))); ?></div>
465 + <div class="de gD"><?php echo esc_html($seo_desc ?: ($ghost_desc ?: 'No description set.')); ?></div>
415 466 </div>
416 467 </div>
417 468 <?php endif; ?>
418 469
419 470 <?php if ($has_robots): ?>
420 - <div class="<?php echo $pcls(); ?>" data-p="robots">
471 + <div class="<?php echo esc_attr($pcls()); ?>" data-p="robots">
421 472 <h2 class="p-title">&#129302; Robots Meta</h2>
422 473 <p class="p-sub">Crawler directives for this post. These are independent flags &mdash; combine as needed.</p>
423 474 <?php if ($has_crob): ?>
424 475 <div class="sec">Common directives</div>
@@ -433,9 +484,10 @@
433 484 'nosnippet' => array('No Snippet', 'No text snippet in results'),
434 485 );
435 486 foreach ($common as $key => $c): ?>
436 487 <label class="chip">
437 - <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) : ''; ?>>
488 + <input type="checkbox" name="common_robots_meta[<?php echo esc_attr($key); ?>]" value="<?php echo esc_attr($key); ?>"<?php // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- checked_attr() returns the validated checked attribute.
489 + echo isset($cr[$key]) ? esc_attr(self::checked_attr($cr[$key] === $key)) : ''; ?>>
438 490 <span class="box">&#10003;</span><div><?php echo esc_html($c[0]); ?><small><?php echo esc_html($c[1]); ?></small></div>
439 491 </label>
440 492 <?php endforeach; ?>
441 493 </div>
@@ -444,13 +496,13 @@
444 496 <div class="sec">Advanced limits <span class="sec-note">&mdash; tick a limit to apply it</span></div>
445 497 <div class="row">
446 498 <div class="field">
447 499 <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">&#10003;</span><div>Max Snippet</div></label>
448 - <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">
500 + <input class="ctrl" type="number" name="advanced_robots_meta[max-snippet][length]" value="<?php echo esc_attr($ar_snip_l); ?>" min="-1" placeholder="e.g. 160">
449 501 <div class="hint">Max snippet length in characters.</div></div>
450 502 <div class="field">
451 503 <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">&#10003;</span><div>Max Video Preview</div></label>
452 - <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">
504 + <input class="ctrl" type="number" name="advanced_robots_meta[max-video-preview][length]" value="<?php echo esc_attr($ar_vid_l); ?>" min="-1" placeholder="e.g. -1">
453 505 <div class="hint">Max preview duration in seconds.</div></div>
454 506 </div>
455 507 <div class="field">
456 508 <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">&#10003;</span><div>Max Image Preview</div></label>
@@ -463,14 +515,14 @@
463 515 </div>
464 516 <?php endif; ?>
465 517
466 518 <?php if ($has_canon): ?>
467 - <div class="<?php echo $pcls(); ?>" data-p="canonical">
519 + <div class="<?php echo esc_attr($pcls()); ?>" data-p="canonical">
468 520 <h2 class="p-title">&#128279; Canonical URL</h2>
469 521 <p class="p-sub">Point search engines to the preferred version of this content.</p>
470 522 <div class="field">
471 523 <div class="lbl"><span>Canonical URL</span></div>
472 - <input class="ctrl" type="text" name="post_canonical_url_meta" value="<?php echo $a($canon); ?>" placeholder="<?php echo $a($pretty); ?>">
524 + <input class="ctrl" type="text" name="post_canonical_url_meta" value="<?php echo esc_attr($canon); ?>" placeholder="<?php echo esc_attr($pretty); ?>">
473 525 <div class="hint">Leave blank to use this post's own URL.</div>
474 526 </div>
475 527 </div>
476 528 <?php endif; ?>
@@ -475,13 +527,14 @@
475 527 </div>
476 528 <?php endif; ?>
477 529
478 530 <?php if ($has_redir): ?>
479 - <div class="<?php echo $pcls(); ?>" data-p="redirect">
531 + <div class="<?php echo esc_attr($pcls()); ?>" data-p="redirect">
480 532 <h2 class="p-title">&#8618;&#65039; Redirection</h2>
481 533 <p class="p-sub">Send visitors of this post somewhere else.</p>
482 534 <div class="switch-card">
483 - <label class="switch"><input type="checkbox" name="post_redirect_meta[enable]" value="true"<?php echo self::checked_attr($rd_en); ?>></label>
535 + <label class="switch"><input type="checkbox" name="post_redirect_meta[enable]" value="true"<?php // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- checked_attr() returns the validated checked attribute.
536 + echo esc_attr(self::checked_attr($rd_en)); ?>></label>
484 537 <div class="m"><b>Enable redirection</b><span>Send visitors of this post to another URL</span></div>
485 538 </div>
486 539 <div class="row">
487 540 <div class="field"><div class="lbl"><span>Type</span></div>
@@ -492,36 +545,37 @@
492 545 <option value="410"<?php selected($rd_type, '410'); ?>>410 Content Deleted</option>
493 546 <option value="451"<?php selected($rd_type, '451'); ?>>451 Content Unavailable</option>
494 547 </select></div>
495 548 <div class="field"><div class="lbl"><span>Destination URL</span></div>
496 - <input class="ctrl" type="text" name="post_redirect_meta[url]" value="<?php echo $a($rd_url); ?>" placeholder="https://example.com/new-url/"></div>
549 + <input class="ctrl" type="text" name="post_redirect_meta[url]" value="<?php echo esc_attr($rd_url); ?>" placeholder="https://example.com/new-url/"></div>
497 550 </div>
498 551 </div>
499 552 <?php endif; ?>
500 553
501 554 <?php if ($has_social): ?>
502 - <div class="<?php echo $pcls(); ?>" data-p="social">
555 + <div class="<?php echo esc_attr($pcls()); ?>" data-p="social">
503 556 <h2 class="p-title">&#128226; Social &amp; Open Graph</h2>
504 557 <p class="p-sub">How this post looks when shared on social platforms.</p>
505 558 <div class="switch-card">
506 - <label class="switch"><input type="checkbox" name="_metasync_og_enabled" value="1"<?php echo self::checked_attr($og_en); ?>></label>
559 + <label class="switch"><input type="checkbox" name="_metasync_og_enabled" value="1"<?php // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- checked_attr() returns the validated checked attribute.
560 + echo esc_attr(self::checked_attr($og_en)); ?>></label>
507 561 <div class="m"><b>Enable Open Graph &amp; Social Media Tags</b><span>Adds Open Graph + Twitter Card tags for better sharing</span></div>
508 562 </div>
509 563
510 564 <div class="subhead"><span class="sq"></span> Open Graph</div>
511 - <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>
512 - <div class="field"><div class="lbl"><span>Description (og:description)</span></div><textarea class="ctrl" name="_metasync_og_description" maxlength="155" placeholder="Post excerpt&hellip;" oninput="mssSocial()"><?php echo esc_textarea($og_desc); ?></textarea></div>
565 + <div class="field"><div class="lbl"><span>Title (og:title)</span></div><input class="ctrl" name="_metasync_og_title" maxlength="60" value="<?php echo esc_attr($og_title); ?>" placeholder="<?php echo esc_attr($og_defaults['title']); ?>" oninput="mssSocial()"></div>
566 + <div class="field"><div class="lbl"><span>Description (og:description)</span></div><textarea class="ctrl" name="_metasync_og_description" maxlength="155" placeholder="<?php echo esc_attr($og_defaults['description']); ?>" oninput="mssSocial()"><?php echo esc_textarea($og_desc); ?></textarea></div>
513 567 <div class="field"><div class="lbl"><span>Image (og:image)</span></div>
514 - <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>
568 + <div class="mss-imgrow"><input class="ctrl ogimg" type="url" name="_metasync_og_image" value="<?php echo esc_attr($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>
515 569 <div class="hint">Recommended 1200&times;630px.</div></div>
516 570 <div class="row">
517 571 <div class="field"><div class="lbl"><span>Type (og:type)</span></div>
518 572 <select class="ctrl" name="_metasync_og_type">
519 573 <?php foreach (array('article', 'website', 'blog', 'product', 'video', 'music') as $t): ?>
520 - <option value="<?php echo $a($t); ?>"<?php selected($og_type, $t); ?>><?php echo esc_html(ucfirst($t)); ?></option>
574 + <option value="<?php echo esc_attr($t); ?>"<?php selected($og_type, $t); ?>><?php echo esc_html(ucfirst($t)); ?></option>
521 575 <?php endforeach; ?>
522 576 </select></div>
523 - <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>
577 + <div class="field"><div class="lbl"><span>URL (og:url)</span></div><input class="ctrl" type="url" name="_metasync_og_url" value="<?php echo esc_attr($og_url); ?>" placeholder="<?php echo esc_attr($pretty); ?>"<?php echo $post->post_status === 'auto-draft' ? ' disabled' : ''; ?>></div>
524 578 </div>
525 579
526 580 <div class="subhead"><span class="sq"></span> Twitter Card</div>
527 581 <div class="field"><div class="lbl"><span>Card Type</span></div>
@@ -531,36 +585,36 @@
531 585 <option value="app"<?php selected($tw_card, 'app'); ?>>App</option>
532 586 <option value="player"<?php selected($tw_card, 'player'); ?>>Player</option>
533 587 </select></div>
534 588 <div class="row">
535 - <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>
536 - <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>
589 + <div class="field"><div class="lbl"><span>Twitter Site</span></div><input class="ctrl" name="_metasync_twitter_site" value="<?php echo esc_attr($tw_site); ?>" placeholder="@yoursite"></div>
590 + <div class="field"><div class="lbl"><span>Twitter Title</span></div><input class="ctrl" name="_metasync_twitter_title" maxlength="70" value="<?php echo esc_attr($tw_title); ?>" placeholder="<?php echo esc_attr($tw_title_placeholder); ?>" oninput="mssSocial()"></div>
537 591 </div>
538 - <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>
592 + <div class="field"><div class="lbl"><span>Twitter Description</span></div><textarea class="ctrl" name="_metasync_twitter_description" maxlength="200" placeholder="<?php echo esc_attr($tw_desc_placeholder); ?>" oninput="mssSocial()"><?php echo esc_textarea($tw_desc); ?></textarea></div>
539 593 <div class="row">
540 594 <div class="field"><div class="lbl"><span>Twitter Image</span></div>
541 - <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>
542 - <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>
595 + <div class="mss-imgrow"><input class="ctrl twimg" type="url" name="_metasync_twitter_image" value="<?php echo esc_attr($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>
596 + <div class="field"><div class="lbl"><span>Image Alt</span></div><input class="ctrl" name="_metasync_twitter_image_alt" maxlength="420" value="<?php echo esc_attr($tw_alt); ?>" placeholder="Accessibility description"></div>
543 597 </div>
544 598
545 599 <div class="mssTwApp" style="display:<?php echo $tw_card === 'app' ? 'block' : 'none'; ?>">
546 600 <div class="subhead"><span class="sq"></span> App Card</div>
547 601 <div class="row">
548 - <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>
549 - <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>
602 + <div class="field"><div class="lbl"><span>iPhone App ID</span></div><input class="ctrl" name="_metasync_twitter_app_id_iphone" value="<?php echo esc_attr($tw_app_iphone); ?>" placeholder="307234931"<?php echo esc_attr($tw_app_disabled); ?>></div>
603 + <div class="field"><div class="lbl"><span>iPad App ID</span></div><input class="ctrl" name="_metasync_twitter_app_id_ipad" value="<?php echo esc_attr($tw_app_ipad); ?>" placeholder="307234931"<?php echo esc_attr($tw_app_disabled); ?>></div>
550 604 </div>
551 - <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>
605 + <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 esc_attr($tw_app_gp); ?>" placeholder="com.android.app"<?php echo esc_attr($tw_app_disabled); ?>></div>
552 606 <div class="row">
553 - <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>
554 - <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>
607 + <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 esc_attr($tw_app_url_iphone); ?>" placeholder="myapp://"<?php echo esc_attr($tw_app_disabled); ?>></div>
608 + <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 esc_attr($tw_app_url_ipad); ?>" placeholder="myapp://"<?php echo esc_attr($tw_app_disabled); ?>></div>
555 609 </div>
556 610 <div class="row">
557 - <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>
611 + <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 esc_attr($tw_app_url_gp); ?>" placeholder="myapp://"<?php echo esc_attr($tw_app_disabled); ?>></div>
558 612 <div class="field"><div class="lbl"><span>App Store Country</span></div>
559 - <select class="ctrl" name="_metasync_twitter_app_country"<?php echo $tw_app_disabled; ?>>
613 + <select class="ctrl" name="_metasync_twitter_app_country"<?php echo esc_attr($tw_app_disabled); ?>>
560 614 <option value=""<?php selected($tw_app_country, ''); ?>>US (Default)</option>
561 615 <?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): ?>
562 - <option value="<?php echo $a($code); ?>"<?php selected($tw_app_country, $code); ?>><?php echo esc_html($country); ?></option>
616 + <option value="<?php echo esc_attr($code); ?>"<?php selected($tw_app_country, $code); ?>><?php echo esc_html($country); ?></option>
563 617 <?php endforeach; ?>
564 618 </select>
565 619 <div class="hint">Required if your app is not available in the US App Store.</div>
566 620 </div>
@@ -567,12 +621,12 @@
567 621 </div>
568 622 </div>
569 623 <div class="mssTwPlayer" style="display:<?php echo $tw_card === 'player' ? 'block' : 'none'; ?>">
570 624 <div class="subhead"><span class="sq"></span> Player Card</div>
571 - <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>
625 + <div class="field"><div class="lbl"><span>Player URL</span></div><input class="ctrl" type="url" name="_metasync_twitter_player" value="<?php echo esc_attr($tw_player); ?>" placeholder="https://example.com/player"<?php echo esc_attr($tw_player_disabled); ?>></div>
572 626 <div class="row">
573 - <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>
574 - <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>
627 + <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 esc_attr($tw_player_w); ?>" placeholder="1280"<?php echo esc_attr($tw_player_disabled); ?>></div>
628 + <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 esc_attr($tw_player_h); ?>" placeholder="720"<?php echo esc_attr($tw_player_disabled); ?>></div>
575 629 </div>
576 630 </div>
577 631
578 632 <div class="subhead"><span class="sq"></span> Social preview</div>
@@ -614,9 +668,9 @@
614 668 </div>
615 669 <?php endif; ?>
616 670
617 671 <?php if ($has_schema): ?>
618 - <div class="<?php echo $pcls(); ?>" data-p="schema">
672 + <div class="<?php echo esc_attr($pcls()); ?>" data-p="schema">
619 673 <h2 class="p-title">&#128208; Schema Markup</h2>
620 674 <div class="mss-native">
621 675 <?php
622 676 if (!empty($this->schema_box['callback'])) {
@@ -629,16 +683,16 @@
629 683 </div>
630 684 <?php endif; ?>
631 685
632 686 <?php if ($has_video): ?>
633 - <div class="<?php echo $pcls(); ?>" data-p="video">
687 + <div class="<?php echo esc_attr($pcls()); ?>" data-p="video">
634 688 <h2 class="p-title">&#127916; Video Sitemap</h2>
635 689 <p class="p-sub">Override auto-detected video data. Leave blank to use auto-detection.</p>
636 - <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>
637 - <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>
638 - <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>
690 + <div class="field"><div class="lbl"><span>Video URL</span></div><input class="ctrl" type="url" name="metasync_video_url" value="<?php echo esc_attr($v_url); ?>" placeholder="https://www.youtube.com/watch?v=..."></div>
691 + <div class="field"><div class="lbl"><span>Thumbnail URL</span></div><input class="ctrl" type="url" name="metasync_video_thumbnail" value="<?php echo esc_attr($v_thumb); ?>" placeholder="https://img.youtube.com/vi/.../hqdefault.jpg"></div>
692 + <div class="field"><div class="lbl"><span>Video Title</span></div><input class="ctrl" name="metasync_video_title" value="<?php echo esc_attr($v_title); ?>" placeholder="Defaults to post title"></div>
639 693 <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>
640 - <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>
694 + <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 esc_attr($v_dur); ?>" placeholder="300"></div>
641 695 </div>
642 696 <?php endif; ?>
643 697
644 698 </div>
@@ -707,9 +761,10 @@
707 761 window.mssSocial=function(){
708 762 var seoT=root.querySelector('.seoT'), seoD=root.querySelector('.seoD');
709 763 var ogTitleEl=byName('_metasync_og_title');
710 764 var baseTitle=mssFld('_metasync_og_title') || (ogTitleEl&&ogTitleEl.getAttribute('placeholder')) || (seoT&&seoT.value.trim()) || 'Untitled';
711 - var baseDesc =mssFld('_metasync_og_description') || (seoD&&seoD.value.trim()) || 'No description set.';
765 + var ogDescEl=byName('_metasync_og_description');
766 + var baseDesc =mssFld('_metasync_og_description') || (ogDescEl&&ogDescEl.getAttribute('placeholder')) || (seoD&&seoD.value.trim()) || 'No description set.';
712 767 var baseImg =mssFld('_metasync_og_image');
713 768 var twTitle=mssFld('_metasync_twitter_title');
714 769 var twDesc =mssFld('_metasync_twitter_description');
715 770 var twImg =mssFld('_metasync_twitter_image');