I have a counter of menu items, that basically add incremental value as a class to a menu system:
<?php
if ($element['#original_link']['depth'] == 1) {
static $counter = 0;
$counter++;
$class = 'count-' . $counter;
}
$output = 'some output code build';
return '<li class="' . $class . '">' .$output .'</li>';
?>
Note, the code is inside each menu item (outside a loop or array). The code will simply output the lists of unordered list, without UL:
<li class="count-1">One</li>
<li class="count-2">Two</li>, ...etc.
This works fine until I change the source of menus.
1). One is using the system menu of my CMS,
2). the latter is using a block output of that system menu,
and both output similar construct of menus, except for the fact that the latter continues the counter from the #1 rather than a reset from a 1 (although #1 is not activated once #2 takes over the place). I haven't figured out why, but it seems that #2 is a continuance of #1. While I expect each should start an increment from 1.
I can not use a reset here. Is there anything obvious I missed that PHP can handle here, apart from the the way of my CMS do to the counters?
Any pointer would be very much appreciated. Thanks
UPDATE, actual codes in use:
function mytheme_menu_link(array $variables) {
//dpm($variables);
$element = $variables['element'];
$sub_menu = '';
if ($element['#below']) {
$sub_menu = drupal_render($element['#below']);
}
if ($element['#original_link']['menu_name'] == variable_get('menu_main_links_source', 'main-menu')) {
if ($element['#original_link']['depth'] == 1) {
static $counter = 0;
$counter++;
$element['#attributes']['class'][] = 'count-' . $counter;
}
}
$output = l($element['#title'], $element['#href'], $element['#localized_options']);
return '<li' . drupal_attributes($element['#attributes']) . '>' . $output . $sub_menu . "</li>\n";
}
/**
* Implements theme_menu_tree()
No helpful variables, except for a flattened render of tree
*/
function mytheme_menu_tree__main_menu($variables) {
return '<ul class="menu">' . $variables['tree'] . '</ul>';
}
When using static variables, the values of the variable will not be reset between subsequent executions of the same code. That's the express purpose of static. Get rid of it if you do not want that behavior.
Related
I have a case where I am using the code below to populate a template of sorts. Within the templates' javascript I would individually check the data attribute field I setup, essentially causing me to have multiple JS files instead of one that is shared. I then thought I could use a generic name field too, but prepend a number through the loop.
For example, with the line of code below where the `name="testField". I want to see if there is a way that I can add a number, but auto increment it through the loop with php.
Is this possible?
echo '<div class="markerItem" name="testField' . $number . '" "data-marker="' . $marker_data . '">';
PHP Code
if ($marker_stmt = $con->prepare($sql_marker)) {
$marker_stmt->execute();
$marker_rows = $marker_stmt->fetchAll(PDO::FETCH_ASSOC);
echo '<div id="projMarker">';
foreach ($marker_rows as $marker_row) {
$marker_solution = $marker_row['solution'];
$maker_item = $marker_row['subSolution'];
$marker_data = $marker_row['subSolution'];
echo '<div class="markerItem" data-marker="' . $marker_data . '">';
echo $marker_item;
echo '</div>';
}
}
echo '</div>';
if ($marker_stmt = $con->prepare($sql_marker)) {
$marker_stmt->execute();
$marker_rows = $marker_stmt->fetchAll(PDO::FETCH_ASSOC);
echo '<div id="projMarker">';
foreach ($marker_rows as $key=>$marker_row) {
$marker_solution = $marker_row['solution'];
$maker_item = $marker_row['subSolution'];
$marker_data = $marker_row['subSolution'];
echo '<div class="markerItem" name="testField_'.$key.'" data-marker="' . $marker_data . '">';
echo $marker_item;
echo '</div>';
}
}
echo '</div>';
Using this, $key is assigned from the array index which will be a number starting from 0 and ending at count($marker_rows)-1.
Suprisingly, I couldn't find an appropriate duplicate for this.
You can easily increment or decrement variables in PHP.
$number = 0;
foreach ($marker_rows as $marker_row) {
...
$number++; // $number will now be $number+1
}
You can use $number++ directly in your attribute (if concatenating) as this will return the current $number then increment the value.
Okay, my script is supposed to open an XML file, recursively loop through all the tags, children, children of children, and so forth spitting out information as we go. Today I noticed an interesting bug in that my foreach loop that is supposed to loop through the children is skipping directly to the last child and I really have no clue as to why.
function theHunt($node)
{
$tagName = '';
print 'I am starting with ' . $node->getName() . ' It should have ' . $node->count() . ' children. The first child should be: ' . $node->children()->getName() . '<br>';
foreach ($node->children() as $child);
{
print $child->getName() . '<br>';
if (isset($child))
{
print 'I found: ' . $child->getName() . ' I\'ll see if it has kids' . '<br>';
$this->theHunt($child);
}
else
{
print 'No kids here, I\'m going to stop digging.<br>';
}
//Now that I am all the way down or working my way back up. I start gathering my information.
$tagName = $node -> getName();
if($this->rootNode->$tagName[0] !== NULL)
{
foreach ($this->rootNode->$tagName[0]->attributes() as $a => $b) ;
{
//echo $a, '="', $b, "<br>";
}
}
//print_r($node);
print'<br> I kicked out <br>';
}
}
The really weird part is that the line:
print 'I am starting with ' . $node->getName() . ' It should have ' . $node->count() . ' children. The first child should be: ' . $node->children()->getName() . '<br>';
Is outputting all the correct information, but the moment I drop into the foreach loop I skip right to the very last child.
Your code is mishandling the tree structure. You should follow the structure below:
function theHunt($node)
{
foreach ($node->children() as $child);
{
if (isset($child))
{ //has children
theHunt($child); //go one level down
}
else
{ //this is a child
//enum thru its attributes
}
}
}
Okay, I figured it out. Really rookie mistake. I put a semicolon after my foreach. Took it out, I'm running beautifully.
I am trying to program a Flat File PHP Dictionary (English -> Spanish).
I've got this up to now:
<?php
$data =
'car;coche
cat;gato
fat;gordo
far;lejos';
if($data) {
$line = explode("\n", $data);
for($i = 0; $i<count($line); $i++) {
$item = explode(";", $line[$i]);
if($_GET['word'] == $item[0]) { echo"<div>" . $item[0] . "</div> <div>" . $item[1] . "</div>"; }
else {echo MAIN PAGE;}
}
}
?>
It is perfect because it opens a loop of pages in one php file:
e.g. http://localhost/?word=fat prints "Fat Gordo"
My problem is when creating the main page http://localhost. I tried with else{ echo "MAIN PAGE";} but, wherever I place it, it prints "MAIN PAGEMAIN PAGEMAIN PAGE".
Any help?
that's because you are looping through every line in $data. Whatever the outcome of the if expression is, after that it just goes on to the next iteration and runs the if statement again.
So if you add the } else { echo "mainpage" to your if, it will echo mainpage everytime when $_GET['word'] doesn't match $item[0] (which obviously at every line if $_GET['word'] is not defined)
To avoid this you can add something like this:
if($data && !empty($_GET['word'])) {
(...)
} else {
echo "mainpage";
}
If you have a big dictionary it's also good to break you loop once you have found a matching word:
if($_GET['word'] == $item[0]) {
echo "<div>" . $item[0] . "</div> <div>" . $item[1] . "</div>";
break;
}
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Walk array recursively and print the path of the walk
Anyone can help me on this code?
<?php
function buildMenuWalk(&$array, &$depth, $currentDepth = 1)
{
# start new level html
$html = '';
# walk till the depth defined on the config
if($currentDepth > $depth)
{
return null;
}
# loop through all items in this level
foreach($array as $key => &$value)
{
# if not in area map continue
if(!is_numeric($key))
{
continue;
}
# if no <li> has been created yet, open the <ul>
$html .= empty( $html ) ? '<ul class="dropdown">' : '';
#extract the label from this level's array, designated by $labelKey
$label = isset( $value['areaname'] ) ? $value['areaname'] : '';
# open an <li>
$html .= '<li>';
# generate url
$url = '';
if($currentDepth == $depth)
{
$url = ' href="'.
$url .= '"';
}
# construct content inside the <li>
$html .= '<a' . $url .'>' . $label . '</a>';
# run the function again to grab children levels
if(is_array($value))
{
$html .= buildMenuWalk($value, $depth, $currentDepth + 1);
}
# close <li>
$html .= '</li>';
}
# close <ul> if was generated content on this level
$html .= !empty( $html ) ? '</ul>' : '';
return $html;
}
$depth = 2;
$config['content']['map'][1]['areaname'] = 'area_1';
$config['content']['map'][1][1]['areaname'] = 'block_1';
$config['content']['map'][2]['areaname'] = 'area_2';
$config['content']['map'][2][1]['areaname'] = 'block_1';
$config['content']['map'][2][2]['areaname'] = 'bloack_2';
echo buildMenuWalk($config['content']['map'], $depth);
?>
If you check the code above, Im using to display a menu recursively ...
If the script identify the menu reached the depth, will display href="" inside the tag. Inside this href I want add all parent areas on the recursion.
For example:
$config['content']['map'][2]['areaname'] = 'area_2';
$config['content']['map'][2][1]['areaname'] = 'block_1';
$config['content']['map'][2][2]['areaname'] = 'bloack_2';
When script reaches the bloack_2, I need display:
<a href="area_2=2&block_2=2">
Since its a multidimensional array and can grow to like 4-5 dimension, the output href should count all these levels. For example area_2=1&block_10=5&sub_area_1=5§ion_7=8 ...
I probably need some array to store all href path during the recursion, but I cant figure how to do it.
Thanks,
PS: The script will be used to build a dropdown menu. The parent levels don't need to be linked, so print the tag will display the child menu. The last child, will be linked, but need contain all parent params so the results can be filtered.
Link to the code running and returning values:
http://codepad.org/iyrcdfQP
Here is a modification of that same slice of code that makes the href= a little more like what you are describing, although it doesn't really make sense to me.
# generate url
$url = '';
if($currentDepth == $depth) {
$url = " href=".$GLOBALS['area_name']."=".$GLOBALS['area']."&$label=$key";
}
else {
$GLOBALS['area'] = $key;
$GLOBALS['area_name'] = $label;
}
I don't see why one would bother with recursoin and multiple dimensions in a world of 2 dimensions as the menu in a web page is!
I would go for 2 dimensions only, the first dimension is to keep all elements (without any criteria) and the second to keep infos about the element:
Check an example for yourself, you set which element to get the function displays it along with all ancestors and root elements of previous levels (as California is).
<?php
function buildMenuWalk($element,$menuElements)
{
for($i=0;$i<=$element;$i++)
{
//for a new level go to the next line
if(!isset($menuElements[$i]['ancestors']))
{
echo '<br>______________________________________</br>';
echo '<strong>',$menuElements[$i]['label'],'</strong> | ';
}
//if the element is reached display it along with ancestors
if($i==$element)
{
//echo all the ancestores
foreach($menuElements[$element]['ancestors'] as $value)
{
echo $menuElements[$value]['label'],' | ';
}
//display the element itself
echo '<font color=red>',$menuElements[$element]['label'],' | </font>';
}
}
}
//California
$menuElements[0]=Array('url'=>'http://www.California.com','label'=>'California');
$menuElements[1]=Array('url'=>'http://www.San Diego.com','label'=>'San Diego','ancestors'=>Array(0));
$menuElements[2]=Array('url'=>'http://www.San Jose.com','label'=>'San Jose','ancestors'=>Array(0,1));
$menuElements[3]=Array('url'=>'http://www.San Francisco.com','label'=>'San Francisco','ancestors'=>Array(0,1,2));
$menuElements[4]=Array('url'=>'http://www.Fresno.com','label'=>'San Francisco','ancestors'=>Array(0,1,2,3));
$menuElements[5]=Array('url'=>'http://www.Sacramento.com','label'=>'Sacramento','ancestors'=>Array(0,1,2,3,4));
//Wyoming
$menuElements[6]=Array('url'=>'http://www.Wyoming.com','label'=>'Wyoming');
$menuElements[7]=Array('url'=>'http://www.Cheyenne.com','label'=>'Cheyenne','ancestors'=>Array(6));
$menuElements[8]=Array('url'=>'http://www.Casper.com','label'=>'Casper','ancestors'=>Array(6,7));
$menuElements[9]=Array('url'=>'http://www.Laramie.com','label'=>'Laramie','ancestors'=>Array(6,7,8));
$menuElements[10]=Array('url'=>'http://www.Gillette.com','label'=>'Gillette','ancestors'=>Array(6,7,8,9));
$menuElements[11]=Array('url'=>'http://www.Rock Springs.com','label'=>'Rock Springs','ancestors'=>Array(6,7,8,9,10));
echo '<pre>';
buildMenuWalk(9,$menuElements);
?>
Since this function is recursively calling itself, you'll have to refer to a global variable to keep track of the previous tree. So here is the code that'll do what I think you want it to do. All of you have to change is the #generate url section.
# generate url
$url = '';
if($currentDepth == $depth) {
$url = " href=area=" . $GLOBALS['area'] . "&block=$key";
} else {
$GLOBALS['area'] = $key;
}
I am trying to add drop down menus to a drupal theme which uses text sliding door CSS rounding.
The current version uses a primary links injection of the span into the a tags, which works fine. But doesn't support drop down menus.
Working code:
<?php print theme('links', $primary_links, array('class' => 'links primary-links')) ?>
In the template with a template.php file addition:
<?php
// function for injecting spans inside anchors which we need for the theme's rounded corner background images
function strands_guybrush_links($links, $attributes = array('class' => 'links')) {
$output = '';
if (count($links) > 0) {
$output = '<ul'. drupal_attributes($attributes) .'>';
$num_links = count($links);
$i = 1;
foreach ($links as $key => $link) {
$class = $key;
// Add first, last and active classes to the list of links to help out themers.
if ($i == 1) {
$class .= ' first';
}
if ($i == $num_links) {
$class .= ' last';
}
if (isset($link['href']) && ($link['href'] == $_GET['q'] || ($link['href'] == '<front>' && drupal_is_front_page()))) {
$class .= ' active';
}
$output .= '<li'. drupal_attributes(array('class' => $class)) .'>';
if (isset($link['href'])) {
$link['title'] = '<span class="link">' . check_plain($link['title']) . '</span>';
$link['html'] = TRUE;
// Pass in $link as $options, they share the same keys.
$output .= l($link['title'], $link['href'], $link);
}
else if (!empty($link['title'])) {
// Some links are actually not links, but we wrap these in <span> for adding title and class attributes
if (empty($link['html'])) {
$link['title'] = check_plain($link['title']);
}
$span_attributes = '';
if (isset($link['attributes'])) {
$span_attributes = drupal_attributes($link['attributes']);
}
$output .= '<span'. $span_attributes .'>'. $link['title'] .'</span>';
}
$i++;
$output .= "</li>\n";
}
$output .= '</ul>';
}
return $output;
}
?>
So I have added the Nice Menu module which works well and allows the drop down menu functions for my navigation which is now addressed from the template using:
<?php print theme_nice_menu_primary_links() ?>
The issue is that the a tags need to have spans inside to allow for the selected state markup. I have tried every angle I could find to edit the drupal function menu_item_link which is used by nice menus to build the links.
E.g. I looked at the drupal forum for two days and no joy.
The lines in the module that build the links are:
function theme_nice_menu_build($menu) {
$output = '';
// Find the active trail and pull out the menus ids.
menu_set_active_menu_name('primary-links');
$trail = menu_get_active_trail('primary-links');
foreach ($trail as $item) {
$trail_ids[] = $item['mlid'];
}
foreach ($menu as $menu_item) {
$mlid = $menu_item['link']['mlid'];
// Check to see if it is a visible menu item.
if ($menu_item['link']['hidden'] == 0) {
// Build class name based on menu path
// e.g. to give each menu item individual style.
// Strip funny symbols.
$clean_path = str_replace(array('http://', '<', '>', '&', '=', '?', ':'), '', $menu_item['link']['href']);
// Convert slashes to dashes.
$clean_path = str_replace('/', '-', $clean_path);
$class = 'menu-path-'. $clean_path;
$class .= in_array($mlid, $trail_ids) ? ' active' : '';
// If it has children build a nice little tree under it.
if ((!empty($menu_item['link']['has_children'])) && (!empty($menu_item['below']))) {
// Keep passing children into the function 'til we get them all.
$children = theme('nice_menu_build', $menu_item['below']);
// Set the class to parent only of children are displayed.
$class .= $children ? ' menuparent ' : '';
// Add an expanded class for items in the menu trail.
$output .= '<li id="menu-'. $mlid .'" class="'. $class .'">'. theme('menu_item_link', $menu_item['link']);
// Build the child UL only if children are displayed for the user.
if ($children) {
$output .= '<ul>';
$output .= $children;
$output .= "</ul>\n";
}
$output .= "</li>\n";
}
else {
$output .= '<li id="menu-'. $mlid .'" class="'. $class .'">'. theme('menu_item_link', $menu_item['link']) .'</li>'."\n";
}
}
}
return $output;
}
As you can see the $output uses menu_item_link to parse the array into links and to added the class of active to the selected navigation link.
The question is how do I add a span inside the a tags OR how do I wrap the a tags with a span that has the active class to style the sliding door links?
If you want to wrap the a tags with a span, you can overwrite the theme_nice_menu_build and add your span to the output. If you want to inside the a tag you need to overwrite the menu_item_link.
You can overwrite a theme funciton by creation a function call your_theme_name_function_name and Drupal will use that function to render the markup instead of the default one. That way you can alter the markup any way you want. This function should be in your theme's template.php file.
A good way to start is to copy the function you want to overwrite and just alter to your likings.
A lot has happened since Drupal 4.7, I don't hope you use that. It's quite easy to insert span tags:
function your_theme_name_menu_item_link($link) {
if (empty($link['localized_options'])) {
$link['localized_options'] = array();
}
$link['localized_options']['html'] = TRUE;
return l('<span>' . $link['title'] . '</span>', $link['href'], $link['localized_options']);
}
I tested this and it works just fine.