HUSKY - WooCommerce Product Filter Professional

WooCommerce 滑出式产品筛选器:Slideout 面板设置与修复

WooCommerce 滑出式(off-canvas)产品筛选器能让商店页面保持整洁:筛选器待在屏幕边缘的面板里,访客点击筛选 (Filter) 标签或按钮时才滑入。HUSKY 以内置的 Slideout 扩展提供了这一功能,因此无需主题抽屉或弹窗插件。本指南介绍该面板的工作原理,如何把它限制在商店页和分类页,如何通过您自己的按钮打开它并在筛选后关闭它,以及如何修复无法滚动、被页眉遮挡或根本不出现的面板。

滑出面板、移动模式或主题抽屉

HUSKY 提供三种方式,让筛选器在需要之前不出现在视线中。每个页面只选其一;混用会出现两个筛选器,或者一个什么都打不开的按钮。

  • Slideout(高级 (Advanced) → Slideout,或 [woof_slideout] 短代码):固定在窗口左、右、上或下边缘的面板,带有一个用来打开它的标签。电脑和手机上都能使用。这就是本指南的主题。
  • 移动模式:仅在手机上,筛选器会被一个打开筛选器 (Open filter) 按钮取代,该按钮会以全屏面板的形式打开它。参见移动端筛选器指南。
  • 自动筛选器,且默认隐藏自动筛选器 (Hide auto filter by default) = 是 (Yes):产品上方的一个按钮,会把筛选器向下展开到网格之上。参见产品上方的水平筛选器。

主题或页面构建器提供的抽屉或滑出式侧边栏同样可用,前提是它只显示和隐藏页面加载时就已存在的筛选器 HTML。如果抽屉是在之后才插入内容,表单就永远不会被初始化,点击也不会有任何反应;Elementor 指南展示了如何识别这种情况。这类抽屉还需要自己的代码,才能在 AJAX 筛选后关闭,具体见移动端与桌面端使用不同的筛选器。

开启滑出面板

Slideout 是内置扩展,始终处于启用状态。它的设置位于 WooCommerce → 设置 → Products Filter → 高级 (Advanced) → Slideout:

  • 全局可见性 (Global visibility):显示 (Show) 会自动把面板添加到 WooCommerce 页面。
  • 按钮样式 (Button as):作为图片 (as Image) 使用Slideout 图片 (Slideout image),大小由按钮图片尺寸 (Button image size) 决定;作为文字 (as Text) 则在标签上显示Slideout 文字 (Slideout text)。
  • 位置 (Position):面板滑出的边缘。偏移 (Offset) 是它与窗口顶部的距离(左右位置),或与左侧的距离(上下位置)。
  • 动作 (Action):点击 (Click) 或悬停 (Hover)。手机没有悬停,所以面板面向手机时请使用点击 (Click)。
  • 容器尺寸 (Container size):面板的宽度和高度。开启全局可见性 (Global visibility) 且未设置宽度时,面板宽 350px。
  • 初始化后的状态 (State after init):否 (No) 会让面板在页面加载时保持关闭。
  • 移动端行为 (Mobile behavior):在所有设备上显示 (Show on all devices)、仅在移动端显示 (Show only on mobile) 或仅在桌面端显示 (Show only on desktop)。

开启全局可见性 (Global visibility) 后,插件会在页面页脚输出 [woof_slideout ...][woof][/woof_slideout]:一个普通的筛选表单,放在带有 position: fixed 的面板中,停放在窗口之外。点击标签会让它滑入,点击面板之外的任何位置会让它滑回;面板内没有关闭按钮。由于表单从一开始就是页面的一部分,所有筛选类型的工作方式都与在侧边栏中一样,AJAX 模式也不例外。

3.4.6 版本中有两个细节。第一,选项中的“商店页面”指 WooCommerce 的 is_woocommerce() 为 true 的每一个页面,这也包括单个产品页。第二,全局面板在把标签文字写入短代码时不加引号,因此由多个单词组成的文字会在第一个空格处被截断:“Show filters”会变成“Show”。在那里请使用单个词的文字,或者使用下面的短代码,在其中可以加引号。移动端行为 (Mobile behavior) 由服务器根据浏览器标识来判断,因此页面缓存必须为手机和电脑分别保存副本,详见移动端指南。

只在您想要的位置显示面板

要控制显示在哪些页面,请把全局可见性 (Global visibility) 设为隐藏 (Hide),然后自己放置短代码。Slideout 标签页底部的生成短代码 (Generate shortcode) 按钮会根据当前选项生成一个短代码;如果这些值不应成为全局值,之后请刷新页面而不是保存,并给含空格的值加上引号。一个典型的短代码:

[woof_slideout location="left" image="null" text="Filters" width="320px" onloadslideout="false"]

image="null" 会把标签变成文字标签。没有内容时,该短代码会自行构建内部的 [woof],并把所有不属于 slideout 设置的属性传给它:tax_only、by_only、sid、btn_position、redirect,以及 [woof] 的其余属性。如果在 [woof_slideout] 和 [/woof_slideout] 之间放入内容,则显示该内容,因此可以加入标题和自定义表单:[woof_slideout text="Filters" image="null"]<h3>Filter products</h3>[woof btn_position="t"][/woof_slideout]。在这种写法中,[woof] 的属性要写在内部的短代码上。

短代码可以放在页面内容或页脚小工具区域中,但不能放在主题在手机上隐藏的侧边栏里:面板就在该侧边栏内部,会随之消失。如果只想在商店页和产品归档页上显示面板,请从主题中输出它:

/*
 * HUSKY: slide-out filter on the shop and product archive pages,
 * not on single products. Set Advanced → Slideout → Global visibility = Hide.
 * Child theme functions.php or a code snippets plugin.
 */
add_action('wp_footer', function () {
    if (!is_shop() && !is_product_taxonomy()) {
        return;
    }
    echo do_shortcode('[woof_slideout location="left" image="null" text="Filters" width="320px" onloadslideout="false"]');
}, 5);

请让优先级低于 10。扩展在它自己的页脚回调(优先级 10)中写入面板的宽度和高度样式,使用的是该回调运行之前最后输出的那个面板;之后才输出的面板得不到尺寸。如果要为每个分类提供不同的筛选器,请测试 is_product_category('shoes'),并给每个面板设置各自的 tax_only="pa_size,pa_color"。如果也想在博客页或首页提供该面板,请加上 redirect="https://example.com/shop/",让结果在商店页打开。

每个页面只用一个面板。slideout 脚本只会准备它找到的第一个面板;第二个面板(例如全局面板加上短代码面板)会保留把它停放在窗口之外的启动样式,因此它的标签会缺失或错位。

通过您自己的按钮打开,并在筛选后关闭

面板响应三个事件:open、close 和 toggle。对于自定义按钮,有一个细节很重要:点击面板之外的任何位置都会关闭面板,而页眉中的按钮就在面板之外。如果点击事件继续传递到 document,面板会在同一瞬间打开又关闭。下面的处理程序阻止了这一点,并且在每次 AJAX 筛选后借助插件的 woof_ajax_done 事件关闭面板:

/*
 * HUSKY slide-out panel: custom open/close buttons, close after AJAX filtering.
 * Child theme functions.php or a code snippets plugin.
 * Buttons: <a href="#" class="open-husky-filter">Filter</a>
 *          <a href="#" class="close-husky-filter">Close</a> (inside the panel)
 */
add_action('wp_footer', function () {
    ?>
    <script>
    jQuery(function ($) {
        $(document.body).on('click', '.open-husky-filter', function (e) {
            e.preventDefault();   // a link with href="#" would jump to the top
            e.stopPropagation();  // otherwise the outside-click rule closes it at once
            $('.woof-slide-out-div').trigger('toggle');
        });
        $(document.body).on('click', '.close-husky-filter', function (e) {
            e.preventDefault();
            $('.woof-slide-out-div').trigger('close');
        });
        $(document).on('woof_ajax_done', function () {
            $('.woof-slide-out-div').trigger('close');
        });
    });
    </script>
    <?php
}, 100);

如果只想使用您自己的按钮,请用 .woof-slide-out-div .woof-handle { display: none; } 隐藏标签。要把关闭链接放进面板,请通过短代码内容把它写在 [woof] 之前。

筛选后关闭适合带有筛选 (Filter) 按钮的情形。开启自动提交 (Autosubmit) 时,每次点击都会触发筛选,面板会在每次选择之后关闭;请在选项 (Options) 标签页中把自动提交 (Autosubmit) 设为否 (No),让访客完成所有选择后,面板只关闭一次。没有 AJAX 时,页面在筛选后会刷新,面板以关闭状态开始,前提是初始化后的状态 (State after init) 为否 (No)。在插件设置第一次保存之前,没有 onloadslideout 的短代码会在每次页面加载时打开;示例中设置了 onloadslideout="false",以免受此影响。

标签、颜色、尺寸与滚动

面板自己的脚本会以内联方式设置一些值,因此有些规则需要 !important;它的样式表在页脚加载,晚于大多数其他样式表,所以有些选择器以 body 开头:

/* HUSKY slide-out panel. Advanced → Code → Custom CSS code,
   or the theme's Additional CSS. */

/* Tab colours; an image tab gets its background inline */
.woof-slide-out-div .woof-handle {
    background-color: #f5c200 !important;
    color: #000;
}

/* Left or right position: move only the tab down, not the panel */
.woof-slide-out-div .woof-handle {
    top: 40px !important;
}

/* No transparency, above sticky headers and cookie bars */
body .woof-slide-out-div {
    opacity: 1 !important;
    z-index: 100000;
}

/* Scroll inside the panel when the filter is longer than the screen */
.woof-slide-out-div .woof-slide-content {
    max-height: calc(100vh - 140px); /* 100px offset + room at the bottom */
    overflow-y: auto;
}

/* Dim the page while the panel is open; a click on the dark area closes it */
.woof-slide-out-div.ui-slideouttab-open {
    box-shadow: 0 0 0 100vmax rgba(0, 0, 0, 0.5);
}

为什么需要滚动规则:页面加载时,如果面板过高或过宽,脚本会把它缩小以适应屏幕,但只会缩小一次。之后才展开的区块、“显示更多”列表,或者旋转手机,都会使内容高于窗口,导致下半部分无法触及。带有 overflow-y: auto 的 max-height 能让面板在任何状态下都有滚动条。减去的数值请设为您的偏移 (Offset) 再加上一些余量。

面板默认有 95% 的不透明度,这会让产品在手机上透出来。它的层叠级别是 9999;层级更高的吸顶页眉、主题遮罩或 Cookie 横幅会盖住它或截获它的点击,看起来就像筛选器无法点击。如果提高面板的层级没有帮助,请检查覆盖在上面的那个元素,并降低它的 z-index。

面板不起作用时

  • 手机上看不到标签。短代码位于主题在小屏幕上隐藏的侧边栏中,移动端行为 (Mobile behavior) 排除了手机,或者页面缓存提供的是桌面端的副本。
  • 面板出现在产品页或所有页面。全局可见性 (Global visibility) 为显示 (Show);请把它切换为隐藏 (Hide),并使用页脚代码段。
  • 每次页面加载时它都会打开。请把初始化后的状态 (State after init) 设为否 (No),并在您的短代码中加入 onloadslideout="false"。
  • 两个标签中只有一个出现或起作用。页面上有两个面板;请只保留一个。
  • 标签出现得很晚或没有反应。JavaScript 优化延迟或合并了插件的脚本。请把 /wp-content/plugins/woocommerce-products-filter/ 从延迟和合并中排除,具体做法见优化插件指南,然后清除所有缓存。
  • 从面板开始筛选,但产品没有变化。这是产品网格的问题,而不是面板的问题;原因与侧边栏中的筛选器相同,参见URL 已变化但产品没有变化。

检查清单

  • 每个页面只用一种隐藏筛选器的方式:Slideout、移动模式、自动筛选器按钮或主题抽屉。
  • 每个页面一个面板;当您自己放置短代码时,全局可见性 (Global visibility) 设为隐藏 (Hide)。
  • 短代码位于主题不会在手机上隐藏的侧边栏之外,或者通过优先级低于 10 的 wp_footer 输出。
  • 带引号的文字标签:image="null" text="Show filters";onloadslideout="false"。
  • 自定义按钮阻止点击传递到 document;面板在 woof_ajax_done 时关闭。
  • 面板内容用 max-height 限制并可滚动;z-index 高于页眉。

如果面板仍然异常,请在 HUSKY 支持论坛上发起一个主题,附上页面链接以及您使用的短代码或设置,我们会检查。