WordPress源码深度解析之:`WordPress`的`Options API`:`add_option()`、`update_option()`和`delete_option()`的底层实现。

各位观众老爷们,晚上好!今天咱们来聊聊WordPress源码里那些藏得比较深,但又特别重要的东西——Options API。这玩意儿就像WordPress的记忆库,专门用来存储和管理网站的各种配置信息。咱们重点扒一扒add_option()update_option()delete_option()这三个核心函数的底层实现,看看它们是怎么在数据库里翻云覆雨的。

一、什么是Options API?

简单来说,Options API提供了一套统一的接口,让开发者可以方便地存取各种网站配置信息,比如网站标题、描述、主题设置等等。这些信息都存储在WordPress数据库的wp_options表中。

使用Options API的好处多多:

  • 统一管理:所有配置信息都集中存储,方便管理和维护。
  • 数据持久化:配置信息存储在数据库中,即使服务器重启也不会丢失。
  • 易于扩展:可以方便地添加、修改和删除配置信息。
  • 安全性:WordPress提供了一些机制来保护配置信息,防止未经授权的访问。

二、wp_options表结构

在深入了解函数之前,我们先来看看wp_options表的大概结构,这将有助于理解后续的代码:

字段名 数据类型 描述
option_id bigint(20) 主键,自增
option_name varchar(191) 选项的名称,唯一索引,非常重要,通过这个名字来检索选项的值。注意长度限制。
option_value longtext 选项的值,这里可以存储各种类型的数据,比如字符串、数组、对象等等。WordPress会自动进行序列化和反序列化。
autoload varchar(20) 是否自动加载。如果设置为yes,WordPress会在每次加载时自动加载该选项的值。这个选项对于性能有很大影响,如果某个选项不是每次都需要用到,就不要设置为yes。通常用于存储一些全局性的配置信息,比如网站标题、描述等等。

三、add_option():添加选项

add_option()函数的作用是向wp_options表中添加一个新的选项。如果该选项已经存在,则不会添加。

function add_option( string $name, mixed $value = '', string $deprecated = '', string $autoload = 'yes' ): bool {
    global $wpdb;

    // Sanitize option name.
    $name = trim( $name );
    if ( empty( $name ) ) {
        return false;
    }

    // Make sure the option doesn't already exist.
    if ( get_option( $name ) !== false ) {
        return false;
    }

    if ( ! empty( $deprecated ) ) {
        _deprecated_argument( __FUNCTION__, '5.5.0', sprintf(
            /* translators: %s: Argument name. */
            __( 'The %s argument is no longer in use.' ),
            '<code>$deprecated</code>'
        ) );
    }

    $autoload = ( 'no' === $autoload ) ? 'no' : 'yes';

    /**
     * Filters the value of an option before it is added.
     *
     * @since 2.3.0
     *
     * @param mixed  $value    The option value. Must be serializable if non-scalar.
     * @param string $name     The option name.
     * @param string $autoload Whether to autoload the option value. Default 'yes'.
     */
    $value = apply_filters( 'pre_add_option', $value, $name, $autoload );

    $serialized_value = maybe_serialize( $value );

    $result = $wpdb->insert(
        $wpdb->options,
        array(
            'option_name'  => $name,
            'option_value' => $serialized_value,
            'autoload'     => $autoload,
        ),
        array(
            '%s',
            '%s',
            '%s',
        )
    );

    if ( ! $result ) {
        return false;
    }

    wp_cache_delete( 'alloptions', 'options' );

    /**
     * Fires after an option is successfully added.
     *
     * @since 2.3.0
     *
     * @param string $name     The option name.
     * @param mixed  $value    The option value.
     */
    do_action( 'add_option', $name, $value );

    return true;
}

我们来逐行分析一下:

  1. 参数校验和清理:

    $name = trim( $name );
    if ( empty( $name ) ) {
        return false;
    }

    首先,对选项名称进行trim()操作,防止出现空格导致的问题。然后判断选项名称是否为空,如果为空则直接返回false。

  2. 检查选项是否存在:

    if ( get_option( $name ) !== false ) {
        return false;
    }

    调用get_option()函数检查该选项是否已经存在。如果存在,则直接返回false,防止重复添加。

  3. 过滤选项值:

    $value = apply_filters( 'pre_add_option', $value, $name, $autoload );

    使用apply_filters()函数对选项值进行过滤。这是一个钩子,允许开发者在选项被添加到数据库之前修改选项值。

  4. 序列化选项值:

    $serialized_value = maybe_serialize( $value );

    使用maybe_serialize()函数对选项值进行序列化。如果选项值是数组或对象,则会被序列化为字符串,以便存储到数据库中。如果选项值本身就是字符串,则不会进行序列化。

  5. 插入数据:

    $result = $wpdb->insert(
        $wpdb->options,
        array(
            'option_name'  => $name,
            'option_value' => $serialized_value,
            'autoload'     => $autoload,
        ),
        array(
            '%s',
            '%s',
            '%s',
        )
    );

    使用$wpdb->insert()函数将选项信息插入到wp_options表中。$wpdb是WordPress的数据库操作对象,$wpdb->options表示wp_options表。后面的array()分别表示要插入的数据和数据类型。

  6. 清除缓存:

    wp_cache_delete( 'alloptions', 'options' );

    使用wp_cache_delete()函数清除缓存。因为wp_options表中的数据可能会被缓存,所以在添加选项后需要清除缓存,以确保下次读取的是最新的数据。

  7. 触发动作:

    do_action( 'add_option', $name, $value );

    使用do_action()函数触发一个动作。这是一个钩子,允许开发者在选项被成功添加到数据库之后执行一些自定义的操作。

  8. 返回结果:

    return true;

    如果一切顺利,返回true,表示选项添加成功。

四、update_option():更新选项

update_option()函数的作用是更新wp_options表中已存在的选项。如果该选项不存在,则会自动添加。

function update_option( string $name, mixed $value, string|bool $autoload = null ): bool {
    global $wpdb;

    // Sanitize option name.
    $name = trim( $name );
    if ( empty( $name ) ) {
        return false;
    }

    /**
     * Filters the value of an option before it is updated.
     *
     * @since 2.3.0
     *
     * @param mixed  $value    The new option value.
     * @param string $name     The name of the option to update.
     * @param mixed  $old_value The old (existing) option value.
     */
    $old_value = get_option( $name );
    $value     = apply_filters( 'pre_update_option', $value, $name, $old_value );

    // If the new and old values are the same, no need to update.
    if ( maybe_serialize( $old_value ) === maybe_serialize( $value ) && $old_value !== false ) {
        return false;
    }

    $serialized_value = maybe_serialize( $value );

    $fields = array( 'option_value' => $serialized_value );
    $types  = array( '%s' );

    if ( null !== $autoload ) {
        $autoload = ( 'no' === $autoload ) ? 'no' : 'yes';
        $fields['autoload'] = $autoload;
        $types[] = '%s';
    }

    $result = $wpdb->update(
        $wpdb->options,
        $fields,
        array( 'option_name' => $name ),
        $types,
        array( '%s' )
    );

    if ( ! $result ) {
        if ( $old_value === false ) {
            return add_option( $name, $value, '', $autoload );
        }

        return false;
    }

    wp_cache_delete( 'alloptions', 'options' );
    wp_cache_delete( $name, 'options' );

    /**
     * Fires after the value of an option has been successfully updated.
     *
     * @since 2.3.0
     *
     * @param string $name     The name of the option to update.
     * @param mixed  $old_value The old (existing) option value.
     * @param mixed  $value    The new option value.
     */
    do_action( 'update_option', $name, $old_value, $value );

    return true;
}

我们来逐行分析一下:

  1. 参数校验和清理:

    $name = trim( $name );
    if ( empty( $name ) ) {
        return false;
    }

    add_option()函数一样,首先对选项名称进行清理和校验。

  2. 过滤选项值:

    $old_value = get_option( $name );
    $value     = apply_filters( 'pre_update_option', $value, $name, $old_value );

    先获取旧的选项值,然后使用apply_filters()函数对新的选项值进行过滤。这个钩子允许开发者在选项被更新到数据库之前修改选项值,并且可以访问到旧的选项值。

  3. 判断是否需要更新:

    if ( maybe_serialize( $old_value ) === maybe_serialize( $value ) && $old_value !== false ) {
        return false;
    }

    如果新的选项值和旧的选项值相同,则不需要更新。这里使用maybe_serialize()函数进行比较,以确保比较的是序列化后的值。$old_value !== false是为了防止get_option返回false的情况被误判为不需要更新。

  4. 序列化选项值:

    $serialized_value = maybe_serialize( $value );

    使用maybe_serialize()函数对选项值进行序列化。

  5. 更新数据:

    $fields = array( 'option_value' => $serialized_value );
    $types  = array( '%s' );
    
    if ( null !== $autoload ) {
        $autoload = ( 'no' === $autoload ) ? 'no' : 'yes';
        $fields['autoload'] = $autoload;
        $types[] = '%s';
    }
    
    $result = $wpdb->update(
        $wpdb->options,
        $fields,
        array( 'option_name' => $name ),
        $types,
        array( '%s' )
    );

    使用$wpdb->update()函数更新wp_options表中的数据。第一个参数是表名,第二个参数是要更新的字段和值,第三个参数是更新的条件,第四个和第五个参数分别是字段类型和条件类型。

  6. 如果选项不存在,则添加:

    if ( ! $result ) {
        if ( $old_value === false ) {
            return add_option( $name, $value, '', $autoload );
        }
    
        return false;
    }

    如果更新失败,并且旧的选项值不存在(即get_option()返回false),则调用add_option()函数添加该选项。

  7. 清除缓存:

    wp_cache_delete( 'alloptions', 'options' );
    wp_cache_delete( $name, 'options' );

    使用wp_cache_delete()函数清除缓存。需要清除alloptions和该选项的缓存。

  8. 触发动作:

    do_action( 'update_option', $name, $old_value, $value );

    使用do_action()函数触发一个动作。这个钩子允许开发者在选项被成功更新到数据库之后执行一些自定义的操作,并且可以访问到旧的选项值和新的选项值。

  9. 返回结果:

    return true;

    如果一切顺利,返回true,表示选项更新成功。

五、delete_option():删除选项

delete_option()函数的作用是从wp_options表中删除一个选项。

function delete_option( string $name ): bool {
    global $wpdb;

    // Sanitize option name.
    $name = trim( $name );
    if ( empty( $name ) ) {
        return false;
    }

    /**
     * Fires immediately before an option is deleted.
     *
     * @since 2.9.0
     *
     * @param string $name The name of the option to delete.
     */
    do_action( 'pre_delete_option', $name );

    $result = $wpdb->delete( $wpdb->options, array( 'option_name' => $name ) );

    if ( ! $result ) {
        return false;
    }

    wp_cache_delete( 'alloptions', 'options' );
    wp_cache_delete( $name, 'options' );

    /**
     * Fires after an option is deleted.
     *
     * @since 2.3.0
     *
     * @param string $name The name of the option to delete.
     */
    do_action( 'delete_option', $name );

    return true;
}

我们来逐行分析一下:

  1. 参数校验和清理:

    $name = trim( $name );
    if ( empty( $name ) ) {
        return false;
    }

    和之前的函数一样,首先对选项名称进行清理和校验。

  2. 触发动作(删除前):

    do_action( 'pre_delete_option', $name );

    使用do_action()函数触发一个动作。这个钩子允许开发者在选项被删除之前执行一些自定义的操作。

  3. 删除数据:

    $result = $wpdb->delete( $wpdb->options, array( 'option_name' => $name ) );

    使用$wpdb->delete()函数从wp_options表中删除数据。第一个参数是表名,第二个参数是删除的条件。

  4. 清除缓存:

    wp_cache_delete( 'alloptions', 'options' );
    wp_cache_delete( $name, 'options' );

    使用wp_cache_delete()函数清除缓存。需要清除alloptions和该选项的缓存。

  5. 触发动作(删除后):

    do_action( 'delete_option', $name );

    使用do_action()函数触发一个动作。这个钩子允许开发者在选项被成功删除之后执行一些自定义的操作。

  6. 返回结果:

    return true;

    如果一切顺利,返回true,表示选项删除成功。

六、总结

今天我们一起深入了解了WordPress Options API中add_option()update_option()delete_option()这三个核心函数的底层实现。

函数名 作用
add_option() wp_options表中添加一个新的选项。如果该选项已经存在,则不会添加。
update_option() 更新wp_options表中已存在的选项。如果该选项不存在,则会自动添加。
delete_option() wp_options表中删除一个选项。

这三个函数都涉及到参数校验、过滤、序列化、数据库操作和缓存清除等步骤。理解这些函数的底层实现,可以帮助我们更好地使用Options API,并避免一些常见的错误。

希望今天的分享对大家有所帮助!下次再见!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注