I've been doing some researching and discovered this nice website http://validator.w3.org/
After running a test i see that my navigation get loads of error.
The error i get is the ul in the coding. I don't close it off because i give it it styling if a condition is met else close it.
But this is not a valid solution according to w3 which gives me some errors.
Can you help me find a fix for my navigation so it gets valid?
With thanks Jim
<ul id="nav-container">
<?php
$select_category = mysql_query("SELECT * FROM menu WHERE hidden = 0 ORDER BY menu ASC");
while ($ln = mysql_fetch_array($select_category)) {
$idcat = $ln['nmr'];
$catname = $ln['menu'];
$catsname = str_replace(' ', '-', $ln['menu']);
echo '<li>';
if($catname == "carparts") {
echo '<span><strong>'.$catname.'</strong></span>';
} else {
echo '<span><strong>'.$catname.'</strong></span>';
}
This gives me the errors: (fixed)
echo '<ul';
if(isset($_GET['cats'])) {
if ($_GET['cats'] == $idcat) {
echo ' style="display:block;">';
} else {
echo '>';
}
The fix: also deleted the closing bracket at the end.
echo '<ul';
if(isset($_GET['cats']) && $_GET['cats'] == $idcat){
echo ' style="display:block;">';
} else {
echo '>';
}
/fix finish
//Error finish
$select_sub = mysql_query("SELECT * FROM submenu WHERE nmrmenu = '$idcat' AND hidden = 0");
while ($lsub = mysql_fetch_array($select_sub)) {
$subname = $lsub['submenu'];
$subsname = str_replace(' ', '-', $lsub['submenu']);
$pil = 'ยป';
$brnr = $lsub['nmr'];
if(isset($_GET['cat'])) {
if ($_GET['cat'] == $brnr) {
$subname = '<u>'.$lsub['submenu'].'</u>';
} else {
$subname = $lsub['submenu'];
}
}
echo '<li><span><strong> '.$subname.' </strong></span></li>';
}
echo '</ul>';
echo '</li>'; // to this location
}
echo '</li>'; //relocated this up one line
} **//Deleted this one!**
?>
</ul>
Update
The output gets like this which is horrible: (fixed)
<ul</li><li><span><strong>name</strong></span>
<ul</li><li><span><strong>name</strong></span><ul</li>
New: now the ul problem is gone, but it's complaining about the li's. Any clue why?
Error: document type does not allow element "li" here; missing one of "ul", "ol", "menu", "dir" start-tag
<ul id="nav-container">
<li>
<span><strong>name</strong></span>
<ul>
<li>
<span><strong> name </strong></span>
</li>
</ul>
</li>
</ul>
/update
You have </ul> and then immediately follow it with a <li>. You can't have a list item outside of a list.
Related
I am working on a calendar script to output events that are grouped by month. Everything is working fine, except I can't figure out how to add a div wrapper around each month without some closing tag issues. Here is my loop code:
if ($posts) {
$month_titles = array();
$close = false;
foreach( $posts as $post ) {
setup_postdata( $post );
$month_title = date('F Y', strtotime(get_post_meta($post->ID,'_event_start_local', true)));
if(!in_array($month_title, $month_titles)) {
if($close) echo '</ul>';
echo '<h4>'.$month_title.'</h4>';
echo '<ul>';
$month_titles[] = $month_title;
$close = true;
}
echo '<li>'.get_the_title().'</li>';
}
if ($close) echo '</ul>';
}
Here is how this is current output:
<h4>Month Name 2018</ul>
<ul>
<li>Title of Event</li>
<li>Title of Event</li>
</ul>
I would like for it to be like this:
<div>
<h4>Month Name 2018</h4>
<ul>
<li>Title of Event</li>
<li>Title of Event</li>
</ul>
</div>
I have tried a few different ways to add the div wrap and it either closes too early or too late. I need a fresh set of eyes on this as I have been messing with it too long!
This logic should work for what you want:
// preset some vars
$oldMonth = null;
$firstItem = true;
foreach($posts as $post) {
setup_postdata($post);
$month_title = date('F Y', strtotime(get_post_meta($post->ID,'_event_start_local', true)));
// check if we have a new month coming up:
if($oldMonth != $month_title) {
// when it's the first one ever, just open the div
if($firstItem) {
echo "<div>";
$firstItem = false; //..and remember that the following aren't the first
} else { // else close the previous ones and open a new one
echo "</ul></div><div>";
}
// show the new month and open the list
echo '<h4>'.$month_title.'</h4>';
echo '<ul>';
}
echo '<li>'.get_the_title().'</li>';
$oldMonth = $month_title; // remember the last month
}
// at the end close the last ul and last div
echo '</ul></div>';
It seems just changing these lines:
if($close) echo '</ul>';
echo '<h4>'.$month_title.'</h4>';
to
if($close) echo '</ul></div>';
echo '<div><h4>'.$month_title.'</h4>';
should do what you want. Note you have to change the if on $close in both places in your code)
In working on a dynamic menu w/ CRUD I have been having some trouble with the finishing touches. It works, but there are some extra tags getting inserted where there shouldn't be and can't figure out how to clean it up before I share it with the world. I used this as a starting point, then changed it to work with an accordion menu (http://www.phpro.org/tutorials/Simple-Mysql-PHP-Menu.html).
Below is the data from the table (I changed the names on the first 2 fields to get it to fit in the SO format from menu_item_id to id, and from menu_parent_id to pid).
id pid menu_item_name menu_url sortorder status
1 0 Settings 0 ACTIVE
2 5 Grid Demo grid.php ACTIVE
3 5 setGridOptions gridoptions.php ACTIVE
4 1 Menu Items adminmenu.php 1 ACTIVE
5 0 Grid Settings 100 ACTIVE
6 1 General Settings settings.php 100 ACTIVE
Here is the PHP that connects to the mysql database and creates the hierarchical tree array to make it work:
include 'db.php';
$sql = "SELECT * FROM menu_items WHERE status = \"ACTIVE\" ORDER BY sortorder, menu_item_name";
$query = $db->query($sql);
while($data = $query->fetch(PDO::FETCH_ASSOC))
// loop over the results
{
// Assign by reference
$thisref = &$refs[ $data['menu_item_id'] ];
// add the the menu parent
$thisref['menu_item_id'] = $data['menu_item_id'];
$thisref['menu_parent_id'] = $data['menu_parent_id'];
$thisref['menu_item_name'] = $data['menu_item_name'];
$thisref['menu_url'] = $data['menu_url'];
// if there is no parent id
if ($data['menu_parent_id'] == 0)
{
$list[ $data['menu_item_id'] ] = &$thisref;
}
else
{
$refs[ $data['menu_parent_id'] ]['children'][ $data['menu_item_id'] ] = &$thisref;
}
}
function create_list( $arr )
{
$html = "";
foreach ($arr as $key=>$v)
{
if ($v['menu_parent_id'] == '0')
{
$html .= '<a class="menuitem submenuheader" href="'. $v['menu_url'] .'">'.$v['menu_item_name']."</a>\n";
$html .= "<div class=\"submenu\">\n<ul>\n";
$html .= "<li>" . create_list($v['children']) . "</li>";
$html .= "</ul>\n";
}
else{
$html .= '<li><a id="' . $v['menu_item_id'] . '">'.$v['menu_item_name']."</a></li>\n";
}
}
$html .= "</div>\n";
return $html;
}
echo "<div class=\"glossymenu\">";
echo create_list( $list );
echo "</div>";
When I run it, it outputs the following:
<div class="glossymenu"><a class="menuitem submenuheader">Settings</a>
<div class="submenu">
<ul>
<li><li><a id="4">Menu Items</a></li>
<li><a id="6">General Settings</a></li>
</div>
</li></ul>
<a class="menuitem submenuheader" href="">Grid Settings</a>
<div class="submenu">
<ul>
<li><li><a id="2">Grid Demo</a></li>
<li><a id="3">setGridOptions</a></li>
</div>
</li></ul>
</div>
</div>
As you can see there are extra <li> tags, the </ul> is in the wrong
spot (should be after the </div>) Other than that, it is working great.
The other thing I can't figure out is if I have a root menu item with no children, I would love it to have a different output like
<a id="8">No Children Menu Item</a>
Instead of:
<a class="menuitem submenuheader">No Children Menu Item</a>
The second example would create the make it show up the little (+/-) for expanding and contracting and wouldn't allow me to click on it. For clarification on the <a> tags, I am using javascript to do a .get() based off the id which is why there is no href or url shown.
UPDATE
It is working correctly and I posted it on Github for anyone that wants it.
https://github.com/ajhalls/php-accordian-menu
Try this :
<?php
include 'db.php';
$sql = "SELECT * FROM menu_items WHERE status = 'ACTIVE' ORDER BY pid ASC, sortorder ASC, menu_item_name ASC";
$query = $db->query($sql);
$menu_items = array();
while($data = $query->fetch(PDO::FETCH_ASSOC)) {
if($data['pid'] == 0) {
$menu_items[$data['id']] = array();
$menu_items[$data['id']]['id'] = $data['id'];
$menu_items[$data['id']]['name'] = $data['menu_item_name'];
$menu_items[$data['id']]['url'] = $data['menu_url'];
$menu_items[$data['id']]['children'] = array();
} else if($data['pid'] != 0) {
$tmp = array();
$tmp['id'] = $data['id'];
$tmp['name'] = $data['menu_item_name'];
$tmp['url'] = $data['menu_url'];
array_push($menu_items[$data['pid']]['children'],$tmp);
unset($tmp);
}
}
function create_list($arr)
{
$html = "";
foreach($arr as $key => $value) {
if(count($value['children']) > 0) {
$html .= ' <a class="menuitem submenuheader" href="'. $value['url'] .'">'.$value['name'].'</a>
<div class="submenu">
<ul>';
foreach($value['children'] AS $child) {
$html .= ' <li>
<a id="'.$child['id'].'">'.$child['name'].'</a>
</li>';
}
$html .= ' </ul>
</div>';
} else{
$html .= ' <a id="'.$value['id'].'">'.$value['name'].'</a>';
}
}
return $html;
}
echo "<div class=\"glossymenu\">";
echo create_list($menu_items);
echo "</div>";
?>
I'm building navigation for a site and for the life of me I can't figure out recursion. I have all my data stored via MySQL using this design:
I've read several links on how recursion works and I must be slow because it's difficult for me to grasp. I've tried to write something and I know it is not even close to what I really need, but it's a start:
PDO
public function viewCategories()
{
$viewSQL = "SELECT * FROM categories";
try
{
$pdo = new PDO('mysql:host=localhost;dbname=store','root','');
$pdo->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
$categoryVIEW = $pdo->prepare($viewSQL);
$categoryVIEW->execute();
$array = $categoryVIEW->fetchAll(PDO::FETCH_ASSOC);
$categoryVIEW->closeCursor();
$json = json_encode($array);
return $json;
}
catch(PDOexception $e)
{
return $e->getMessage();
exit();
}
}
Recursion
$return = json_decode($category->viewCategories(),true);
function buildNavigation($json)
{
foreach($json as $item)
{
if($item['category_id'] === $item['parent'])
{
print('<li>'.$item['category_name'].'</li>');
if($item['category_id'] === $item['parent'])
{
print('<li>match'.$item['category_name'].'</li>');
buildNavigation($json);
}
}
}
buildNavigation($return);
as expected this will never enter the condition. I did try to figure this out on my own since this is a good thing to have knowledge of, but I guess it's beyond my mental capacity :(
Thanks for having a look :)
UPDATE
I know this has been answered already, but is there a way I can do this to build an associative array? I have been playing around with a function that ALMOST works for me that I got from HERE, but it adds an extra array that I do NOT want.
Method
private function buildCategories($array,$parent)
{
$result = array();
foreach($array as $row)
{
if($row['parent'] == $parent)
{
$result[$row['category_name']] = $this->buildCategories($array,$row['category_id']);
}
}
return $result;
}
$json = json_encode($this->buildCategories($array,NULL));
return $json;
I want this:
{"reloading":{"components","presses and dies","tumblers & scales","tools & accessories","shotshell reloading"}
but what I get is this:
{"reloading":{"components":[],"presses and dies":[],"tumblers & scales":[],"tools & accessories":[],"shotshell reloading":[]}
Here's an example with recursion.
function buildNavigation($items, $parent = NULL)
{
$hasChildren = false;
$outputHtml = '<ul>%s</ul>';
$childrenHtml = '';
foreach($items as $item)
{
if ($item['parent'] == $parent) {
$hasChildren = true;
$childrenHtml .= '<li>'.$item['category_name'];
$childrenHtml .= buildNavigation($items, $item['category_id']);
$childrenHtml .= '</li>';
}
}
// Without children, we do not need the <ul> tag.
if (!$hasChildren) {
$outputHtml = '';
}
// Returns the HTML
return sprintf($outputHtml, $childrenHtml);
}
print buildNavigation($items);
That script produces the following output :
<ul>
<li>Menu 1</li>
<li>Menu 2
<ul>
<li>Sub Menu 2.1</li>
<li>Sub Menu 2.2</li>
<li>Sub Menu 2.3
<ul>
<li>Sub Menu 2.2.1</li>
<li>Sub Menu 2.2.2</li>
<li>Sub Menu 2.2.3</li>
</ul>
</li>
</ul>
</li>
<li>Menu 3</li>
</ul>
I have the same above code with little bit modification, so that a user can apply different css on each level of menu, now its showing classes of sub menu like child-class1 when its in 1st sub menu , and it will show child-class2 when its in 2nd sub menu and so on...
<?php
function buildNavigation($items, $parent = NULL, $n=NULL)
{
$hasChildren = false;
if ($parent == NULL)
{
$level=0;
$outputHtml = '<ul class="parent-class">%s</ul>';
}
else
{
if($n==NULL)
{
$level=1;
}
else
{
$level=$n;
}
$outputHtml = '<ul class="child-class'.$level.'">%s</ul>';
}
$childrenHtml = '';
foreach($items as $item)
{
if ($item['parent'] == $parent) {
$hasChildren = true;
$childrenHtml .= '<li>'.$item['ptitle'].'';
$next = ++$level;
$childrenHtml .= buildNavigation($items, $item['pageid'],$next);
$childrenHtml .= '</li>';
}
}
// Without children, we do not need the <ul> tag.
if (!$hasChildren) {
$outputHtml = '';
}
// Returns the HTML
return sprintf($outputHtml, $childrenHtml);
}
echo buildNavigation($ppages);
?>
it will show out put like this
<ul class="parent-class">
<li>
page 1
<ul class="child-class1">
<li>
this is child page
<ul class="child-class2">
<li>
child of child </li>
</ul>
</li>
</ul>
</li>
</ul>
I would like to thanks Mr #Maxime Morin.
I need to take some simple UL tag generated in PHP (Joomla 1.5) and wrap each anchor tag's text content with a SPAN tag. The incoming HTML looks like this:
<ul>
<li>
Home
</li>
<li>
Watch UNC-TV
</li>
<li>
<a href="#" >Contact</a>
</li>
</ul>
The output needs to look like this:
<ul id="top-nav" class="flatList">
<li class="selected">
<a href="#"><span class="embed embed-top-nav">Home</span>
<p >news, highlights</p></a>
</li>
<li>
<a href="#"><span class="embed embed-top-nav">Watch UNC-TV</span>
<p>schedule, local programs</p></a>
</li>
<li id="nav-last">
<a href="#"><span class="embed embed-top-nav">Contact</span>
<p>feedback, connect, share</p></a>
</li>
</ul>
Also note the class added to the active LI tag ("selected") and the class added to the last one in the list ("nav-last"). This is in Joomla 1.5, where I'm overriding the mod_mainmenu module used by the Main Menu. The code uses the SimpleXML library to read and write the HTML in the modMainMenuXMLCallback(&$node, $args):
<?php
defined('_JEXEC') or die('Restricted access');
if ( ! defined('fancyMenuPatch') )
{
function fancyMenuPatch($result,$tag){
// Replace UL tag with ours.
// Replace LI tag with ours.
// Add to the start of the UL tag.
$begin_ul = "<ul id=\"top-nav\" class=\"flatList\">";
$begin_li = "<li>"; //not sure what to do with this.
// do the replacement
$result = str_replace("<ul>",$begin_ul, $result);
$result = str_replace("<li>", $begin_li, $result);
return $result;
}
define('fancyMenuPatch', true);
}
if ( ! defined('modMainMenuXMLCallbackDefined') )
{
function modMainMenuXMLCallback(&$node, $args)
{
$user = &JFactory::getUser();
$menu = &JSite::getMenu();
$active = $menu->getActive();
$path = isset($active) ? array_reverse($active->tree) : null;
if (($args['end']) && ($node->attributes('level') >= $args['end']))
{
$children = $node->children();
foreach ($node->children() as $child)
{
if ($child->name() == 'ul') {
$node->removeChild($child);
}
}
}
if ($node->name() == 'ul') {
foreach ($node->children() as $child)
{
if ($child->attributes('access') > $user->get('aid', 0)) {
$node->removeChild($child);
}
}
}
if (($node->name() == 'li') && isset($node->ul)) {
$node->addAttribute('class', 'parent');
}
if (isset($path) && (in_array($node->attributes('id'), $path) || in_array($node->attributes('rel'), $path)))
{
if ($node->attributes('class')) {
$node->addAttribute('class', $node->attributes('class').' active');
} else {
$node->addAttribute('class', 'active');
}
}
else
{
if (isset($args['children']) && !$args['children'])
{
$children = $node->children();
foreach ($node->children() as $child)
{
if ($child->name() == 'ul') {
$node->removeChild($child);
}
}
}
}
if (($node->name() == 'li') && ($id = $node->attributes('id'))) {
if ($node->attributes('class')) {
$node->addAttribute('class', $node->attributes('class').' item'.$id);
} else {
$node->addAttribute('class', 'item'.$id);
}
}
if (isset($path) && $node->attributes('id') == $path[0]) {
$node->addAttribute('id', 'current');
} else {
$node->removeAttribute('id');
}
$node->removeAttribute('rel');
$node->removeAttribute('level');
$node->removeAttribute('access');
}
define('modMainMenuXMLCallbackDefined', true);
}
ob_start();
modMainMenuHelper::render($params, 'modMyMainMenuXMLCallback');
$menu_html = ob_get_contents();
ob_end_clean();
if($params->get('menutype')=="primarynav"){
$tag = $params->get('tag_id');
}
//output the menu!
echo fancyMenuPatch($menu_html,$tag);
?>
Thank you.
Ok so here is how you want to do this. Jump out of the default.php script you posted above. As Joomla! uses the core mainmenu module for all menus and trees down from that you will need to edit the helper script. This should stick regardless of any 3rd party menu extension you may be using.
rootdirectory/modules/mod_mainmenu/helper.php
Now jump down to the switch statement at line 358. Specifically we want to edit line 363. It looks like this:
$data = ''.$image.$tmp->name.'';
Now edit it to be this:
$data = '<span class="embed embed-top-nav">'.$image.$tmp->name.'</span>';
there you go, now menus utilized by the Joomla! getMenu class will add this span tag around the links.
Note that you may also want to do this to line 375 for links that will open in a new window et cetra. Also note Louis' funny comment " // hrm...this is a bit dickey".
cheers
I am trying to design a dynamic vertical menu :
my table is:
primary // primary key
pid //parent id 0 if none
cid //the actual category id
comment //some comment
the thing is that I want to design a php function where after reading the values from database it should output it into an html ordered list (like a multilevel nested unordered list)
I know that it would be easily achieved by using a recursion function
the problem is that i just can't do it.. I've tried many times but failed in vain
The main problem comes in nesting (where to give list items and where to start the list)
I would be very grateful if anyone of you could help me out...
well i've managed to write an ugly code:
{here i ve used two tables one for the parent and one for the child}
$query="SELECT * FROM parentCat";
$result=mysql_query($query);
echo "<ul id=\"suckertree1\">";
while($row=mysql_fetch_array($result))
{
$name=$row['comment'];
$pid=$row['catid'];
echo "<li> $name ";
$query="select * from childCat WHERE pid=$pid";
$subresult=mysql_query($query);
$af=mysql_num_rows($subresult);
if($af>0)
{
echo "<ul>";
while($subrow=mysql_fetch_array($subresult))
{
$name=$subrow['comment'];
echo "<li> $name </li>";
}
echo "</ul>";
}
echo "</li>";
}
echo "</ul>";
it will show only one sublevel...
wht should i do to make it work for infinite level
I thing a while script is best for you
$query = mysql_query("SELECT * FROM menu ORDER BY primary ASC");
$parent=0;
$sub=0
echo "<ul>";//start list
while($menu = mysql_fetch_array($query){
if($parent != $menu['pid']){//if not seen item before
if($sub != 0){echo "</ul>";}else{$sub++;}//if not first submenu, close submenu before. If first sub sub++.
echo "<ul>";}//open submenu
echo "<li>".$menu[cid]."</li>";//echo item
if($parent != $menu['pid']){//if not seen before
$parent = $menu['pid']; //set to seen before so next loop will be recognised
}
}
echo "</ul>"; //end list
I dont know if this is gonna work since I did not test it, but it should show you an option on how it could be done. Idea of lists:
<ul>
<li>Item1</li>
<ul>
<li>Subitem1</li>
<li>Subitem2</li>
</ul>
<li>Item 2</li>
<ul>
<li>Subitem1 of Item2</li>
</ul>
</ul>
Gives:
Item1
Subitem1
Subitem2
Item2
Subitem1 of Item2
Try this, it should do the trick.
<?php
$query = "SELECT a.comment parent
, b.comment child
FROM menu a
JOIN menu b
ON a.primary = b.pid
ORDER BY a.primary";
$result = mysql_query($query);
$parent = '';
echo "<ul>";
foreach ($result as $next) {
if ($next['parent'] != $parent) {
if (strlen($parent) > 0) {
echo " </ul>";
echo " </li>";
}
echo " <li>" . $next['parent'];
echo " <ul>";
}
echo " <li>" . $next['child'] . "</li>";
$parent = $next['parent'];
}
echo " </ul>";
echo " </li>";
echo "</ul>";
?>
To render a nested list for an assoc array try this:
<?php
$list = array(
'item-1' => 'test-1',
'item-2' => 'test-2',
'item-3' => array(
'item-3-1' => 'test-3',
'item-3-2' => array(
'item-3-2-1' => 'test-4',
'item-3-2-2' => 'test-5',
),
),
'item-4' => 'test-6',
);
function render_list($list) {
echo '<ul>';
foreach ($list as $key => $value) {
echo '<li>';
echo $key.':';
if (is_array($value)) render_list($value);
else echo $value;
echo '</li>';
}
echo '</ul>';
}
render_list($list);
Which will result in this:
<ul>
<li>item-1:test-1</li>
<li>item-2:test-2</li>
<li>
item-3:
<ul>
<li>item-3-1:test-3</li>
<li>
item-3-2:
<ul>
<li>item-3-2-1:test-4</li>
<li>item-3-2-2:test-5</li>
</ul>
</li>
</ul>
</li>
<li>item-4:test-6</li>
</ul>
item-1:test-1
item-2:test-2
item-3:
item-3-1:test-3
item-3-2:
item-3-2-1:test-4
item-3-2-2:test-5
item-4:test-6