需求很小:网站要有个搜索。做下来发现,难点不在“能不能搜”,而在“搜的体验顺不顺”。
起点:为什么 WordPress 自带的搜索不行
WordPress 本身是有搜索的,但你得自己放一个入口。最省事的做法是用 get_search_form() 塞进页头——结果是:输入框常年占着导航栏的位置,要么丑,要么在旁边挂一个突兀的按钮。
我想要的效果是:
- 桌面端不占地方,点放大镜才展开
- 手机端一眼可见,别藏在二级菜单
- 只搜文章,不要把“关于”这类页面和附件也搜出来
- 输入框和整个站点的视觉风格一致
方案:把表单挂进导航菜单
WordPress 的 wp_nav_menu_items 过滤器可以在菜单末尾追加任意 HTML。这一点很关键——如果表单挂在导航外面,手机上菜单折叠时它不会跟着走。
add_filter('wp_nav_menu_items', function ($items, $args) {
if (empty($args->theme_location) || $args->theme_location !== 'primary') {
return $items;
}
$id = 'mohenji-search-' . wp_unique_id();
return $items
. '<li class="menu-item mohenji-search">'
. '<form role="search" method="get" action="' . esc_url(home_url('/')) . '">'
. '<label for="' . esc_attr($id) . '">搜索</label>'
. '<input type="search" id="' . esc_attr($id) . '" name="s" placeholder="搜索文章…">'
. '<button type="submit" aria-label="搜索">…</button>'
. '</form></li>';
}, 20, 2);
wp_unique_id() 用来生成唯一 ID——如果页面上有两个搜索框(比如空结果页还有一个),label for 就不会指向错的那个。
只搜文章
默认搜索会把所有 post_type 都扫一遍。加三行限制,范围立刻收窄:
add_action('pre_get_posts', function ($query) {
if (is_admin() || !$query->is_main_query() || !$query->is_search()) {
return;
}
$query->set('post_type', 'post');
});
注意必须先判断 is_main_query(),否则会影响后台的查询。
交互:桌面展开,手机常驻
这里不需要框架,30 行原生 JS 就够:
var box = document.querySelector('.mohenji-search');
var toggle = box.querySelector('label');
var input = box.querySelector('input');
toggle.addEventListener('click', function (e) {
e.preventDefault();
if (box.classList.contains('is-open')) {
input.value.trim() ? box.querySelector('form').submit() : box.classList.remove('is-open');
return;
}
box.classList.add('is-open');
input.focus();
});
// Esc 收起
document.addEventListener('keydown', function (e) {
if (e.key === 'Escape') { box.classList.remove('is-open'); toggle.focus(); }
});
CSS 用 width 过渡实现展开动画,用 @media 让手机端固定为全宽:
.mohenji-search input { width: 0; opacity: 0; transition: width .28s; }
.mohenji-search.is-open input { width: 170px; opacity: 1; }
@media (max-width: 768px) {
.mohenji-search label { display: none; }
.mohenji-search input { width: 100%; opacity: 1; }
}
踩到的三个坑

坑一:输入框有个去不掉的内边框
展开后输入框里总有一圈灰色方框。排查发现是主题里更早定义的 input[type="search"] 样式在起作用,而我写的选择器优先级不够。
解决方式不是疯狂加 !important,而是提高选择器特异性:
.mohenji-search .mohenji-search-input { border: 0; outline: 0; }
同时还要关掉 Safari/Chrome 给 type="search" 加的默认清除按钮:
.mohenji-search-input::-webkit-search-cancel-button { -webkit-appearance: none; display: none; }
坑二:空结果页的搜索表单不受控
用户搜不到东西时,WordPress 会自动渲染一个 get_search_form()。那个表单是主题的默认样式——方角、灰色按钮,跟整站格格不入。
处理思路是不改模板,只加样式:
.search-results .no-results .search-field {
border-radius: 999px;
border: 1.5px solid var(--line-strong);
}
.search-results .no-results .search-submit {
background: var(--sky);
border-radius: 999px;
}
坑三:装饰插图被卡片裁掉了
我想在空结果页放一张插图增加亲和力。第一次用 position: absolute 放在卡片左上角,结果整个被 overflow: hidden 裁掉了——因为卡片内边距只有 30px,而插图有 74px 高。
试了三种方案:
- 绝对定位 + 内边距 → 内容被挤窄
- 作为卡片第一行(
display: block)→ 标题的负外边距把它顶出去了 - 最终方案:放在卡片内部右上角,给右侧内容留
max-width限制
.mohenji-no-results .no-results::after {
content: "";
position: absolute;
top: 30px; right: 32px;
width: 104px; height: 74px;
background: var(--empty-art) center/contain no-repeat;
}
效果
上线后:
- 桌面端点放大镜 → 输入框从右侧滑出 → 按回车搜索
- 手机端菜单展开后,搜索框固定在底部,44px 高,单手可点
- 结果页只显示文章卡片,关键词高亮
- 空结果页有插图和可用的输入框
一点体会
这类小功能最容易翻车的地方,不是逻辑,而是样式冲突。WordPress 主题通常有几十条针对 input 的全局规则,你的组件只要有一个选择器没压住,就会出现奇怪的边框或背景。
我的做法是:写组件样式时,全部带上组件的命名空间(.mohenji-search .xxx),不要裸写 input。这样以后加新组件也不会互相打架。