
本文介绍如何在 WordPress 自定义 A-Z 字典索引中,将带重音符号的字母(如 É、È、Ê)统一归入对应基础字母(如 E)分组,避免因 sanitize_title() 过早处理导致的分组错乱问题。
本文介绍如何在 wordpress 自定义 a-z 字典索引中,将带重音符号的字母(如 É、È、Ê)统一归入对应基础字母(如 e)分组,避免因 `sanitize_title()` 过早处理导致的分组错乱问题。
在构建多语言词典类网站时,A-Z 索引的字母分组必须兼顾语言特性。法语、西班牙语等语言中大量使用带重音的字母(如 É, À, Ñ),而 WordPress 默认的 sanitize_title() 函数会将这些字符转为 ASCII 形式(如 É → e),但其内部逻辑依赖于 remove_accents(),该函数对某些 Unicode 字符处理不一致,且若在提取首字母前就调用 sanitize_title(),会导致原始字符信息丢失——例如 École 和 Email 的首字母被分别处理为 e 和 e,看似一致,但在实际字符串比较中却因编码或截取方式差异(如未指定 UTF-8)引发分组断裂。
根本原因在于原代码中直接使用 get_the_title()[0] 截取首字符(PHP 7.4+ 虽支持字符串下标访问 UTF-8 字符,但存在字节级风险),且过早对整标题调用 sanitize_title(),破坏了原始重音结构,使后续 strtoupper() 无法正确识别语言上下文。
✅ 正确做法是:先以 UTF-8 安全方式提取首字符 → 统一转为大写 → 再标准化(去重音)→ 最后用于分组判断。关键使用 mb_substr() 指定 'UTF-8' 编码,并配合 mb_strtoupper() 保障多语言大写转换准确性。
以下是优化后的核心逻辑(兼容 PHP 7.2+ 及 WordPress 多语言环境):
<?php
$letter = '';
while ($dictionnaire->have_posts()) {
$dictionnaire->the_post();
// 安全提取首字符(UTF-8 意识)、转大写、去重音、标准化为小写键(可选)
$first_char = mb_substr(get_the_title(), 0, 1, 'UTF-8');
$upper_char = mb_strtoupper($first_char, 'UTF-8');
$sanitized_char = sanitize_title($upper_char); // 此时仅处理单字符,精准去重音
if ($letter !== $sanitized_char) {
// 关闭上一组容器
if ($letter !== '') {
echo '</div></section>';
}
$letter = $sanitized_char;
// 输出新分组容器(ID 使用标准化字母,确保 HTML ID 合法)
echo '<section id="' . esc_attr($letter) . '" class="wp-block-group letter-section">';
echo '<div class="big-letter"><p>' . esc_html($letter) . '</p></div>';
echo '<div class="wp-block-group__inner-container d-grid columns-3">';
}
}
// 循环结束后关闭最后一组
if ($letter !== '') {
echo '</div></section>';
}
?>? 关键要点与注意事项:
- ✅ 始终显式声明 'UTF-8' 编码:mb_substr() 和 mb_strtoupper() 必须传入第三个参数,否则在非 UTF-8 locale 下可能返回空或乱码;
- ✅ sanitize_title() 应作用于单字符:避免对整标题预处理,防止干扰首字母识别逻辑;
- ✅ HTML id 属性需符合规范:使用 esc_attr() 转义 $letter,防止重音字符生成非法 ID(如 É 不合法,但 e 合法);
- ⚠️ 避免 get_the_title()[0]:该写法在 PHP 8+ 中对多字节字符不可靠,务必改用 mb_substr();
- ? 扩展建议:如需支持 Æ, Ø, Å 等北欧字符,可自定义映射数组,在 sanitize_title() 后追加替换逻辑(如 'ae' => 'a', 'oe' => 'o');
- ? 调试技巧:临时加入 error_log("Title: " . get_the_title() . " | First: '$first_char' | Upper: '$upper_char' | Sanitized: '$sanitized_char'"); 验证每步输出。
通过此方案,Éclair、Été、Email、Eau 将全部归入


















