| @@ -208,10 +208,10 @@ | ||
| 208 | 208 | if ($conflict_handler->og_title_needs_replacement()) { |
| 209 | 209 | $title = $conflict_handler->get_metasync_title(); |
| 210 | 210 | if (!empty($title)) { |
| 211 | 211 | $title_escaped = esc_attr($title); |
| 212 | - echo '<meta property="og:title" content="' . $title_escaped . '" data-metasync-seo="custom" />' . "\n"; | |
| 213 | - echo '<meta name="twitter:title" content="' . $title_escaped . '" data-metasync-seo="custom" />' . "\n"; | |
| 212 | + echo '<meta property="og:title" content="' . $title_escaped . '" data-metasync-seo="custom" />' . "\n"; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- value already escaped via esc_attr() above; the sniff cannot track custom escaped variables | |
| 213 | + echo '<meta name="twitter:title" content="' . $title_escaped . '" data-metasync-seo="custom" />' . "\n"; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- value already escaped via esc_attr() above; the sniff cannot track custom escaped variables | |
| 214 | 214 | } |
| 215 | 215 | } |
| 216 | 216 | |
| 217 | 217 | // With an active third-party SEO plugin, that plugin emits the description |
| @@ -243,9 +243,9 @@ | ||
| 243 | 243 | return; |
| 244 | 244 | } |
| 245 | 245 | |
| 246 | 246 | // Which stored value wins is decided in one place, so the global |
| 247 | - // "SEO Title & Description Priority" setting reaches this emitter | |
| 247 | + // "SEO Meta Priority" setting reaches this emitter | |
| 248 | 248 | // without a second copy of the rule. Under the default this is still |
| 249 | 249 | // the customer's description; under OTTO priority the chain hands back |
| 250 | 250 | // OTTO's value and falls back to the custom one where OTTO has none. |
| 251 | 251 | $resolved = Metasync_Seo_Precedence::resolve($post_id, Metasync_Seo_Precedence::FIELD_DESCRIPTION); |
| @@ -298,9 +298,9 @@ | ||
| 298 | 298 | $marker = ' data-metasync-seo="custom"'; |
| 299 | 299 | } |
| 300 | 300 | // Standard meta description |
| 301 | 301 | if (!$defer_meta_description) { |
| 302 | - echo '<meta name="description" content="' . $description_escaped . '"' . $marker . ' />' . "\n"; | |
| 302 | + echo '<meta name="description" content="' . $description_escaped . '"' . $marker . ' />' . "\n"; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- value already escaped via esc_attr() above; the sniff cannot track custom escaped variables | |
| 303 | 303 | } |
| 304 | 304 | |
| 305 | 305 | // og:description / twitter:description are Open Graph & social tags, so they |
| 306 | 306 | // answer to the site-wide Social Media & Open Graph switch as well as the |
| @@ -314,11 +314,11 @@ | ||
| 314 | 314 | // it belongs to the SEO title/description feature, which has its own setting. |
| 315 | 315 | if (!$defer_og_description |
| 316 | 316 | && !Metasync_OpenGraph::is_social_output_disabled($post_id)) { |
| 317 | 317 | // Open Graph description |
| 318 | - echo '<meta property="og:description" content="' . $description_escaped . '"' . $marker . ' />' . "\n"; | |
| 318 | + echo '<meta property="og:description" content="' . $description_escaped . '"' . $marker . ' />' . "\n"; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- value already escaped via esc_attr() above; the sniff cannot track custom escaped variables | |
| 319 | 319 | // Twitter description |
| 320 | - echo '<meta name="twitter:description" content="' . $description_escaped . '"' . $marker . ' />' . "\n"; | |
| 320 | + echo '<meta name="twitter:description" content="' . $description_escaped . '"' . $marker . ' />' . "\n"; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- value already escaped via esc_attr() above; the sniff cannot track custom escaped variables | |
| 321 | 321 | } |
| 322 | 322 | } |
| 323 | 323 | } |
| 324 | 324 | |
| @@ -345,9 +345,9 @@ | ||
| 345 | 345 | return $title; |
| 346 | 346 | } |
| 347 | 347 | |
| 348 | 348 | // Which stored value wins is decided in one place, so the global |
| 349 | - // "SEO Title & Description Priority" setting reaches this filter | |
| 349 | + // "SEO Meta Priority" setting reaches this filter | |
| 350 | 350 | // without a second copy of the rule. Under the default the customer's |
| 351 | 351 | // title still wins; under OTTO priority the chain hands back OTTO's |
| 352 | 352 | // value and falls back to the custom one where OTTO has none. |
| 353 | 353 | // |
| @@ -420,9 +420,9 @@ | ||
| 420 | 420 | /** |
| 421 | 421 | * Filter document title parts (for themes using wp_get_document_title) |
| 422 | 422 | * |
| 423 | 423 | * Which stored value wins is decided by Metasync_Seo_Precedence, so this |
| 424 | - * filter follows the global "SEO Title & Description Priority" setting | |
| 424 | + * filter follows the global "SEO Meta Priority" setting | |
| 425 | 425 | * without restating the order. |
| 426 | 426 | * |
| 427 | 427 | * @param array $title_parts Title parts array |
| 428 | 428 | * @return array Modified title parts |
| @@ -944,8 +944,17 @@ | ||
| 944 | 944 | 'activeSeoPlugins' => array( |
| 945 | 945 | 'yoast' => defined('WPSEO_VERSION'), |
| 946 | 946 | 'rankmath' => defined('RANK_MATH_VERSION'), |
| 947 | 947 | 'aioseo' => defined('AIOSEO_VERSION') || class_exists('AIOSEO\\Plugin\\AIOSEO'), |
| 948 | + ), | |
| 949 | + // Breadcrumb Title Override visibility. False only when MetaSync | |
| 950 | + // breadcrumbs are off AND no Yoast/Rank Math breadcrumb provider is | |
| 951 | + // active — in that state the override can never reach a trail. | |
| 952 | + // Stored overrides are never deleted, so this is display-only. | |
| 953 | + 'breadcrumbs' => array( | |
| 954 | + 'titleFieldEnabled' => class_exists('Metasync_Breadcrumbs') | |
| 955 | + ? Metasync_Breadcrumbs::is_breadcrumb_title_meaningful() | |
| 956 | + : true, | |
| 948 | 957 | ), |
| 949 | 958 | 'wpmlEntries' => $wpml_entries, |
| 950 | 959 | // '1' when enabled, '' when disabled. wp_localize_script() casts |
| 951 | 960 | // top-level scalars with (string), so a raw boolean false would |