扩展WordPress Page Walker

我已经看过在以前的博客文章中打印WordPress页面的智能列表,但是我想重新访问此主题并使用WordPress的Walker类。Walker类是一个抽象类,它对从数据库中提取和呈现项目的层次结构列表所需的许多基本功能进行了分类。从本质上讲,它是一个迭代器类,它了解包含项目列表的项目列表,并且可以在WordPress中需要此结构的任何地方使用。可以在文件wp-includes / classes.php中找到Walker类,以及其他四个扩展Walker的类。

  • Walker_Page-构造一个包含无序HTML层次页面列表的字符串。

  • Walker_PageDropdown-构造一个字符串,其中包含页面列表作为单个select元素中的选项。

  • Walker_Category-构造一个包含类别的无序HTML层次列表的字符串。

  • Walker_CategoryDropdown-在单个select元素中构造一个包含类别列表作为选项的字符串。

快速搜索WordPress 3.0.1的源代码会发现其他两个使用Walker类来打印项目的分层列表的类。这些如下。

  • Walker_Comment(位于wp-includes / comment_template.php中)-构造一个包含层次结构注释列表的字符串。

  • Walker_Nav_Menu(位于wp-includes / nav-menu-template.php中)-构造菜单项的无序HTML层次结构列表。使用WordPress菜单系统时可以看到这一点。

  • Walker_Category_Checklist(位于wp-admin / includes / template.php中)-为WordPress的admin部分创建,用于创建复选框的分层列表。将帖子分配到类别时可以看到此列表。

要创建自己的项目列表,您可以扩展基础Walker类,或者如果您只想覆盖某些功能,则可以扩展任何子类。这些类要实现的一件事是,它们不能直接使用,WordPress可以使用它们来遍历其他函数调用创建的内容。最好在一个示例中对此进行说明。

以下示例扩展了Walker_Page类,从而通过覆盖start_lvl()andend_lvl()方法,将页面列表打印为有序HTML列表(默认为无序列表)。

class OrderedListOfPages extends Walker_Page {
 
	/**
	 * @see Walker::start_lvl()
	 * @since 2.1.0
	 *
	 * @param string $output Passed by reference. Used to append additional content.
	 * @param int $depth Depth of page. Used for padding.
	 */
	function start_lvl(&$output, $depth) {
		$indent = str_repeat("\t", $depth);
		$output .= "\n$indent\n";
	}
 
	/**
	 * @see Walker::end_lvl()
	 * @since 2.1.0
	 *
	 * @param string $output Passed by reference. Used to append additional content.
	 * @param int $depth Depth of page. Used for padding.
	 */
	function end_lvl(&$output, $depth) {
		$indent = str_repeat("\t", $depth);
		$output .= "$indent\n";
	}
}

要在页面模板中使用该类,您需要将该类包括在WordPress可以看到的某个位置(在function.php文件中或作为插件),然后使用该wp_list_pages()函数,将该类作为参数传递。以下示例将使用上面的OrderedListOfPages类打印出我们的页面层次结构。

wp_list_pages(array('walker' => new OrderedListOfPages()));

或者,您可以通过添加过滤器来更改页面小部件的工作方式,而不是向模板中添加代码。以下代码段将强制页面小部件使用我们新的OrderedListOfPages类。

function my_page_filter($args) {
    $args = array_merge($args, array('walker' => new OrderedListOfPages()));
    return $args;
}
 
add_filter('widget_pages_args', 'my_page_filter');

回顾我以前的动态菜单创建者示例,我想创建一个类来做同样的事情,但是这次使用WordPress walker类。为此,我只需要重写start_el()Walker_Page类中的方法,检查每个页面(即对的每次调用start_el())以查看页面在页面层次结构中的位置。该start_el()方法还创建了一堆CSS类,可用于以不同方式对元素进行样式设置,并且在我重写该方法时重新实现了此功能。我在这里使用的策略是,如果需要将元素作为页面层次结构的一部分,则允许以常规方式构造该元素,否则只需返回以不创建该元素。

此类与动态菜单创建者所做的唯一不同的是,当真正深入到树中时,顶层元素的同级元素开始被切除,但是当前页面的路径和上面的层始终是保持开放。

class DynamicPageMenu extends Walker_Page {
 
	/**
	 * @see Walker::start_el()
	 * @since 2.1.0
	 *
	 * @param string $output Passed by reference. Used to append additional content.
	 * @param object $page Page data object.
	 * @param int $depth Depth of page. Used for padding.
	 * @param int $current_page Page ID.
	 * @param array $args
	 */
	function start_el(&$output, $page, $depth, $args, $current_page) {
		if ( $depth ) {
			$indent = str_repeat("\t", $depth);
		} else {
			$indent = '';
		}
 
		extract($args, EXTR_SKIP);
		$css_class = array('page_item', 'page-item-'.$page->ID);
 
        $_current_page = null;
        $_tmp_page     = null;
 
        if (!empty($current_page)) {
            $_current_page = get_page( $current_page );
            $_tmp_page = get_page( $_current_page->post_parent );
        }
 
        if ($page->post_parent == 0) {
            // 这是顶层页面,因此必须打印
        } elseif (isset($_current_page->ancestors) && in_array($page->ID, (array) $_current_page->ancestors)) {
            // 这是我们当前页面的路径,因此必须将其打印出来
            $css_class[] = 'current_page_ancestor';
        } elseif ($page->ID == $current_page) {
            // 这是当前页面,必须打印
            $css_class[] = 'current_page_item';
        } elseif (!is_null($_current_page) && $page->ID == $_current_page->post_parent) {
            // 此页面是当前页面的父页面
            $css_class[] = 'current_page_parent';
        } elseif (!is_null($_current_page) && $page->post_parent == $_current_page->ID) {
            // 该页面位于当前页面的正下方,因此也必须将其打印出来
        } elseif (!is_null($_tmp_page) && $_tmp_page->post_parent == $page->post_parent) {
            // 这是当前页面父级的同级,因此也必须将其打印出来
        } elseif (!is_null($_current_page) && $_current_page->post_parent == $page->post_parent) {
            // 这是当前页面的同级,因此必须打印
        } else {
            // 拒绝其他一切。
            return true;
        }
 
 
        $css_class = implode(' ', apply_filters('page_css_class', $css_class, $page));
 
		$output .= $indent . '' . $link_before . apply_filters( 'the_title', $page->post_title, $page->ID ) . $link_after . '';
 
		if ( !empty($show_date) ) {
			if ( 'modified' == $show_date ) {
				$time = $page->post_modified;
			} else {
				$time = $page->post_date;
			}
			$output .= " " . mysql2date($date_format, $time);
		}
	}
}

以与以前相同的方式使用此类,如下所示:

wp_list_pages(array('walker' => new DynamicPageMenu()));

或者,要使用它覆盖页面小部件的输出,请使用以下代码。

function my_page_filter($args) {
    $args = array_merge($args, array('walker' => new DynamicPageMenu()));
    return $args;
}
 
add_filter('widget_pages_args', 'my_page_filter');