WordPress中文开发手册

WordPress主题开发 — 改进用户体验的工具

上下文控制,部分和面板

WordPress 4.0和4.1还增加了对Customizer UI部分的显示或隐藏的支持,这取决于用户在Customizer预览窗口中预览的部分网站。 一个简单的上下文控制示例将是您的主题仅在首页上显示标题图像和站点标语。 这是Customizer Manager的get_方法的完美用例,因为我们可以直接修改这些设置的核心控件,以使其与首页相关:

// Hide core sections/controls when they aren't used on the current page.
$wp_customize->get_section( 'header_image' )->active_callback = 'is_front_page';
$wp_customize->get_control( 'blogdescription' )->active_callback = 'is_front_page';

在此上下文控制示例中,主题仅在首页上显示站点标语,因此当用户浏览到预览窗口中的其他页面时,定制器中的相应字段将被隐藏。

面板,节和控件的active_callback参数采用回调函数名称,无论是核心还是自定义。 注册对象时,也可以设置此参数。 这是二十四主题的例子:

$wp_customize->add_section( 'featured_content', array(
  'title'       => __( 'Featured Content', 'twentyfourteen' ),
  'description' => //...
  'priority'        => 130,
  'active_callback' => 'is_front_page',
) );

在前面的例子中,直接使用is_front_page。 但是,对于更复杂的逻辑,例如检查当前视图是否是页面(甚至是特定页面,按id),可以使用自定义函数(有关为什么需要这个信息的详细信息,请参阅#30251)。 如果您不需要支持PHP 5.2,则可以内联:

'active_callback' => function () { return is_page(); }

PHP 5.2支持与创建命名函数一样简单,并使用active_callback参数引用它:

//...
'active_callback' => 'prefix_return_is_page';
//...
function prefix_return_is_page() {
  return is_page();
}

在自定义控件,Sections和面板中,还有一个选项可以直接在自定义Customizer对象类中覆盖active_callback函数:

class WP_Customize_Greeting_Control extends WP_Customize_Control {
  // ...
  function active_callback() {
    return is_front_page();
  }
}

最后,有一个过滤器可以用来覆盖所有其他的active_callback行为:

// Hide all controls without a description when previewing single posts.
function title_tagline_control_filter( $active, $control ) {
  if ( '' === $control->description ) {
    $active = is_singular();
  }
  return $active;
}
add_filter( 'customize_control_active', 'title_tagline_control_filter', 10, 2 );

请注意,对于所有Customizer对象类型(控件,节和面板),active_callback API的工作原理相同。 作为一个额外的好处,如果其中的所有控件都被上下文隐藏,则部分将自动隐藏,并且面板的功能相同。

选择性刷新:快速,准确的更新

在WordPress 4.5中引入,定制程序中的选择性刷新更新“预览”仅刷新相关设置更改的区域。通过仅更新已更改的元素,它比完全iframe刷新更快,更少破坏性。在定制器中选择性刷新中所述的其他一些好处是:

不要重复(DRY)逻辑
准确的预览更新
预览部分与相关设置和控件之间的关联以及WordPress 4.7中的可见编辑快捷方式
纯JavaScript postMessage更新中的逻辑重复。定制程序中的JavaScript必须镜像生成标记的PHP,或者使用快捷方式近似它。但是Selective Refresh是DRY,因为没有JavaScript和PHP的重复。 Ajax请求检索预览的新标记。

而且由于这个Ajax调用,刷新是准确的。它使用可以更改标记的过滤器。它显示与前端相同的结果。

另外,选择性刷新部分会提供预览区域与其对应设置之间的关联。定制工具利用这种关系提供可见的编辑快捷方式,帮助用户找到与其网站特定部分相关联的控件。在将来,部分API可以扩展,以便在预览中直接编辑设置,并且包含一个结构化的JS API,用于预览部分设置。

由于这些原因,强烈建议所有设置利用选择性刷新传输以改善用户体验,并提供额外的基于JavaScript的传输以进一步增强设置预览。

注册部分

设置预览需要通过注册必要的部分来选择使用选择性刷新。 在这个例子中,很大程度上取自于他们二十六,通过添加相同名称的部分,为博客描述设置添加了选择性刷新。

function foo_theme_customize_register( WP_Customize_Manager $wp_customize ) {
    $wp_customize->selective_refresh->add_partial( 'blogdescription', array(
        'selector' => '.site-description',
        'container_inclusive' => false,
        'render_callback' => function() {
            bloginfo( 'description' );
        },
    ) );
}
add_action( 'customize_register', 'foo_theme_customize_register' );

如果没有提供设置参数,它默认与部分ID相同,与控件的设置默认为控件ID相同。 以下是部分的一些主要参数:

变量类型描述
settingsarray设置与部分相关联的ID。
selectorstring指定要更新的页面标记中的元素。
container_inclusiveboolean如果为真,刷新将替换整个容器。 否则,它只会替换容器的孩子。 默认为false.
render_callbackfunction生成要刷新的标记.
fallback_refreshbool是否在文档中找不到部分文件时是否应进行全页刷新.

选择性刷新JavaScript事件

这些火wp.customize.selectiveRefresh:

部分内容呈现
展示位置时。 如上所述,JavaScript驱动的小部件可以重新构建在此事件上。
渲染部分响应
数据返回后,请求部分呈现。 服务器使用'customize_render_partials_response'过滤这些数据。
部分内容移动
当窗口小部件在其侧边栏中移动时。 如上所示,JavaScript驱动的小部件可以刷新此事件。
小部件更新
当使用其renderContent方法刷新WidgetPartial时。
侧边栏更新
当边栏具有刷新或更新的小部件时。 或者当侧边栏的小部件被排序时,使用reflowWidgets()。

小部件:选择性选择性刷新

主题和小部件都需要选择使用选择性刷新。 所有核心小部件和主题已经启用。

侧栏中的主题支持

为了允许部分刷新主题的边栏中的小部件:

add_theme_support( 'customize-selective-refresh-widgets' );

小部件支持

即使主题支持选择性刷新,小部件也必须选择加入。 所有核心小部件已经启用它。 这是一个添加对Selective Refresh的支持的示例窗口小部件:

class Foo_Widget extends WP_Widget {
 
    public function __construct() {
        parent::__construct(
            ‘foo’,
            __( 'Example', 'bar-plugin' ),
            array(
                'description' => __( ‘An example widget’, ‘bar-plugin’ ),
                'customize_selective_refresh' => true,
            )
        );
 
        if ( is_active_widget( false, false, $this->id_base ) || is_customize_preview() ) {
            add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
        }
    }
    ...

上面的第9行启用了选择性刷新:

'customize_selective_refresh' => true,

上面的第13行确保小部件的样式表始终显示在Customizer会话中。 添加小部件不会导致全页刷新来检索样式:

if ( is_active_widget( false, false, $this->id_base ) || is_customize_preview() ) {
    add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
}

请参阅实现小部件的选择性刷新支持。

JavaScript驱动的小部件支持

依赖JavaScript进行标记的小部件将需要其他步骤,如实现Widget的选择性刷新支持所示:

按照is_customize_preview()排列任何JavaScript文件,如上图所示。
添加部分内容渲染事件的处理程序,并根据需要刷新窗口小部件:

wp.customize.selectiveRefresh.bind( 'partial-content-rendered', function( placement ) {
    // logic to refresh
} );

如果小部件包含一个iframe,请添加一个处理程序来刷新部分:

wp.customize.selectiveRefresh.bind( 'partial-content-moved', function( placement ) {
    // logic to refresh, perhaps conditionally
}

使用PostMessage改进设置预览

定制程序会自动处理即时预览所有设置。这是通过静默地重新加载整个预览窗口来完成的,在Ajax调用中PHP被过滤。虽然这样做很好,但它可能非常慢,因为整个前端必须重新加载,以进行每一个设置更改。选择性刷新通过仅刷新已更改的元素来改善此体验,但由于Ajax调用,在预览中看到更改仍然有延迟。

为了进一步改善用户体验,Customizer提供了一个API,用于直接在JavaScript中管理设置更改,从而实现真实的预览。下图显示了使用此技术(称为postMessage)与标准刷新选项的自定义CSS选项的比较:

使用postMessage设置传输的Customizer中的自定义CSS设置。
Customizer中的自定义CSS设置,具有默认的刷新设置传输。

要使用postMessage,请在添加设置时先将传输参数设置为postMessage。许多主题还可以通过修改这些设置的传输属性来修改核心设置,如标题和标语来利用postMessage。

$wp_customize->get_setting( 'blogname' )->transport        = 'postMessage';
$wp_customize->get_setting( 'blogdescription' )->transport = 'postMessage';

一旦设置的传输设置为postMessage,设置将不再触发刷新的预览,当其值更改。 要实现JavaScript以在前端预览中更新设置,请首先创建并排入JavaScript文件:

function my_preview_js() {
  wp_enqueue_script( 'custom_css_preview', 'path/to/file.js', array( 'customize-preview', 'jquery' ) );
}
add_action( 'customize_preview_init', 'my_preview_js' );

您的JavaScript文件应如下所示:

( function( $ ) {
  wp.customize( 'setting_id', function( value ) {
    value.bind( function( to ) {
      $( '#custom-theme-css' ).html( to );
    } );
  } );
  wp.customize( 'custom_plugin_css', function( value ) {
    value.bind( function( to ) {
      $( '#custom-plugin-css' ).html( to );
    } );
  } );
} )( jQuery );

请注意,您不一定需要使用JavaScript来使用postMessage - 大多数代码是样板。 从PostMessage传输中受益最大的设置类型需要简单的JS更改,例如使用jQuery的.html()或.text()方法,或者在<body>或另一个元素上交换一个类,以触发不同的 CSS规则。 做到这一点,或者通过选择性刷新更新完全准确的更改来简化即时预览逻辑,用户体验可以快速,而不会重复JS中的所有PHP逻辑。

设置验证

WordPress 4.6包括与Customizer设置值的验证相关的新API。定制程序自介绍以来已经对设置值进行了消毒。消毒涉及强制将某个值安全地保留到数据库中:常见的示例是将值转换为整数或从一些文本输入中剥离标签。因此,消毒是一种有损运作。随着设置验证的增加:

  • 所有修改的设置在保存之前先验证。
  • 如果任何设置无效,则定制程序保存请求被拒绝:保存因此变为事务性,所有设置为脏,以便再次保存。 (定制器交易建议与设置验证密切相关。)
  • 验证错误消息显示给用户,提示他们修复错误,然后重试。
  • 消毒和验证也分别通过WP_REST_Request :: sanitize_params()和WP_REST_Request :: validate_params()作为REST API基础结构的一部分。设定值通过验证后进行清洁。

有关验证行为的更多信息和其他代码示例,请参阅功能公告帖子。

验证PHP中的设置

正如您在注册设置时可以提供sanitize_callback一样,还可以提供validate_callback arg:

$wp_customize->add_setting( 'established_year', array(
    'sanitize_callback' => 'absint',
    'validate_callback' => 'validate_established_year'
) );
function validate_established_year( $validity, $value ) {
    $value = intval( $value );
    if ( empty( $value ) || ! is_numeric( $value ) ) {
        $validity->add( 'required', __( 'You must supply a valid year.' ) );
    } elseif ( $value < 1900 ) {
        $validity->add( 'year_too_small', __( 'Year is too old.' ) );
    } elseif ( $value > gmdate( 'Y' ) ) {
        $validity->add( 'year_too_big', __( 'Year is too new.' ) );
    }
    return $validity;
}

正如提供一个sanitize_callback arg,为customize_sanitize _ {$ setting_id}添加了一个过滤器,所以提供一个validate_callback arg也会为customize_validate _ {$ setting_id}添加一个过滤器。 假设WP_Customize_Setting实例在其验证方法中对这些实例应用过滤器,如果需要为先前添加的设置添加验证,则可以添加此过滤器。

validate_callback和任何customize_validate _ {$ setting_id}过滤器回调采用WP_Error实例是其第一个参数(最初没有添加任何错误),其次是$值被清理,最后是正在验证的WP_Customize_Setting实例。

自定义设置类也可以直接覆盖设置类的validate方法。

客户端验证

如果您有一个纯粹通过JavaScript进行预览的设置(并且postMessage传输没有选择性刷新),那么您还应该添加客户端验证。否则,任何验证错误将持续,直到完全刷新发生或尝试保存。客户端验证不能取代服务器端验证,因为如果相应的服务器端验证不到位,恶意用户可能会绕过客户端验证来保存无效值。

在wp.customize.Setting JS类(实际上是wp.customize.Value基类)中有一个可用的验证方法。它的名字有点误导,因为它实际上与WP_Customize_Setting :: sanitize()PHP方法类似,但它可以用于在JS中对某个值进行清理和验证。请注意,此JS在“定制器”窗格的上下文中运行而不是预览,因此任何此类JS应具有自定义控件作为依赖关系(而不是自定义预览),并在customize_controls_enqueue_scripts操作期间排入队列。一些例子JS验证:

wp.customize( 'established_year', function ( setting ) {
    setting.validate = function ( value ) {
        var code, notification;
        var year = parseInt( value, 10 );
 
        code = 'required';
        if ( isNaN( year ) ) {
            notification = new wp.customize.Notification( code, {message: myPlugin.l10n.yearRequired} );
            setting.notifications.add( code, notification );
        } else {
            setting.notifications.remove( code );
        }
 
        code = 'year_too_small';
        if ( year < 1900 ) {
            notification = new wp.customize.Notification( code, {message: myPlugin.l10n.yearTooSmall} );
            setting.notifications.add( code, notification );
        } else {
            setting.notifications.remove( code );
        }
 
        code = 'year_too_big';
        if ( year > new Date().getFullYear() ) {
            notification = new wp.customize.Notification( code, {message: myPlugin.l10n.yearTooBig} );
            setting.notifications.add( code, notification );
        } else {
            setting.notifications.remove( code );
        }
 
        return value;
    };
} );

通知

错误通知通知提供用户反馈,通常基于控件设置的值。当设置的验证例程返回WP_Error实例时,会将错误通知添加到设置的通知集合中。添加到PHP WP_Error实例的每个错误都表示为一个wp.customize.Notification在JavaScript中:

WP_Error的代码可以作为JS中的notification.code使用。
WP_Error的消息在JS中可用作notification.message。请注意,如果在PHP中添加了给定错误代码的多个消息,它们将被连接到JS中的单个消息中。
WP_Error的数据在JS中可用作notification.data。这将有助于将额外的错误上下文从服务器传递给客户端。
任何时候从服务器上的验证例程返回WP_Error,将导致一个wp.customize.Notification被创建,其类型属性为“error”。

当前不支持从PHP设置非错误通知(请参阅#37281),您还可以按照以下方式向JS添加非错误通知:

wp.customize( 'blogname', function( setting ) {
    setting.bind( function( value ) {
        var code = 'long_title';
        if ( value.length > 20 ) {
            setting.notifications.add( code, new wp.customize.Notification(
                code,
                {
                    type: 'warning',
                    message: 'This theme prefers title with max 20 chars.'
                }
            ) );
        } else {
            setting.notifications.remove( code );
        }
    } );
} );

您也可以提供“信息”作为通知的类型。 默认类型为“error”。 也可以提供自定义类型,并且可以使用CSS选择器匹配notice.notice-foo来设置通知,其中“foo”是提供的类型。 控件也可以覆盖通过覆盖wp.customize.Control.renderNotifications方法来呈现通知的默认行为。