| @@ -101,12 +101,15 @@ | ||
| 101 | 101 | if ($description === '') { |
| 102 | 102 | return; |
| 103 | 103 | } |
| 104 | 104 | |
| 105 | - // Ensure description is within optimal length (150-160 characters) | |
| 106 | - if (strlen($description) > 160) { | |
| 107 | - $description = wp_trim_words($description, 25, '...'); | |
| 108 | - } | |
| 105 | + // Keep the rendered description within the ~160 characters search | |
| 106 | + // engines display. Measure and cut in CHARACTERS: strlen() counts | |
| 107 | + // BYTES, so a Cyrillic/CJK description tripped a limit it was nowhere | |
| 108 | + // near, and wp_trim_words() cuts by WORD COUNT, so a long-worded | |
| 109 | + // description sailed past the cap entirely. Three units, three | |
| 110 | + // different answers. | |
| 111 | + $description = $this->trim_to_length($description, self::DESCRIPTION_MAX_LENGTH); | |
| 109 | 112 | |
| 110 | 113 | // Opens the block through SEO_Manager so its closing comment, printed |
| 111 | 114 | // on wp_head at priority 99, knows an opener was emitted. |
| 112 | 115 | \ThinkRank\Frontend\SEO_Manager::note_opening_comment(); |
| @@ -115,8 +118,36 @@ | ||
| 115 | 118 | echo "<!-- /ThinkRank SEO Meta Description -->\n"; |
| 116 | 119 | } |
| 117 | 120 | |
| 118 | 121 | /** |
| 122 | + * Characters search engines display for a meta description. | |
| 123 | + * | |
| 124 | + * @since 2.2.0 | |
| 125 | + * @var int | |
| 126 | + */ | |
| 127 | + private const DESCRIPTION_MAX_LENGTH = 160; | |
| 128 | + | |
| 129 | + /** | |
| 130 | + * Trim a description to a character budget, multibyte-safe. | |
| 131 | + * | |
| 132 | + * Cuts on a word boundary when one is available inside the budget, so the | |
| 133 | + * result does not end mid-word; falls back to a hard character cut for | |
| 134 | + * scripts that do not use spaces (CJK), where a word-boundary search would | |
| 135 | + * find nothing and return the string untouched. | |
| 136 | + * | |
| 137 | + * @since 2.2.0 | |
| 138 | + * @param string $description Description text. | |
| 139 | + * @param int $limit Maximum length in characters, ellipsis included. | |
| 140 | + * @return string | |
| 141 | + */ | |
| 142 | + private function trim_to_length(string $description, int $limit): string { | |
| 143 | + // The implementation moved to Seo_Text so the four other | |
| 144 | + // description paths could stop carrying the broken version of it | |
| 145 | + // (#687). This stays as the local name the author-archive code reads. | |
| 146 | + return \ThinkRank\Core\Seo_Text::trim_to_length($description, $limit); | |
| 147 | + } | |
| 148 | + | |
| 149 | + /** | |
| 119 | 150 | * Modify document title for author archives |
| 120 | 151 | * |
| 121 | 152 | * @since 1.0.0 |
| 122 | 153 | * @param string $title Original title |
| @@ -261,9 +292,14 @@ | ||
| 261 | 292 | // Default to true (enabled) |
| 262 | 293 | $enabled = $settings->get('author_archives_enabled', true); |
| 263 | 294 | |
| 264 | 295 | if (!$enabled) { |
| 265 | - wp_safe_redirect(home_url(), 301); | |
| 296 | + // 302, not 301. This redirect lasts exactly as long as the | |
| 297 | + // setting stays off, but a 301 is cached by browsers and CDNs | |
| 298 | + // indefinitely — so turning author archives back on could not | |
| 299 | + // undo it for anyone who had already been redirected, and there | |
| 300 | + // was no server-side way to fix that. | |
| 301 | + wp_safe_redirect(home_url(), 302); | |
| 266 | 302 | exit; |
| 267 | 303 | } |
| 268 | 304 | } |
| 269 | 305 | } |