在编写了可以在Wordpress中创建给定页面的子页面列表的函数之后,我需要更强大,更自动的功能。为此,我创建了一个插件,该插件将创建一个包含动态创建的页面菜单的小部件。
该小部件可以确定当前正在显示的页面,并将爬到页面树上,直到找到根页面为止。在攀爬页面树的同时,插件将保留当前所选页面的路径,并且在打印出该树时,路径将被打开。它最适合具有坚实层次结构页面的站点,而不是简单的博客站点。
在效率方面,我已经使用最多嵌套25个级别的页面进行了测试,页面负载只有很小的减少。但是,对于一般的小型Wordpress网站而言,此插件是完美的,因为页面仅嵌套了几层。
<?php /** * Plugin Name: Page Menu Navigation * Plugin URI: http://www.hashbangcode.com/ * Description: Adds an intelligent page navigation menu that is dependent on page hierarchy. * Version: 1.0 * Author: Philip Norton * Author URI: http://www.hashbangcode.com/ */ /** * Print out hirachical page structure. * * @global object $post The current post. */ function printPages() { global $post; if ($post->post_type == 'page') { if ($post->post_parent > 0) { $root = findPathInformation($post); $pages = traversePageTree($root['root'], $root['activepath'], $root['depth']); } else { $root = $post; $pages = traversePageTree($root, array($root->ID), 1); } echo printPageTree($pages); } } /** * From a single page find out how deep it is * * @param object $page The current page. * * @return array An array of information about the page and the path. */ function findPathInformation($page) { // 上那棵树,看看那是什么。 $reverse_tree = climbPageTree($page); // 整理树以获取当前的活动路径。 $activePath = flattenTree($reverse_tree); // 确保当前页面在活动路径中。 $activePath[] = $page->ID; $root = $reverse_tree[0]; // 设置为2,就好像我们在此代码中一样,位于根目录下。 $depth = 2; // Recursivley遍历页面并找到根页面和深度。 while (is_array($root->post_parent)) { ++$depth; $root = $root->post_parent[0]; } return array('root' => $root, 'depth' => $depth, 'activepath' => $activePath); } /** * Flatten the tree into a single array. * * @param array $tree A multi dimensional array of pages. * * @return array A single dimensional array of pages. */ function flattenTree($tree) { $flat = array(); while (is_array($tree[0]->post_parent)) { $flat[] = $tree[0]->ID; $tree = $tree[0]->post_parent; } $flat[] = $tree[0]->ID; return $flat; } /** * Find out if the current page is in the active path. * * @param integer $id The ID of the current page. * @param array $activePath An array of ID's of the pages in the current path. * * @return boolean True if the page is in current path, otherwise false. */ function inActivePath($id, $activePath) { if (in_array($id, $activePath)) { return true; } else { return false; } } /** * Starting with the current page go up level after level until the root page * reached. This function will run one SQL query for every level. * * @global wpdb $wpdb The current Wordpress database connection object. * * @param object $page The current page. * * @return <type> */ function climbPageTree($page) { global $wpdb; $parent = $wpdb->get_results("SELECT ID, post_title, post_parent FROM $wpdb->posts WHERE post_status = 'publish' AND post_type = 'page' AND ID = " . $page->post_parent . " ORDER BY menu_order, post_title", OBJECT); if (count($parent) > 0) { foreach ($parent as $item => $par) { if ($par->post_parent != 0) { $parent_parent = climbPageTree($par); if ($parent_parent !== false) { $parent[$item]->post_parent = $parent_parent; } } else { // 到达树的顶部 return $parent; } } } return $parent; } /** * Traverse the page structure and create a tree of the pages. * * @global wpdb $wpdb The current Wordpress database connection object. * * @param object $page The page to start the tree traversal from, usually root. * @param array $activePath An array of page ID's in the active path. * @param integer $maxdepth The maximum depth to follow the traversal * @param integer $depth The current depth of the traversal. * * @return array A tree of pages. */ function traversePageTree($page, $activePath = array(), $maxdepth = 10, $depth = 0) { if ($depth >= $maxdepth) { // 我们已经达到最大深度,停止遍历。 return array(); } // 获取Wordpress db对象。 global $wpdb; $children = $wpdb->get_results("SELECT ID, post_title, post_parent FROM $wpdb->posts WHERE post_status = 'publish' AND post_type = 'page' AND post_parent = " . $page->ID . " ORDER BY menu_order, post_title", OBJECT); if (count($children) > 0) { foreach ($children as $item => $child) { if (inActivePath($child->ID, $activePath)) { // 当前页面处于活动路径中,找到子代。 $children[$item]->children = traversePageTree($child, $activePath, $maxdepth, $depth + 1); } } } return $children; } /** * Print out the page tree as created by the traversePageTree() function. * * @see traversePageTree() * * @param array $pages A tree of pages. */ function printPageTree($pages) { $class = ''; $output = ''; $output .= "\n<ul>\n"; foreach ($pages as $page) { if (is_page($page->ID) === true) { $class = ''; } $output .= "<li" . $class . "><a href=\"" . get_page_link($page->ID) . "\" title=\"" . $page->post_title . "\">" . $page->post_title . "</a>"; $class = ''; if (isset($page->children) && count($page->children) > 0) { $output .= printPageTree($page->children); } $output .= "</li>\n"; } $output .= "</ul>\n"; return $output; } /** * Widget function * * @param array $args */ function pageMenuNavigationWidget($args) { extract($args); echo '<div id="subNav">'; echo printPages(); echo '</div>'; } register_sidebar_widget(__('Page Menu Navigation'), 'pageMenuNavigationWidget'); $wp_registered_widgets[sanitize_title('Page Menu Navigation')]['description'] = 'Creates a navigation menu.';
如果您喜欢这个插件并且觉得它有用,请告诉我,我将其添加到Wordpress插件中心。我确定可以对插件进行一些改进,如果您认为有任何改进,请留下评论并告诉我。
我还用过Walker_Page类生成了动态菜单。使用Walker_Page方法的好处是,它可以用于覆盖WordPress随附的默认页面小部件。