Here is a fix to show the children pages in the main_nav method. Was an easy fix. I’m sure this method could be optimized a bit. This was literally a 5 minute hack job. I just copied the sub_nav method and made a couple of changes.
Change your nav_main method call to:
{exp:structure:nav_main exclude_status="hidden|no_main_nav" show_children="true"}
In nav_main method around line 123 add/change to:
$html .= ">";
$html .= "<a >" . $entry_data['title'];
$html .= "</a>";
if( $show_children == 'true' and $here == 'here' ) {
$html .= $this->get_children($entry_data['entry_id'], $exclude_status_list);
}
$html .= "</li>";
2nd half of the method:
// get site pages data
$site_pages = $PREFS->ini('site_pages');
// get current uri path
$uri = $IN->URI;
// get node of the current entry
$node = $start_node = $entry_id ? $this->nset->getNode($entry_id) : false;
// node does not have any structure data we return nothing to prevent errors
if ($node === false && ! $entry_id) {
return '';
}
// if we have an entry id but no node, we have listing entry
if ($entry_id && ! $node) {
// get entry's parent id
$pid = $this->get_pid_for_listing_entry($entry_id);
// get node of parent entry
// because we will be showing nav sub from its view point
$node = $start_node = $this->nset->getNode($pid);
}
// if we are on a root that is a leaf
// no sub nav to return
if ($node && $node['isLeaf'] && $node['depth'] == 0) {
return '';
}
if ($node['isLeaf'] && $node['depth'] > 1) {
// we are on a child leaf past the root level
// so we use the parent as the starting point for the sub nav
$start_node = $this->nset->getNode($node['parent_id']);
}
// get siblings
$where = 'node.parent_id = ' . ($start_node['depth'] ? $start_node['parent_id'] : $start_node['id']);
// get children
$where .= ' OR node.parent_id = ' . $start_node['id'];
$entry_depth = $start_node['depth'] ? $start_node['depth'] : 1;
// get structure data from DB
$sql = "SELECT node.*,
(COUNT(parent.entry_id) - 1) AS depth,
((COUNT(parent.entry_id) - 1) - $entry_depth) AS subDepth,
if((node.rgt - node.lft) = 1,1,0) AS isLeaf,
expt.title,
expt.status
FROM exp_structure AS node
INNER JOIN exp_structure AS parent
ON node.lft BETWEEN parent.lft AND parent.rgt
INNER JOIN exp_weblog_titles AS expt
ON node.entry_id = expt.entry_id
WHERE parent.lft > 1
AND ($where)
GROUP BY node.entry_id
ORDER BY node.lft";
$result = $DB->query($sql);
// check how many entries at subDepth 0
$num = 0;
foreach ($result->result as $entry) {
if ($entry['subDepth'] == 0) {
$num++;
}
}
// if we only have 1 subDepth 0 entry and it has children
// then we just show the children
if ($num === 1 && $result->num_rows > 1) {
unset($result->result[0]);
foreach ($result->result as &$entry) {
$entry['subDepth'] -= 1;
}
}
// Remove anything to be excluded from the results array
foreach ($result->result as $key => $entry_data) {
if( in_array( strtolower($entry_data['status']), $exclude_status_list) ) {
unset($result->result[$key]);
}
}
if(count($result->result) > 0) {
$html = "<ul>";
$prev_subDepth = false;
$ul_open = false;
foreach ($result->result as $entry_data) {
if ($prev_subDepth === 0 && $entry_data['subDepth'] == 1) {
$html = substr($html, 0, -5);
$html .= "\n<ul>";
$ul_open = true;
} else if ($prev_subDepth === 1 && $entry_data['subDepth'] == 0) {
// Finds the previous entry
preg_match("~<li class=\"(.+)\"><(.+)\</li>~", $list_item, $matches);
// Creates the new class entry
$last_item_class = $matches[1] . " last";
// Stores the inner of the <li>
$last_item_inner = $matches[2];
// Replace the string
$html = str_replace($list_item, "\n<li class=\"$last_item_class\"><$last_item_inner</li>", $html);
$html .= "\n</ul></li>";
$ul_open = false;
}
// out entry uri of this loop instance
$euri = $site_pages['uris'][$entry_data['entry_id']];
// current page's parent uri
$puri = $node['parent_id'] ? $site_pages['uris'][$node['parent_id']] : '';
$here = '';
if ($euri === $puri) {
$here = ' parent' . $separator . 'here';
} else if ($uri === $euri) {
$here = ' here';
}
$last = '';
if($entry_data == end($result->result)) {
$last = ' last';
}
// Make sure we have the site_url path in case we're operating in a subdirectory
// If site_index is set then add it to URIs, otherwise leave it blank
//$root_uri = parse_url($PREFS->ini('site_url'), PHP_URL_PATH); // req. PHP v5.1.2
$the_uri = parse_url($PREFS->ini('site_url'));
$root_uri = $the_uri['path'];
$index_uri = $PREFS->ini('site_index');
//$index_uri = $PREFS->ini('site_index') ? "/" . $PREFS->ini('site_index') : "";
$item_uri = str_replace('//', '/', $root_uri . $index_uri . $euri);
$list_item = "\n<li class=\"sub" . $separator . "level" . $separator . $entry_data['subDepth'] . $here . $last . "\">";
$list_item .= "<a >" . $entry_data['title'];
$list_item .= "</a></li>";
$html .= $list_item;
$prev_subDepth = (int)$entry_data['subDepth'];
}
$html .= $ul_open ? "\n</ul></li></ul>" : "\n</ul>";
}
return $html;
}
Ok, one more modification. I needed to show the category title above my nav links like so:
Category One — Page 1 — Page 2 — Page 3 Category Two — Page 4 — Page 5
Here is a new nav_main method with the option to print the the pages (first) category as a header above the links with the option to link the category title itself.
{exp:structure:nav_main exclude_status="hidden|no_main_nav" show_children="true" show_category_title="true" link_category_title="true"}
function nav_main() {
global $DB, $IN, $OUT, $PREFS, $TMPL;
if($PREFS->ini('word_separator') == 'dash') {
$separator = "-";
} else if ($PREFS->ini('word_separator') == 'underscore') {
$separator = "_";
}
// get site ID
$site_id = $PREFS->ini('site_id');
// get current uri path
$uri = $IN->URI;
// Retrieve status labels to exclude
// break apart string at pipe chars and build array
$exclude_status = $TMPL->fetch_param('exclude_status');
$exclude_status_list = split("\|", strtolower($exclude_status));
$show_children = strtolower($TMPL->fetch_param('show_children'));
$show_category_title = strtolower($TMPL->fetch_param('show_category_title'));
$link_category_title = strtolower($TMPL->fetch_param('link_category_title'));
// get site pages data
//$site_pages = $PREFS->core_ini['site_pages'];
$site_pages = $PREFS->ini('site_pages');
// get structure data from DB
$sql = "SELECT node.*,
expt.title,
expt.status
FROM exp_structure AS node
INNER JOIN exp_weblog_titles AS expt
ON node.entry_id = expt.entry_id
WHERE node.parent_id = 0
AND node.site_id = $site_id
GROUP BY node.entry_id
ORDER BY node.lft";
$result = $DB->query($sql);
// Remove anything to be excluded from the results array
foreach ($result->result as $key => $entry_data) {
if( in_array( strtolower($entry_data['status']), $exclude_status_list) ) {
unset($result->result[$key]);
}
}
$segment_1 = $IN->fetch_uri_segment('1');
if ($OUT->out_type == '404') { $page_not_found = true; } else { $page_not_found = false; }
if(count($result->result) > 0) {
$html = "<ul id=\"nav\">";
$ul_open = false;
foreach ($result->result as $entry_data) {
// out entry uri of this loop instance
$euri = $site_pages['uris'][$entry_data['entry_id']];
// current page's parent uri
$puri = $node['parent_id'] ? $site_pages['uris'][$node['parent_id']] : '';
$here = '';
if ($uri === $euri || ($uri == '' && $euri == '/') || $segment_1 === trim($euri, '/') && !$page_not_found ) {
$here = 'here';
}
$last = '';
if($entry_data == end($result->result)) {
$last = 'last';
if($here != '') { $last = ' ' . $last; }
}
// get category title
$category_name = '';
if( $show_category_title == 'true' )
{
$cat_sql = "SELECT exp_categories.cat_name AS category_name,
exp_categories.cat_url_title AS category_url_title
FROM exp_categories
JOIN exp_category_posts
ON exp_category_posts.cat_id = exp_categories.cat_id
WHERE exp_category_posts.entry_id = ${entry_data['entry_id']}
GROUP BY exp_category_posts.cat_id";
$cat_result = $DB->query($cat_sql);
$category_name = $cat_result->result[0]['category_name'];
$category_url_title = $cat_result->result[0]['category_url_title'];
$blog_sql = "SELECT blog_name FROM exp_weblogs WHERE weblog_id = ${entry_data['weblog_id']}";
$blog_result = $DB->query($blog_sql);
$blog_name = $blog_result->result[0]['blog_name'];
}
// Make sure we have the site_url path in case we're operating in a subdirectory
// If site_index is set then add it to URIs, otherwise leave it blank
//$root_uri = parse_url($PREFS->ini('site_url'), PHP_URL_PATH); // req. PHP v5.1.2
$the_uri = parse_url($PREFS->ini('site_url'));
$root_uri = $the_uri['path'];
$index_uri = $PREFS->ini('site_index');
//$index_uri = $PREFS->ini('site_index') ? "/" . $PREFS->ini('site_index') : "";
$item_uri = str_replace('//', '/', $root_uri . $index_uri . $euri);
if( $show_category_title == 'true' and $previous_category != $category_name ){
if( $link_category_title == 'true' ){
$category_title = "<a href="http://.">ini('reserved_category_word'). "/" .$category_url_title .">". $category_name ."</a>";
} else {
$category_title = $category_name;
}
$html .= "\n<li class=\"category\">". $category_title ."</li>";
}
$html .= "\n<li";
if($here || $last) {
$html .= ' class="' . $here . $last . '"';
}
$html .= ">";
$html .= "<a >" . $entry_data['title'];
$html .= "</a>";
if( $show_children == 'true' and $here == 'here' ) {
$html .= $this->get_children($entry_data['entry_id'], $exclude_status_list);
}
$html .= "</li>";
if( $show_category_title == 'true'){
$previous_category = $category_name;
}
}
$html .= $ul_open ? "\n</ul></li></ul>" : "\n</ul>";
}
//$html .= '<pre>' . $sql . '</pre>
<p>’;
return $html;
}
I’ve found what I would call a “bug” in Structure (version 1.1.1) in that it doesn’t respect the current path of the “themes” directory in ExpressionEngine — or better said, Structure’s CSS needs to be updated so that it doesn’t rely on the Control Panel’s “themes” path.
For example, if the “themes” path in ExpressionEngine is changed from the default then the background images for the Structure Settings” button (CP Home >Modules > Structure) doesn’t appear — instead you’re left with an issue of white text on a white background and the “Settings” button disappearing!!!
This problem drove me nuts for the longest time until I figured out what was wrong. Here’s the two lines of problematic code:
[b]/modules/structure/css/structure.css[/b]
[b]Line 94:[/b] background: transparent url(/themes/cp_themes/default/images/bg_button_a.gif) no-repeat top right;
[b]Line 105:[/b] background: transparent url(/themes/cp_themes/default/images/bg_button_div.gif) no-repeat top left;
Note the dependance upon the ExpressionEngine Control Panel images and path.
The problem should be fixed by either:
1. Bundling the images with the Structure Module (easiest; preferred)
2. Making Structure aware of the themes path setting (difficult; not necessary)
Since Structure already bundles its own assets (Images, Style Sheets, JavaScript), there’s absolutely no reason why the background images can’t be included along with the other assets found in /modules/structure/img.
While this situation is rare and only affects those who have changed the default path of the ‘themes’ directory, the entire problem can (and should) be avoided by fixing two lines of code.
I’ve got to say that once you work out the quirks and conflicts, Structure is absolutely brilliant. That said, I could do with a bit of guidance:
I’m building out a site with multiple listing pages – since the weblog that’s being listed is selected for the page within the Structure tab, is there a way of reading that in and passing it to the {exp:weblog:entries weblog="pressreleases" dynamic="off"} tag? I’d hate to have to create a separate template for every listing page, only to change the weblog value…
Oh, also: I can’t seem to get pagination to work correctly. It’s generating the correct links, but doesn’t seem to pick up the offset when you click any of them, instead just showing the first n records. The tag configuration I’m trying to use is:
{exp:structure:paginate parse="inward" show_num_pages="3"}
{exp:weblog:entries weblog="news" dynamic="off" limit="2"}
<h3><a href="http://{page_url}">{title}</a></h3>
{entry_date format="%F %d, %Y"}
{/exp:weblog:entries}
{/exp:structure:paginate}
@mkuplens no reason to involve Structure in that as that’s not really what it’s meant for. Just make a normal template group for that. Structure is really for an easy dynamic page hierarchy and simple interface for your clients. They will never “edit” the RSS feed as it’s drawn automatically from other “listing” weblogs.
Packet Tide owns and develops ExpressionEngine. © Packet Tide, All Rights Reserved.