探究 WordPress `get_edit_post_link()` 函数的源码:如何生成文章编辑页的链接,并支持自定义文章类型。

哈喽大家好!欢迎来到今天的WordPress源码解密小课堂。今天我们要聊聊一个在WordPress开发中非常实用,但可能又被大家忽略的小家伙:get_edit_post_link() 函数。

别看它名字平平无奇,作用可大了!它可以帮你生成文章编辑页面的链接,而且还非常智能,能根据不同的文章类型自动调整。

今天,我们就来扒一扒它的源码,看看它到底是如何实现的,以及我们如何利用它来做一些更有趣的事情。

一、get_edit_post_link() 是个啥?

首先,让我们明确一下get_edit_post_link() 的作用:

  • 功能: 生成指定文章的编辑页面的URL。
  • 用途: 在前台页面提供一个方便的编辑入口,方便用户快速修改文章。
  • 特点: 智能,可以根据文章类型自动生成正确的链接。

举个例子,假设你正在开发一个自定义文章类型“书籍”,你希望在前台页面显示一个“编辑书籍”的链接,就可以使用这个函数轻松实现。

二、源码探秘:wp-includes/link-template.php

好了,废话不多说,让我们直接进入源码的世界。get_edit_post_link() 的定义位于 wp-includes/link-template.php 文件中。

function get_edit_post_link( $id = 0, $context = '', $echo = false ) {
    global $pagenow;

    $id = absint( $id );
    if ( ! $id ) {
        $id = get_the_ID();
    }

    $post = get_post( $id );

    if ( ! $post ) {
        return;
    }

    if ( 'revision' === $post->post_type ) {
        $id = $post->post_parent;
        $post = get_post( $id );
        if ( ! $post ) {
            return;
        }
    }

    if ( ! current_user_can( 'edit_post', $id ) ) {
        return;
    }

    if ( 'display' == $context ) {
        $link = '<a href="' . esc_url( get_edit_post_link( $id ) ) . '">' . __( 'Edit' ) . '</a>';
        /**
         * Filters the edit post link text.
         *
         * @since 2.9.0
         *
         * @param string $text The edit link text.
         */
        $link = apply_filters( 'edit_post_link', $link );
    } else {
        $file = 'post.php';
        if ( 'page' == $post->post_type ) {
            $file = 'page.php';
        } elseif ( 'attachment' == $post->post_type ) {
            $file = 'media.php';
        }

        $link = admin_url( $file . '?post=' . $id . '&action=edit' );

        /**
         * Filters the URL to edit a post.
         *
         * @since 2.5.0
         *
         * @param string      $link    The edit link.
         * @param int         $post_id Post ID.
         * @param string|null $context The link context. If 'display', the link will
         *                                include an ampersand.
         */
        $link = apply_filters( 'edit_post_link', $link, $id, $context );
    }

    if ( $echo ) {
        echo $link;
    } else {
        return $link;
    }
}

三、源码解读:步步为营

让我们一步一步地分析这段代码:

  1. 参数处理:

    • $id = 0: 要编辑的文章ID,默认为0,表示当前文章。
    • $context = '': 上下文,决定了返回链接的形式,默认为空,表示返回URL。如果为'display',则返回包含<a>标签的HTML链接。
    • $echo = false: 是否直接输出链接,默认为false,表示返回链接字符串。
    function get_edit_post_link( $id = 0, $context = '', $echo = false ) {
        global $pagenow;
    
        $id = absint( $id );
        if ( ! $id ) {
            $id = get_the_ID();
        }

    这段代码首先获取文章ID,如果$id 为空,则尝试获取当前文章的ID。absint() 函数确保ID是一个正整数。

  2. 获取文章对象:

    $post = get_post( $id );
    
    if ( ! $post ) {
        return;
    }

    使用 get_post() 函数根据ID获取文章对象。如果文章不存在,则直接返回。

  3. 处理修订版本:

    if ( 'revision' === $post->post_type ) {
        $id = $post->post_parent;
        $post = get_post( $id );
        if ( ! $post ) {
            return;
        }
    }

    如果文章是修订版本,则获取其父文章的ID,并重新获取父文章对象。这是为了确保编辑链接指向的是原始文章,而不是修订版本。

  4. 权限检查:

    if ( ! current_user_can( 'edit_post', $id ) ) {
        return;
    }

    使用 current_user_can() 函数检查当前用户是否有编辑该文章的权限。如果没有权限,则直接返回。

  5. 根据上下文生成链接:

    if ( 'display' == $context ) {
        $link = '<a href="' . esc_url( get_edit_post_link( $id ) ) . '">' . __( 'Edit' ) . '</a>';
        /**
         * Filters the edit post link text.
         *
         * @since 2.9.0
         *
         * @param string $text The edit link text.
         */
        $link = apply_filters( 'edit_post_link', $link );
    } else {
        $file = 'post.php';
        if ( 'page' == $post->post_type ) {
            $file = 'page.php';
        } elseif ( 'attachment' == $post->post_type ) {
            $file = 'media.php';
        }
    
        $link = admin_url( $file . '?post=' . $id . '&action=edit' );
    
        /**
         * Filters the URL to edit a post.
         *
         * @since 2.5.0
         *
         * @param string      $link    The edit link.
         * @param int         $post_id Post ID.
         * @param string|null $context The link context. If 'display', the link will
         *                                include an ampersand.
         */
        $link = apply_filters( 'edit_post_link', $link, $id, $context );
    }

    这段代码是生成链接的关键部分。

    • 如果 $context'display',则生成包含<a>标签的HTML链接,链接文本默认为“Edit”,可以使用 edit_post_link 过滤器修改。
    • 否则,根据文章类型确定后台编辑页面的文件名(post.phppage.phpmedia.php),并使用 admin_url() 函数生成后台编辑页面的URL。同样,可以使用 edit_post_link 过滤器修改URL。
  6. 输出或返回链接:

    if ( $echo ) {
        echo $link;
    } else {
        return $link;
    }

    根据 $echo 参数的值,选择直接输出链接或返回链接字符串。

四、核心机制:admin_url() 和文章类型判断

通过上面的源码分析,我们可以发现,get_edit_post_link() 函数的核心机制在于:

  • admin_url() 函数: 用于生成后台管理页面的URL。它接受一个文件名作为参数,例如 post.phppage.php 等,并自动添加必要的参数,例如 postaction
  • 文章类型判断: 根据文章的 post_type 属性,选择不同的后台编辑页面文件名。默认情况下,文章类型为 post 时使用 post.php,页面类型为 page 时使用 page.php,附件类型为 attachment 时使用 media.php

五、自定义文章类型:如何让 get_edit_post_link() 乖乖听话

现在,让我们回到最初的问题:如何让 get_edit_post_link() 函数正确地生成自定义文章类型的编辑链接?

答案就在于 过滤器

get_edit_post_link() 函数在生成链接之前,会应用 edit_post_link 过滤器。我们可以利用这个过滤器,修改链接的URL。

以下是一个示例,假设我们的自定义文章类型是“书籍”,后台编辑页面的文件名是 edit-book.php

add_filter( 'edit_post_link', 'my_custom_edit_post_link', 10, 3 );

function my_custom_edit_post_link( $link, $post_id, $context ) {
    $post = get_post( $post_id );

    if ( 'book' === $post->post_type ) {
        $link = admin_url( 'edit-book.php?post=' . $post_id . '&action=edit' );
    }

    return $link;
}

这段代码做了以下事情:

  1. 使用 add_filter() 函数,将 my_custom_edit_post_link() 函数添加到 edit_post_link 过滤器中。
  2. my_custom_edit_post_link() 函数接收三个参数:
    • $link: 原始的编辑链接。
    • $post_id: 文章ID。
    • $context: 上下文。
  3. 在函数中,首先获取文章对象,然后判断文章类型是否为“书籍”。
  4. 如果是“书籍”类型,则使用 admin_url() 函数生成新的编辑链接,指向 edit-book.php 文件。
  5. 最后,返回修改后的链接。

这样,当调用 get_edit_post_link() 函数生成“书籍”类型文章的编辑链接时,就会自动使用我们自定义的链接。

六、更优雅的方式:get_post_type_object()rewrite

除了使用过滤器之外,还有一种更优雅的方式来处理自定义文章类型的编辑链接:

  1. 注册文章类型时,设置 rewrite 参数:

    在注册自定义文章类型时,可以使用 rewrite 参数来指定文章的URL结构。例如:

    register_post_type( 'book', array(
        'labels' => array(
            'name' => __( 'Books' ),
            'singular_name' => __( 'Book' ),
        ),
        'public' => true,
        'has_archive' => true,
        'rewrite' => array( 'slug' => 'books' ), // 设置URL slug
    ) );

    这样,WordPress会自动根据 slug 生成文章的URL。

  2. 使用 get_post_type_object() 函数获取文章类型对象:

    get_post_type_object() 函数可以获取指定文章类型的对象,该对象包含了文章类型的各种属性,例如 labelsrewrite 等。

  3. 自定义编辑页面的文件名:

    如果你的自定义文章类型的编辑页面不是 post.phppage.phpmedia.php 中的任何一个,你需要自定义一个编辑页面,例如 edit-book.php

  4. 在自定义编辑页面中,使用 get_current_screen() 函数获取当前屏幕对象:

    get_current_screen() 函数可以获取当前屏幕对象,该对象包含了当前页面的各种信息,例如 idbasepost_type 等。

  5. 根据屏幕对象的 post_type 属性,判断是否为自定义文章类型:

    如果屏幕对象的 post_type 属性与你的自定义文章类型匹配,则执行相应的操作。

虽然这种方式稍微复杂一些,但它可以更好地与WordPress的架构集成,使你的代码更加清晰和易于维护。

七、实战演练:一个完整的“书籍”文章类型示例

为了更好地理解上面的内容,让我们来看一个完整的“书籍”文章类型的示例:

<?php
/**
 * Plugin Name: Custom Book Post Type
 * Description: Registers a custom post type for books.
 */

// 注册自定义文章类型
add_action( 'init', 'register_book_post_type' );

function register_book_post_type() {
    $labels = array(
        'name'               => _x( 'Books', 'post type general name' ),
        'singular_name'      => _x( 'Book', 'post type singular name' ),
        'menu_name'          => _x( 'Books', 'admin menu' ),
        'name_admin_bar'     => _x( 'Book', 'add new on admin bar' ),
        'add_new'            => _x( 'Add New', 'book' ),
        'add_new_item'       => __( 'Add New Book' ),
        'new_item'           => __( 'New Book' ),
        'edit_item'          => __( 'Edit Book' ),
        'view_item'          => __( 'View Book' ),
        'all_items'          => __( 'All Books' ),
        'search_items'       => __( 'Search Books' ),
        'parent_item_colon'  => __( 'Parent Books:' ),
        'not_found'          => __( 'No books found.' ),
        'not_found_in_trash' => __( 'No books found in Trash.' )
    );

    $args = array(
        'labels'             => $labels,
        'public'             => true,
        'publicly_queryable' => true,
        'show_ui'            => true,
        'show_in_menu'       => true,
        'query_var'          => true,
        'rewrite'            => array( 'slug' => 'books' ),
        'capability_type'    => 'post',
        'has_archive'        => true,
        'hierarchical'       => false,
        'menu_position'      => 5,
        'supports'           => array( 'title', 'editor', 'author', 'thumbnail', 'excerpt', 'comments' ),
    );

    register_post_type( 'book', $args );
}

// 修改编辑链接
add_filter( 'edit_post_link', 'my_custom_edit_post_link', 10, 3 );

function my_custom_edit_post_link( $link, $post_id, $context ) {
    $post = get_post( $post_id );

    if ( 'book' === $post->post_type ) {
        $link = admin_url( 'post.php?post=' . $post_id . '&action=edit' ); // 假设使用默认的post.php编辑页面
    }

    return $link;
}

// 可选:添加自定义字段(示例)
add_action( 'add_meta_boxes', 'add_book_meta_boxes' );

function add_book_meta_boxes( $post_type ) {
    if ( 'book' == $post_type ) {
        add_meta_box(
            'book_author',
            __( 'Author Information', 'myplugin_textdomain' ),
            'book_author_meta_box_callback',
            'book',
            'normal',
            'default'
        );
    }
}

function book_author_meta_box_callback( $post ) {
    wp_nonce_field( basename( __FILE__ ), 'book_author_nonce' );
    $author_name = get_post_meta( $post->ID, '_book_author_name', true );
    ?>
    <p>
        <label for="book_author_name"><?php _e( 'Author Name', 'myplugin_textdomain' ); ?></label>
        <input type="text" id="book_author_name" name="book_author_name" value="<?php echo esc_attr( $author_name ); ?>" size="25" />
    </p>
    <?php
}

add_action( 'save_post', 'save_book_author_meta' );

function save_book_author_meta( $post_id ) {
    if ( ! isset( $_POST['book_author_nonce'] ) || ! wp_verify_nonce( $_POST['book_author_nonce'], basename( __FILE__ ) ) ) {
        return;
    }

    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
        return;
    }

    if ( ! current_user_can( 'edit_post', $post_id ) ) {
        return;
    }

    if ( isset( $_POST['book_author_name'] ) ) {
        update_post_meta( $post_id, '_book_author_name', sanitize_text_field( $_POST['book_author_name'] ) );
    }
}

这个示例包含了以下内容:

  • 注册“书籍”文章类型: 使用 register_post_type() 函数注册一个名为 book 的自定义文章类型。
  • 修改编辑链接: 使用 edit_post_link 过滤器,确保“书籍”文章类型的编辑链接指向正确的页面。这里为了演示简单,假设使用默认的post.php进行编辑,但是可以替换为你的自定义编辑页面。
  • 添加自定义字段: 添加一个名为“作者信息”的自定义字段,用于存储书籍的作者姓名。

将这段代码保存为一个插件文件(例如 custom-book-post-type.php),然后上传到 WordPress 的 wp-content/plugins/ 目录下,并激活该插件。

现在,你就可以在 WordPress 后台看到“书籍”文章类型了,并且可以通过 get_edit_post_link() 函数生成“书籍”文章的编辑链接。

八、总结与展望

通过今天的源码解密,我们深入了解了 get_edit_post_link() 函数的实现原理,以及如何利用它来处理自定义文章类型的编辑链接。

总而言之,get_edit_post_link() 函数是一个非常实用的工具,可以帮助我们快速生成文章编辑页面的链接。通过过滤器和自定义文章类型,我们可以灵活地控制链接的生成方式,从而满足各种不同的需求。

希望今天的课程对你有所帮助!下次再见!

发表回复

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