banacan Posted September 19, 2011 Share Posted September 19, 2011 I'm using a modification of script 1.3 to create a nested navigation menu. So far I've got the structure working great, the question I have is how do I add another field to the list() array - or in my case the link() array. What I have now is the navigation name showing in the structure, but I need the value from another field for the link. Here is what I have: // Funtion for displaying list. // Receives one argument: an array. function make_list ($parent) { // Need the main pages array: global $links; // Start an unordered list: echo '<ul class="sf-menu sf-vertical">'; // Loop through each subarray: foreach ($parent as $pid => $nav_name) { // Display the list item: echo "<li class=\"sfHover\"><a href=\"$link_name\">$nav_name</a>"; // Check for subpages: if (isset($links[$pid])) { // Call this function: make_list($links[$pid]); } // Complete the list item: echo '</li>'; } // End of FOREACH loop. // Close the unordered list: echo '</ul>'; } // end of make_list() function ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>Test nested navigation</title> </head> <body> <?php // Initialize the storage array: $links = array(); while (list($page_id, $pid, $nav_name, $link_name ) = mysql_fetch_array($pageList, MYSQL_NUM)) { // Add to the array: $links[$pid][$page_id] = $nav_name; } // For debugging: echo '<pre>' . print_r($links,1) . '</pre>'; // Send the first array element // to the make_list() function: make_list($links[$start]); As you can see, I've added $link_name to the while(list()) but I can't understand how to get $link_name added to the array which contains the nested navigation items. You can also see how I have added $link_name to the <a> element in the <li> but when I test the script I only get <a href="">whatever</a>. Here is my SQL: mysql_select_db($database_siteuser, $siteuser); $query_pageList = "SELECT page_id, pid, nav_name, link_name, ordr FROM webtext WHERE page_id != 0 AND navInclude = 'y' OR sidebar_disp = 'y' ORDER BY pid, ordr"; $pageList = mysql_query($query_pageList, $siteuser) or die(mysql_error()); $row_pageList = mysql_fetch_assoc($pageList); Any help would be appreciated. Link to comment Share on other sites More sharing options...
Larry Posted September 19, 2011 Share Posted September 19, 2011 You would replace this line: $links[$pid][$page_id] = $nav_name; with: $links[$pid][$page_id] = array('nav' => $nav_name, 'link' => $link_name); That will store the link-name as an array. Then, to display them, you would replace: foreach ($parent as $pid => $nav_name) { with: foreach ($parent as $pid => $item) { And within the foreach loop, you'd use $item['nav'] and $item['link'] Link to comment Share on other sites More sharing options...
banacan Posted September 20, 2011 Author Share Posted September 20, 2011 Hi Larry, Thanks for the reply. I made those changes and the structure is correct (I see the sub-array with 'link' and 'nav') but I'm having difficulty with the output. If I have: echo "<li class=\"sf_hover\">$nav_name"; I see the structure (with the debugging uncommented) though there is nothing but an empty ul li. If I have: echo "<li class=\"sf_hover\">$item['nav']"; I see nothing, just a blank page. What is happening? Link to comment Share on other sites More sharing options...
banacan Posted September 21, 2011 Author Share Posted September 21, 2011 As I suspected, the problem was with escaping single and double quotes. Instead of trying to find my way through that labyrinth, I just combined HTML and code using the concatenator ".", now all is well. Thanks Larry. Link to comment Share on other sites More sharing options...
Larry Posted September 21, 2011 Share Posted September 21, 2011 Glad it's working and thanks for letting us know. Link to comment Share on other sites More sharing options...
banacan Posted September 21, 2011 Author Share Posted September 21, 2011 Hi Larry, I have another question, is there a way to show the "path" of sub-navigation items within this script? Say the main category is Fresh Fruits & Vegetables, a sub-category would be Fruits, and the item would be Apples. I would like to have the hierarchy part of the <li> element for linking purposes. So something like: fresh-fruits-and-vegetables/fruits/apples/ In the multidimensional array structure the "categories" are represented by the pid, so I would need to use the associated link_name for each level or iteration. Can this be done? Many thanks, Brett Link to comment Share on other sites More sharing options...
Larry Posted September 23, 2011 Share Posted September 23, 2011 Hmmm...interesting question. It certainly can be done, it's just a matter of how. My initial thought is to pass the preface (e.g., fresh-fruits-and-vegetables/fruits/) along as a second argument to the function, so that the function can add that to subcategories. You'd just need a little logic as to when the preface gets passed along and when it changes. Link to comment Share on other sites More sharing options...
banacan Posted September 23, 2011 Author Share Posted September 23, 2011 The recursion function "walks the tree", iteration by iteration, mapping the entire tree. But as it does so, it replaces the variable value during each iteration. So how would the "preface" be created? It seems to me that what I need is a second function that can walk the tree in the opposite direction creating an array of all link_names related by pid and page_id up to 0. As you have probably figured out, I'm trying to create a dynamic menu for use with my .htaccess file. Using your modularized web site approach, I have the home page at the site root, then I have sub-directories (what I call category directories) which contain modularized index pages (all category pages have a pid value of 0). All pages below each category page can be further nested by making the parent page (page_id) it is descended from the pid. Though the descendant category pages are really just the index page with the content being replaced, I need to show the hierarchical relationship to match the RewriteRule in my .htaccess file. This is an issue that must be common, since all frameworks use this method. Do you know how they have solved this problem? I assume some form of recursion is necessary, since the level of depth is unknown. Thanks for your continued help. Link to comment Share on other sites More sharing options...
Larry Posted September 23, 2011 Share Posted September 23, 2011 You already have recursion, so you shouldn't need to do a reverse recursion, too. What I was thinking is you start by defining the recursive function so it takes an optional second argument: function make_list ($parent, $preface = '') { Then, when you call the function recursively, you can send the current item along as the preface of the subelements: make_list($links[$pid], $nav_name); And you change the function so that it uses the preface, when appropriate, in creating the link. That's the basic idea. To acknowledge sub-sub links, you can append the next the next preface onto the current preface and pass that along. The only thing that I don't know the answer to off the top of my head is when/how you reset the preface. Perhaps you have thoughts on that or I might if I had a visual of the sample data. Link to comment Share on other sites More sharing options...
banacan Posted October 13, 2011 Author Share Posted October 13, 2011 Hi Larry, I'm sorry for the long delay in responding to your last post, I was sick for a week and when I got back to work I had a big backlog of work and looming deadlines. I have tried a couple of things so far but nothing is working. I tried adding the second argument to the function, but when I called the function with $nav_name as the value of the second parameter, nothing at all appeared - there was no value. I thought it might help for you to see the nesting structure so you can see what I'm trying to accomplish: Array ( [0] => Array ( [34] => Array ( [pid] => 0 [nav] => Mouldings [link] => mouldings ) [35] => Array ( [pid] => 0 [nav] => News [link] => news ) [57] => Array ( [pid] => 0 [nav] => Gallery [link] => gallery ) ) [34] => Array ( [36] => Array ( [pid] => 34 [nav] => Historical [link] => historical-mouldings ) [37] => Array ( [pid] => 34 [nav] => Stock [link] => stock-mouldings ) [46] => Array ( [pid] => 34 [nav] => Custom [link] => custom-mouldings ) ) [35] => Array ( [44] => Array ( [pid] => 35 [nav] => Industry [link] => industry-news ) ) [36] => Array ( [45] => Array ( [pid] => 36 [nav] => Colonial [link] => colonial-style-mouldings ) [38] => Array ( [pid] => 36 [nav] => Craftsman [link] => craftsman-style-mouldings ) [39] => Array ( [pid] => 36 [nav] => Federal [link] => federal-style-mouldings ) [47] => Array ( [pid] => 36 [nav] => Georgian & Wren [link] => georgian-and-wren ) [59] => Array ( [pid] => 36 [nav] => Victorian [link] => victorian-style-mouldings ) ) [47] => Array ( [58] => Array ( [pid] => 47 [nav] => Georgian [link] => georgian-style-mouldings ) [48] => Array ( [pid] => 47 [nav] => Wren [link] => wren-style-mouldings ) ) ) Mouldings Historical Colonial Craftsman Federal Georgian & Wren Georgian Wren Victorian Stock Custom News Industry Gallery This is not all of the structure but it will show you the level of nesting involved. Your continued help is appreciated. Link to comment Share on other sites More sharing options...
banacan Posted October 17, 2011 Author Share Posted October 17, 2011 Hi Larry, I've been able to get the parent link added to the path of the current link, but I still haven't figured out how to append the new parent link onto the previous "preface" and continue that process to the last child. Also, it's unclear to me how the recursion process works - I hope I can describe what I mean because I'm sure it makes very big difference. During recursion, does the "path" begin at the root level and proceed down every child to the end, creating a complete map for each child, or does it map only from the parent node for each? I'm assuming, based on your previous post about resetting, that it only maps from the parent node. Here is what I have right now that is working - sort of: // Funtion for displaying list. // Receives one argument: an array. function make_list ($parent, $preface = '') { // Need the main pages array: global $links; // Start an unordered list: echo '<ul class="sf-menu sf-vertical">'; // Loop through each subarray: foreach ($parent as $pid=>$item) { // Display the list item: ?> <li class="sf-hover"><a href="<?php echo $basedir . "/" . $preface . "/" . $item['link'] ?>/"> <?php echo $item['nav']; // Check for subpages: if (isset($links[$pid])) { // Call this function: make_list($links[$pid], $item['link']); } // Complete the list item: echo '</li>'; } // End of FOREACH loop. // Close the unordered list: echo '</ul>'; } // end of make_list() function ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>Test nested navigation</title> </head> <body> <?php // Initialize the storage array: $links = array(); while (list($page_id, $pid, $nav_name, $link_name ) = mysql_fetch_array($pageList, MYSQL_NUM)) { // Add to the array: $links[$pid][$page_id] = array('pid'=>$pid, 'nav'=>$nav_name,'link'=>$link_name); } // For debugging: echo '<pre>' . print_r($links,1) . '</pre>'; // Send the first array element // to the make_list() function: make_list($links[0]); ?> </body> Thanks for your help. Link to comment Share on other sites More sharing options...
banacan Posted October 17, 2011 Author Share Posted October 17, 2011 Well, I've figured out how to append the parents to the child to make the links correct. EXCEPT, as you said, I haven't been able to figure out how to get it to reset. Anyway, here is my modified code that at least creates the full path - for one branch of the tree: // Funtion for displaying list. // Receives one argument: an array. function make_list ($parent, $preface = '') { // Need the main pages array: global $links; // Start an unordered list: echo '<ul class="sf-menu sf-vertical">'; // Loop through each subarray: foreach ($parent as $pid=>$item) { // Display the list item: ?> <li class="sf-hover"><a href="<?php echo $basedir . "/" . $preface . $item['link'] . "/" ?>"> <?php echo $item['nav']; // Check for subpages: if (isset($links[$pid])) { // Call this function: make_list($links[$pid], ($preface .= $item['link'] . "/") ); } // Complete the list item: echo '</li>'; } // End of FOREACH loop. // Close the unordered list: echo '</ul>'; } // end of make_list() function Mouldings Historical Colonial Craftsman Federal Georgian & Wren Georgian Wren Victorian Stock Custom News Industry Gallery So from the structure shown above, the link for Wren is: http://www.whatever....tyle-mouldings/ Great, but the very next link in the list is Victorian and that link is: http://www.whatever....tyle-mouldings/ but it should be: http://www.whatever....tyle-mouldings/ but it's not, because I don't know how to reset the preface. To give you a little more info on what is being produced by this code, the link for Stock is: http://www.whatever....tock-mouldings/ it should be: http://www.whatever....tock-mouldings/ Preface seems to reset itself on links above itself, but not adjacent to itself, which is why the News link is: http://www.whatever....mouldings/news/ but should be: http://www.whatever.com/news/ news is adjacent to mouldings and so is gallery - all three are at the same nesting level. One last link to show you is for Gallery: http://www.whatever....s/news/gallery/ Here you can see how all previous adjacent links are added to the path, though they shouldn't be. Anyway, I hope this gives you some ideas on how this can be corrected and you might have a suggestion for me. Thanks Link to comment Share on other sites More sharing options...
Larry Posted October 18, 2011 Share Posted October 18, 2011 Okay. Thanks for sharing where you're at. Give me a couple of days to look this over and see what I can suggest. Link to comment Share on other sites More sharing options...
banacan Posted October 18, 2011 Author Share Posted October 18, 2011 Larry, Thanks, I would appreciate any suggestions you might be able to offer. Link to comment Share on other sites More sharing options...
banacan Posted November 4, 2011 Author Share Posted November 4, 2011 Hi Larry, I'm still struggling to figure out how to reset $preface and I'm hoping you can provide some guidance. As I said in an earlier post, $preface resets itself when moving up to the parent level but it does not reset itself at the sibling level. It seems to me what I need to do is find the $key=>$value pair where the $key = the current $pid, then locate that $value in the $preface string so I can use substr() and stripos() to replace $preface. So my question is how do I search - within the foreach loop - for the $key=>$value pair where the $key = the current $pid? Link to comment Share on other sites More sharing options...
Larry Posted November 5, 2011 Share Posted November 5, 2011 Sorry for the lack of reply. This has been on my to-reply list, I just haven't had time to get to it. I'll do my best to run some code and come up with a solution in the next few days. Link to comment Share on other sites More sharing options...
banacan Posted November 5, 2011 Author Share Posted November 5, 2011 Hey Larry, I know you are busy and I also know that you give your time out of the goodness of your heart, so I want to thank you for spending a little of that valuable time on me. Warm regards, Brett Link to comment Share on other sites More sharing options...
Larry Posted November 23, 2011 Share Posted November 23, 2011 Hey Brett. I'm sorry. I've really meant to get to this, but I'm so behind in my own work and about to take off for the holidays. I haven't tested this yet, but I think the solution would be to use an array for the prefaces. For each new level, you add another item to the end of the array. And you pass the array to the function with each recursive call. Then, after the last recursive function call and before the next one (i.e., after the make_list() call but before the end of the foreach), you would pop off the last element in the array. I'm not positive that will work, but that's what I would test next. Apologies for the delay and for not having the time to test this theory before offering it up. Link to comment Share on other sites More sharing options...
banacan Posted December 19, 2011 Author Share Posted December 19, 2011 Hey Larry, Thanks for your reply, I totally understand about being behind on work, I too am overloaded at the moment which is why I'm so late in replying to you. It seems to me, if I understand what you are recommending, lopping off the last element of the array will work if each nested item is only one level away. But what happens if one nav link is 4 levels deep and the very next nav link is only 1 level deep? I'd only be lopping off to the third level which would make the hierarchy incorrect and the link wrong. Does that make sense? So I'm wondering, would there be a way to assign the depth level to each nav link and to the current depth level of the preface so that the array string could be cut back the right number of levels based on each nav link level? Could that work? Thanks, Brett Link to comment Share on other sites More sharing options...
Larry Posted December 20, 2011 Share Posted December 20, 2011 No, lopping off the last element of the array would be done after the recursive call. So if you were to go down four levels, there would be four pops of the last array element off of the array before getting back to that top level. Link to comment Share on other sites More sharing options...
banacan Posted December 29, 2011 Author Share Posted December 29, 2011 Hi Larry, I'm very very close now thanks to your suggestion. Here is what I currently have: // Funtion for displaying links. // Receives one argument: an array. function make_list ($parent, $preface = '') { // Need the main pages array: global $links; // Start an unordered list: echo '<ul class="sf-menu sf-vertical">'; // Loop through each subarray: foreach ($parent as $pid=>$item) { // Display the list item: ?> <li class="sf-hover"><a href="<?php echo $basedir . "/" . $preface . $item['link'] . "/" ?>"> <?php echo $item['nav']; ?></a><?php // Check for subpages: if (isset($links[$pid])) { // Call this function: make_list($links[$pid], ($preface .= $item['link'] . "/") ); // lop off last element of $preface array $length = strlen($preface); $pos = strrpos($preface,'/', -2); $slength = ($length - 1) - $pos; $preface = substr($preface, 0, -$slength); } // Complete the list item: echo '</li>'; } // End of FOREACH loop. // Close the unordered list: echo '</ul>'; } // end of make_list() function // Initialize the storage array: $links = array(); while (list($page_id, $pid, $nav_name, $link_name ) = mysql_fetch_array($pageList, MYSQL_BOTH)) { // Add to the array: $links[$pid][$page_id] = array('pid'=>$pid, 'nav'=>$nav_name,'link'=>$link_name); } Here is the nav menu output: Mouldings - link path is: /mouldings/ Historical - link path is: /mouldings/historical-mouldings/ Colonial - link path is: /mouldings/historical-mouldings/colonial-style-mouldings/ Craftsman - link path is: /mouldings/historical-mouldings/craftsman-style-mouldings/ Federal - link path is: /mouldings/historical-mouldings/federal-style-mouldings/ Georgian & Wren - link path is: /mouldings/historical-mouldings/georgian-and-wren/ Georgian - link path is: /mouldings/historical-mouldings/georgian-and-wren/georgian-style-mouldings/ Wren - link path is: /mouldings/historical-mouldings/georgian-and-wren/wren-style-mouldings/ Victorian - link path is: /mouldings/historical-mouldings/victorian-style-mouldings/ Stock - link path is: /mouldings/stock-mouldings/ Custom - link path is: /mouldings/custom-mouldings/ News - link path is: /mnews/ Industry - link path is: /mnews/industry-news/ Gallery - link path is: /mgallery/ As you can see, the links are all correct until News and Gallery where there is a stray "m" mucking things up. These are base categories like Mouldings, but because I had to subtract 1 from $length to have the deeper links display correctly, it leaves the stray "m" (from Mouldings) in front of News and Gallery. Here is what happens if I don't subtract 1 from $length: Mouldings - link path is: /mouldings/ Historical - link path is: /mouldings/historical-mouldings/ Colonial - link path is: /mouldings/historical-mouldings/colonial-style-mouldings/ Craftsman - link path is: /mouldings/historical-mouldings/craftsman-style-mouldings/ Federal - link path is: /mouldings/historical-mouldings/federal-style-mouldings/ Georgian & Wren - link path is: /mouldings/historical-mouldings/georgian-and-wren/ Georgian - link path is: /mouldings/historical-mouldings/georgian-and-wren/georgian-style-mouldings/ Wren - link path is: /mouldings/historical-mouldings/georgian-and-wren/wren-style-mouldings/ Victorian - link path is: /mouldings/historical-mouldingsvictorian-style-mouldings/ Stock - link path is: /mouldingsstock-mouldings/ Custom - link path is: /mouldingscustom-mouldings/ News - link path is: /news/ Industry - link path is: /news/industry-news/ Gallery - link path is: /gallery/ You will see that the "/" is missing between historical-mouldings and victorian-style-mouldings, as well as mouldings and stock-mouldings, and mouldings and custom-mouldings. Now however, News and Gallery are correct. Do you have any ideas how to solve this? Thanks for your continued help. Link to comment Share on other sites More sharing options...
banacan Posted December 30, 2011 Author Share Posted December 30, 2011 I think I finally have it figured out. I had forgotten that I had access to the pid value for each item - which for category pages is 0 - so for those whose pid = 0 I reset the $preface manually, the rest I kept as before. Here is my final code for those who are interested: // Funtion for displaying links. // Receives one argument: an array. function make_list ($parent, $preface = '') { // Need the main pages array: global $links; // Start an unordered list: echo '<ul class="sf-menu sf-vertical">'; // Loop through each subarray: foreach ($parent as $pid=>$item) { // Display the list item: ?> <li class="sf-hover"><a href="<?php echo $basedir . "/" . $preface . $item['link'] . "/" ?>"> <?php echo $item['nav']; ?></a><?php // Check for subpages: if (isset($links[$pid])) { // Call this function: make_list($links[$pid], ($preface .= $item['link'] . "/") ); // lop off last element of $preface array or reset it $length = strlen($preface); $pos = strrpos($preface,'/', -2); $slength = ($length - 1) - $pos; $item['pid'] == 0 ? $preface = '' : $preface = substr($preface, 0, -$slength); } // Complete the list item: echo '</li>'; } // End of FOREACH loop. // Close the unordered list: echo '</ul>'; } // end of make_list() function // Initialize the storage array: $links = array(); while (list($page_id, $pid, $nav_name, $link_name ) = mysql_fetch_array($pageList, MYSQL_BOTH)) { // Add to the array: $links[$pid][$page_id] = array('pid'=>$pid, 'nav'=>$nav_name,'link'=>$link_name); } Here is the resulting nav menu: Mouldings - link path is: /mouldings/ Historical - link path is: /mouldings/historical-mouldings/ Colonial - link path is: /mouldings/historical-mouldings/colonial-style-mouldings/ Craftsman - link path is: /mouldings/historical-mouldings/craftsman-style-mouldings/ Federal - link path is: /mouldings/historical-mouldings/federal-style-mouldings/ Georgian & Wren - link path is: /mouldings/historical-mouldings/georgian-and-wren/ Georgian - link path is: /mouldings/historical-mouldings/georgian-and-wren/georgian-style-mouldings/ Wren - link path is: /mouldings/historical-mouldings/georgian-and-wren/wren-style-mouldings/ Victorian - link path is: /mouldings/historical-mouldings/victorian-style-mouldings/ Stock - link path is: /mouldings/stock-mouldings/ Custom - link path is: /mouldings/custom-mouldings/ News - link path is: /news/ Industry - link path is: /news/industry-news/ Gallery - link path is: /gallery/ Thank you Larry for your help, I'm sure I wouldn't have gotten this figured out without it. And thank you also for the fine book that provided me with the initial script which has made this possible. This was a major accomplishment for me because it was vital for a dynamic navigation menu which works with my .htaccess file. I sure do value your books and this forum where you are always so generously giving of your time. Best, Brett Link to comment Share on other sites More sharing options...
Larry Posted January 3, 2012 Share Posted January 3, 2012 Kudos for figuring it out and thanks for sharing your solution. I'm glad you got it working. Thanks, too, for the nice words on what I do! Link to comment Share on other sites More sharing options...
Recommended Posts