I'm trying to build a navigation in php and add an .active class to the <li> element if the page displays. I found this code and it works for the top level elements, i.e. it will apply the .active class to the <li> when the selected page loads.
<?php
$nav = <<<NAV
<nav id="nav">
<ul>
<li>Home</li>
<li>Section 1</li>
<li>Section 2</li>
</ul>
</nav>
NAV;
$lines = explode("\n", $nav);
foreach ($lines as $line) {
$current = false;
preg_match('/href="([^"]+)"/', $line, $url);
if (substr($_SERVER["REQUEST_URI"], 0, 5) == substr(#$url[1], 0, 5)) {
$line = str_replace('<a h', '<a class="active" h', $line);
}
echo $line."\n";
}
?>
However, when I add some child pages to the html these child pages also inherit the .active class even when the parent page is displayed. Likewise, if a child page is displayed the parent also inherits the .active class.
<?php
$nav = <<<NAV
<nav id="nav">
<ul>
<li>Home</li>
<li>Section 1
<ul>
<li>Child Page 1</li>
<li>Child Page 2</li>
</ul>
</li>
<li>Section 2</li>
</ul>
</nav>
NAV;
$lines = explode("\n", $nav);
foreach ($lines as $line) {
$current = false;
preg_match('/href="([^"]+)"/', $line, $url);
if (substr($_SERVER["REQUEST_URI"], 0, 5) == substr(#$url[1], 0, 5)) {
$line = str_replace('<a h', '<a class="active" h', $line);
}
echo $line."\n";
}
?>
Is there a way to adapt the php so only the <li> to the corresponding page inherits the .active class. Also if the .active element was a child then the parent <li> would get a class name like .active-trail?
Alternatively is there a better way to do this via another language like jQuery?
Really appreciate any help on this.
Related
There was a question raised by Log1x about Comparing JSON after foreach loop for a Discord Channel Viewer
This is the link: Comparing JSON after foreach loop In his viewer he wanted to output something like:
<ul>
<li>Channel 1
<ul>
<li>User 1</li>
<li>User 2</li>
</ul>
</li>
<li>Channel 2</li>
<li>Channel 3
<ul>
<li>User 3</li>
</ul>
</li>
</ul>
There was an excellent answer on how to do this, from Mojtaba which was:
$discord = json_decode(file_get_contents('https://discordapp.com/api/servers/'.$id.'/widget.json'));
if ($discord->channels) {
usort($discord->channels, function($a, $b) {
return $a->position > $b->position ? 1 : -1;
});
echo '<ul>';
foreach ($discord->members as $member) {
if (!empty($member->channel_id)) {
$channel_members[$member->channel_id][] = $member->username;
}
}
foreach ($discord->channels as $channel) {
echo "<li>{$channel->name}";
if (!empty($channel_members[$channel->id])) {
echo '<ul>';
foreach ($channel_members[$channel->id] as $username) {
echo "<li>$username</li>";
}
echo '</ul>';
}
echo "</li>";
}
echo '</ul>';
}
I have already completed my viewer but you will be able to see from this screen-shot link that my available space is limited and taken up by too many empty channels. So I am interested to know if there is a way to hide channels that are empty i.e.
<ul>
<li>Channel 1
<ul>
<li>User 1</li>
<li>User 2</li>
</ul>
</li>
<li>Channel 3
<ul>
<li>User 3</li>
</ul>
</li>
</ul>
As I have said, my interest is also for a Discord Channel Viewer , so the above information from both Mojtaba and the first link are directly relevant to my code too.
Thanks in advance.
I think you should be able to just move your <li> tag inside the if.
foreach ($discord->channels as $channel) {
// outside the if, the channel shows even if it's empty
if (!empty($channel_members[$channel->id])) {
// inside the if, you'll only see the channel if it's not empty
echo "<li>{$channel->name}<ul>";
foreach ($channel_members[$channel->id] as $username) {
echo "<li>$username</li>";
}
echo '</ul></li>';
}
}
I'm have an issue with a WordPress theme that I am making using Twitter Bootstrap.
I have two menu's, one of which is a Nav_Walker to which that displays correctly and highlights an active post category if selected, however, the next menu is used to display child pages on the parent page and is using code to do it (See Code). It outputs all the child pages correctly but it doesn't trigger active on the child page menu entry that is being looked at therefor I can't set the active menu item to look any differently.
<?php
if ($post->post_parent)
$children = wp_list_pages("title_li=&child_of=" . $post->post_parent . "&echo=0");
else
$children = wp_list_pages("title_li=&child_of=" . $post->ID . "&echo=0");
if ($children) {
?>
<?php } ?></pre>
<ul class="nav nav-tabs nav-stacked uppercase">
<li class="menu-heading"><h6>OVERVIEW</h6></li>
<?php echo $children; ?>
</ul>
The the code outputs:
<ul class = "nav nav-tabs nav-stacked uppercase">
<li class = "menu-heading"><h6>OVERVIEW</h6></li>
<li class = "">SUB PAGE 1</li>
<li class = "">SUB PAGE 2</li>
<li class = "">SUB PAGE 3</li>
</ul>
The class for the li remains empty when the page is active.
Does anyone know how I can work around this?
Thanks in advance!!
Using the following PHP script to select the page Im currently on.
each page has the variable $page== 'pagename'
This script works fine but sometimes the buttons need to be rolled over twice in order for the dropdown menu to appear.
Is there a better way?
<div id="navigation">
<ul id="nav">
<!-- If the button HOME is selected then make the HOME Button Active -->
<?php if ($page == 'home') { ?><li>HOME</li>
<?php } else { ?><li>HOME<?php } ?>
<!-- If the button ABOUT US is selected then make the ABOUT US Button Active -->
<?php if ($page == 'about-us') { ?><li>ABOUT US
</li>
<?php } else { ?><li>ABOUT US
</li>
<?php } ?>
<!-- If the page projects is selected then make the Projects Button Active -->
<?php if ($page == 'projects') { ?><li>PROJECTS
<ul>
<li>Project 1</li>
<li>Project 2</li>
<li>Project 3</li>
<li>Project 4</li>
</ul>
</li>
<?php } else { ?><li>PROJECTS
<ul>
<li>Project 1</li>
<li>Project 2</li>
<li>Project 3</li>
<li>Project 4</li>
</ul>
</li>
<?php } ?>
<!-- If the page Capabilities is selected then make the Capabilities Button Active -->
<?php if ($page == 'capabilities') { ?><li>CAPABILITIES
<ul>
<li>Civil Works</li>
<li>Commercial Construction</li>
<li>Controlled Waste Management</li>
<li>Plant Hire</li>
</ul>
</li>
<?php } else { ?><li>CAPABILITIES
<ul>
<li>Civil Works</li>
<li>Commercial Construction</li>
<li>Controlled Waste Management</li>
<li>Plant Hire</li>
</ul>
</li>
<?php } ?>
<!-- If the page Careers is selected then make the Careers Button Active -->
<?php if ($page == 'careers') { ?><li>CAREERS</li>
<?php } else { ?><li>CAREERS
</li>
<?php } ?>
<!-- If the page Contact Us is selected then make the Contact Us Button Active -->
<?php if ($page == 'contactus') { ?><li>CONTACT US</li>
<?php } else { ?><li>CONTACT US
</li>
<?php } ?>
</ul>
<!-- Search Form -->
<div class="search-form">
<form method="get" action="#">
<input type="text" class="search-text-box" />
</form>
</div>
</div>
<div class="clear"></div>
</div>
<!-- Navigation / End -->
The second part could be smaller:
<?php if ($page == 'projects') { ?><li>PROJECTS <?php } else { ?> <li>PROJECTS <?php } ?>
<ul>
<li>Project 1</li>
<li>Project 2</li>
<li>Project 3</li>
<li>Project 4</li>
</ul>
</li>
So basically on which page your are on, that should have id="current"? This can be done the following way:
<?php
$selected = array($page => ' id="current"');
?>
...
<li><a href="index.php"<?php print $selected['home']; ?>></li>
<li><a href="about-us.php"<?php print $selected['about-us']; ?>>ABOUT US</a></li>
...
The array $selected will have one index which is the current page and the value will be id="current". So this value will be applied to the active page only.
However this will trigger an undefined index notice, but you won't need any ifs in your code.
If you are okay with a bit more complex structure you could do it like this and won't get notices.
<?php
$selected = array($page => ' id="current"');
?>
...
<li><a href="index.php"<?php print isset($selected['home'])?$selected['home']:''; ?>></li>
<li><a href="about-us.php"<?php print isset($selected['about-us'])?$selected['about-us']:''; ?>>ABOUT US</a></li>
...
Since you are basically doing the same thing over and over again, I'd suggest automating the whole thing anyway.
<?php
$naviPages = array(
array('name' => 'HOME', 'url' => 'index.php'),
array('name' => 'ABOUT US', 'url' => 'about-us.php'),
array('name' => 'PROJECTS' => 'url' => 'projects.php', 'children' => array(
array('name' => 'Project 1', 'url' => 'project-01.php'),
array('name' => 'Project 2', 'url' => 'project-02.php'),
)),
//...
);
//...
foreach ($naviPages as $naviPage) {
print '<li><a href="'.$naviPage['url'].'"';
if ($page == $naviPage['name'])
print ' id="active"';
print '>'.$naviPage['name'].'</a>';
if (isset($naviPage['children'])) {
print '<ul>';
foreach ($naviPage['children'] as $naviPageChild) {
print '<li>'.$naviPageChild['name'].'</li>';
}
print '</ul>';
}
print '</li>';
}
I would tend to stick the $page as a css class in your <body> tag or the navigation div. Then you can do just about everything else in pure css!
So for example, say you have this:
<div id="navigation" class="page-<?php echo $page ?>">
<ul id="nav">
<li class="nav-home">HOME
<li class="nav-about">ABOUT US</li>
Notice how the navigation div has the page name, and each menu item has a unique class name. Now all you have to do is use some CSS:
.page-home .nav-home,
.page-about .nav-about {
color: red; /** assuming you want your active/current menu item to be red **/
}
See how much cleaner that is?
Of course you can then extend this to show/hiding the sub-menus. Give your sub-menu <ul> tag a unique classname:
<li class="nav-projects">PROJECTS
<ul class="submenu sub-projects">
...
</ul>
And some CSS to control that:
.submenu {
display: none; /** Our default **/
}
.page-projects .sub-projects {
display: block; /** Show the projects sub-menu when you are on that page **/
}
I have the following HTML output;
<ul>
<li>Test 1</li>
<li>Test 2.</li>
<li>Test 3</li>
<li>Test 4</li>
<li>Test 5</li>
<li>Test 6</li>
<li>Test 7</li>
</ul>
What I need to do, is display the same HTML, but with only the first 4 <li> tags, i.e.
<ul>
<li>Test 1</li>
<li>Test 2.</li>
<li>Test 3</li>
<li>Test 4</li>
</ul>
Is there an easy way I can do this in PHP?
Thanks
EDIT:
The data is coming from:
$data = $product->getDescription();
It is stored in the DB as the HTML content, I am currently displaying it using the above code;
Thanks
Umm yes..
Depending on where the data is coming from, I am going to assume it is a db of some sort and you have it in an array():
$databasevalue = array(); //stuff from database goes here / dragons
echo "<ul>";
for ( $counter = 0; $counter < 4; $counter ++) {
echo "<li>".$databasevalue[$counter]."</li>";
}
echo "</ul>";
Can't offer more without better question details.
How is data coming from ?
If this data comes from an array you can slice it with array_slice function
$list = array_slice($input, 0, 4);
// $list now only having first 4 item.
<?php
echo '<ul>' . PHP_EOL;
for ($i = 1; $i <= 4; $i++)
{
echo '<li>' . $i . '</li>' . PHP_EOL;
}
echo '<ul>' . PHP_EOL;
?>
Outputs:
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<ul>
Someone else answered with a good one (requires SimpleXMLElement, PHP5) but has been deleted:
<?php
$data = '<ul>
<li>Test 1</li>
<li>Test 2.</li>
<li>Test 3</li>
<li>Test 4</li>
<li>Test 5</li>
<li>Test 6</li>
<li>Test 7</li>
</ul>';
$ul = new SimpleXMLElement($data);
$li = $ul->li;
echo '<ul>'.PHP_EOL;
for($i = 0 ; $i < 4 ; $i++)
{
echo '<li>'.$li[$i].'</li>'.PHP_EOL;
}
echo '</ul>'.PHP_EOL;
?>
if you're using database, you should use "LIMIT" in your SQL, otherwise array_slice will do the job.
don't forget: documentation is your best friend (especially in php)
In Wordpress, I'm looking for some way to add a "last" and a "first" class to list items inside Wordpress widgets. The HTML could look like this:
<div class="widget-area">
<ul >
<li class="widget_recent_comments">
<h3 class="widget-title">Recent comments</h3>
<ul id="recentcomments">
<li class="recentcomments">Comment 1</li>
<li class="recentcomments">Comment 2</li>
<li class="recentcomments">Comment 3</li>
<li class="recentcomments">Comment 4</li>
</ul>
</li>
<li class="widget_my_links">
<h3 class="widget-title">My links</h3>
<ul id="my-links">
<li class="item">Link 1</li>
<li class="item">Link 2</li>
<li class="item">Link 3</li>
<li class="item">Link 4</li>
<li class="item">Link 5</li>
</ul>
</li>
</ul></div>
In this example above i'd like to have first/last classes added to the li with "Comment 1", "Comment 4", "Link 1" and "Link 5".
Is there an easy workaround for this? (I don't want to do this with javascript)
Thank you.
I'm guessing these lists are generated in a loop. So what you could do, is create a variable before you go into the loop, and set it's value to 1 ($i = 1). Than at the end of the loop, add one up ($i++). Now, where you want the first/last class to appear, you can do
<?php if($i == 1):
echo ' first';
elseif( $i == $number_of_items )
echo 'last';
endif;
?>
At $i == $number_of_items, you are comparing the max with the current, so you know you have the last if the statement is true.
Hope this answers your question.
Well the first-item is easy, just use
ul#my-list li:first-child {
/* special styles */
}
It's not adding a class, but you can still style it. There is not a similar css rule for :last-child unfortunately