Add custom data-attribute to Wordpress navigation menu - wordpress

I've seen some similar questions here on stackoverflow, but mine is a bit different..
I need to be able to add custom data attribute to wordpress menu.
The problem i've got is that all the solutions i found, like the following, for example:
add_filter( 'nav_menu_link_attributes', 'my_nav_menu_attribs', 10, 3 );
function my_nav_menu_attribs( $atts, $item, $args )
{
// The ID of the target menu item
$menu_target = 365;
// inspect $item
if ($item->ID == $menu_target) {
$atts['data-reveal-id'] = 'myModal';
}
return $atts;
}
allows you to add the same attribute to all menu items.
What i need, is actually a way to add the same data attribute, but with different values on each element on the list.
this is pretty much what i need to achive:
<ul id="myMenu">
<li data-menuanchor="firstPage" class="active">First section</li>
<li data-menuanchor="secondPage">Second section</li>
<li data-menuanchor="thirdPage">Third section</li>
<li data-menuanchor="fourthPage">Fourth section</li>
</ul>
because i need to use this plugin here: https://github.com/alvarotrigo/fullPage.js#fullpagejs
any advice?
Thanks

I guess the solution would be to extend the navigation items. I made this before to add icons to menu items.
Take a look over here - instead of a subheadline you cann name the field "anchortarget" (or anything else) and call it in your menu...
http://www.wpexplorer.com/adding-custom-attributes-to-wordpress-menus/
If you need further hints, you should google for "wordpress + menu + custom field".
Hope this helps you. All the best

At the end, I managed to solve this using javascript.
This is what I did:
(function() {
var arrayList, key, val;
arrayList = ['first', 'second', 'third', 'fourth'];
for (key in arrayList) {if (window.CP.shouldStopExecution(1)){break;}
val = arrayList[key];
console.log("key is " + key + " and val is " + val);
$('li').each(function(index) {
if (parseInt(index) === parseInt(key)) {
return $(this).attr('data-anchor', val);
}
});
}
window.CP.exitedLoop(1);
}).call(this);
Create an array with the data you need
Foreach loop to iterate trough the array
Inside that loop, loop trough the menu items
If the menu index is the same as the array index, append the array value as an attribute.
Here's a codepen example as well: http://codepen.io/NickHG/pen/GmKqqE

Ok, too bad, I am sorry. I would post the code I've written for my icons but the code ist like 400 lines with the walker and stuff. But as it seems you're using foundation, you should head over here -> https://www.smashingmagazine.com/2015/10/customize-tree-like-data-structures-wordpress-walker-class/
Even if you don't know about php or wordpress hooks this tutorial will absolutly explain every step needed to code it by hand. It works, I just tested it with my site by copy / pasting it.
If you scroll down, you'll see screenshots - they added an icon field (nearly like i did) how they did it and how they use it. After seeing this tut, honestly, I regret I made it all by myself. It was painfull - this tut just works like a charm....

Related

Wordpress : Create breadcrumb style link using get_post_type_archive_link

I am trying to create a breadcrumb style link back to the archive/feed page for each of my custom post types, for a magazine style website, preferably without having to make a separate template for each post type as there are a few. (I'm also hoping to be able to use the same breadcrumb style link on my main feed in a featured posts kind of way. EG above each H1 of each featured post, so that if somebody clicked fashion instead of the H1 it would take them through to that archive page, as another way of browsing the site as opposed to having to use the top level menu nav.)
Using the following:
$postType = get_post_type_object(get_post_type());
if ($postType) { echo ''; echo esc_html($postType->labels->name); echo ''; }
the_title('', '');
Stackoverflow has stripped the HTML parts from the above code, not sure what I'm doing wrong there
It is correctly pulling and displaying the name of the post type, eg 'Fashion', however the link returned is for the current post, not the feed page.
has_archive and hierarchical are both set to true when creating post type and I've updated permalinks. Anybody have a solution?
So I had a related problem while back and because I despise plugins I decided to make my own breadcrumb.
Instead of going full on php, I went the js road. The breadcrumb is automatically generated based on the user current url. Which is way more efficient than building it the other way around.
Container to add to your theme, wherever:
<ol id="bread"></ol>
Script to enqueue:
var pathname = location.pathname;
if (((bread = []), pathname.endsWith("/"))) var crumbs = pathname.split("/").slice(1, -1);
else crumbs = pathname.split("/").slice(1);
for (crumb = 0; crumb < crumbs.length; crumb++) {
var url = location.href.split(crumbs[crumb])[0];
if (crumbs[crumb].length > 35) var short = crumbs[crumb].replace(/-/g, " ").substring(0, 35) + "[...]";
else short = crumbs[crumb].replace(/-/g, " ");
bread.push('<li style="display:inline;padding:0 5px;">' + short + "</li>");
}
(document.getElementById("bread").innerHTML = bread.join(">")),
(document.getElementById("bread").lastChild.style.pointerEvents = "none"),
(document.getElementById("bread").lastChild.firstElementChild.style.textDecoration = "none"),
(document.getElementById("bread").lastChild.firstElementChild.style.color = "inherit");
The breadcrumb is unstyled beside display:inline;padding:0 5px; which display the list inline and can be easily modified.
You could probably also achieve the same behaviour in php.
The way I achieved with PHP was
$postType = get_post_type_object(get_post_type());
if($postType) {
esc_html($postType->labels->link); echo esc_html($postType->labels->name);
}
I created an extra label within custom post types replicating the slug in order to spit out the URL correctly. I'm not sure why, but when I tried to echo the slug this way I got a critical error.
When originally searching for the answer I found quite a few posts about this, so while I'm not sure its the perfect solution to this problem, I hope this is helpful for anybody else looking.

Make a visible primary link not clickable

On my Drupal site I've got a set of Primary Links. The ones that expand I'd like to make the parent not click able e.g
-home
-about
-history
-website
Only home, history, website should link to a page. If the user clicks on aboutnothing should happen. I've tried searching around the admin panels as well as leaving the field blank but it doesn't seem to be working. I'd assume I'd have to hardcode this? If so, how?
Try this module http://drupal.org/project/special_menu_items
Its probably the simplest way to achieve what you want.
If you can live with it, the easiest solution is to use js to disable clicks.
Adding a yourtheme_menu_item function in template.php seems to be the way to go for this. The documentation for the original function is at http://api.drupal.org/api/function/theme_menu_item
The function passes a $has_children variable and a $menu variable, so it should be pretty easy to adjust Primary Menu items with children as needed.
Some untested example code:
function yourtheme_menu_item($link, $has_children, $menu = '', $in_active_trail = FALSE, $extra_class = NULL) {
// ... original theme code copy-pasted ...
if ($has_children) {
$modified_link_name = youtheme_write_menu_item_without_links($link);
return '<li class="'. $class .'">'. $modified_link_name ."</li>\n";
} else {
// From original function
return '<li class="'. $class .'">'. $link . $menu ."</li>\n";
}
}
You just need to add in the path the phrase <nolink>.
"You just need to add in the path the phrase <nolink>"
i used this before and it worked, but for some reason it didnĀ“t work for a different site that i am using now.
So i tried to write # in the path and worked fine for me.
Hug everybody.

How to hide Edit | View tabs?

Can I hide the
Edit | View
tabs on top of each node ?
I've searched for this option in theme settings (both global and standard theme but I couldn't find it).
I still want to be able my customer to edit / administer content, so I cannot just remove the permission for it.
thanks
here is a very easy solution for you. (Drupal 7)
Open your page.tpl.php in your current template and search for the $tabs variable.
Remove the render code if you want to hide it completely.
If you want to display it only to administrators use this code
<?php if ($tabs and $is_admin): ?>
<div class="tabs">
<?php print render($tabs); ?>
</div>
The above code checks if the user is administrator. If it is it will render the tabs. If not it wont render them.
This really is a presentational thing, not a functionality thing, so it should be done at the theme level.
The problem with overriding theme_menu_local_tasks() is that you override/take a hatchet to the entire local task display, when you really just want to get in there with a scalpel to remove two specific local tasks. So, you need to get a little more specific.
theme_menu_local_tasks() gets the current page's local tasks and passes them to menu_local_tasks(). Here, two theme functions are used:
theme_menu_item_link(), which gets the link markup for the task
theme_menu_local_task(), which gets the <li> element for the task.
So, you can get rid of the View and Edit local tasks in a really robust way by overriding theme_menu_item_link() and theme_menu_local_task() to include your check for them:
function mytheme_menu_item_link($link) {
// Local tasks for view and edit nodes shouldn't be displayed.
if ($link['type'] & MENU_LOCAL_TASK && ($link['path'] === 'node/%/edit' || $link['path'] === 'node/%/view')) {
return '';
}
else {
if (empty($link['localized_options'])) {
$link['localized_options'] = array();
}
return l($link['title'], $link['href'], $link['localized_options']);
}
}
function mytheme_menu_local_task($link, $active = FALSE) {
// Don't return a <li> element if $link is empty
if ($link === '') {
return '';
}
else {
return '<li '. ($active ? 'class="active" ' : '') .'>'. $link ."</li>\n";
}
}
This way, you're relying on the menu router path, not modifying the menu router item, and achieving the result you want with minimal changes to core functionality or theming.
On the module side, you could do something that decouples the Edit's menu entry from the local tasks for the node:
function custom_menu_alter(&$items) {
$items['node/%node/edit']['type'] = MENU_CALLBACK;
}
The edit path is still there, but now it is not associated with the View tab. This includes the edit page itself--no View tab there.
there is a module for that: tab tamer allows to hide or disable tabs and rename them as well.
I use the following in template.php by theme (which is perhaps a little hacky, I feel I should be considering unsetting $tabs instead):
function THEME_NAME_menu_local_tasks() {
return '';
}
Or you could ommit:
if ($tabs) echo $tabs;
from your page.tpl.php...
View and Edit are functional features. They have a reason for being there.
The best way to "remove" them, is to "remove" that functionality alltogether. After all: why remove the interface of a piece of functionality, but not the functionality itself?
Besides, simply not printing the tabs, does not remove the url endpoints. In other words: if you don't print the edit tab, people can still access the edit page.
Again: best is to remove that functionality: The fact that you don't want the edit tab, sounds as if you don't want the edit functionality for certain users.
If so, then just remove that permission for that role. That is all. The tabs will be gone.
If, however, you simply wish to display these tabs differently, Drupal is your friends. As you may have noticed, they are called local tasks and not tabs. That is because the theme decides how to render them: The theme is the thing that decides to show them as tabs.
Simply override the theme_menu_local_tasks() to create your own HTML for the "local-tasks". And in your page-tpl, simply move the $tabs variable around to a place, where you want them.
But again: Don't try to change the behavior of the app, by removing interface-elements. That is not the right thing to do: you should change the behavior, in order to change the behavior :)
For all the people stumbling upon this question while looking for a D7 solution: As stated on https://drupal.stackexchange.com/a/77964/15055 it's hook_menu_local_tasks_alter()
/**
* Implements hook_menu_local_tasks_alter() to unset unwanted tabs
*/
function MYMODULE_menu_local_tasks_alter(&$data) {
foreach ($data['tabs'][0]['output'] as $key => $value) {
if ($value['#link']['path'] == 'node/%/view') {
unset($data['tabs'][0]['output'][$key]);
}
}
}
This is not the answer to the question of what the author asked. But somehow it might be useful for others user who facing the similar problem with me. Please let me know if this is not suitable to put in here.
I get the answer from #grayside and modified a bit to hide the view | edit tab from node based on the content type I want.
function MYMODULE_menu_alter(&$items) {
$items['node/%node/view']['access callback'] = 'MYMODULE_disable_node_view';
$items['node/%node/view']['access arguments'] = array(1);
}
function MYMODULE_disable_node_view($node){
if($node->type == 'product'){
return false;
}
}
product is the machine name of my content type, I don't want anywant to access it including root user.
The simplest solution to hide the tabs is to add this class in your theme css
.tabs{ display:none;}
Thanks for the last answer. But be aware of this detail: if you try it as-is it cannot work: literals should be just rounded with " or ', not both of them altogether. So it should be:
/**
* Implements hook_menu_local_tasks_alter() to unset unwanted tabs
*/
function MYMODULE_menu_local_tasks_alter(&$data) {
foreach ($data['tabs'][0]['output'] as $key => $value) {
if ($value['#link']['path'] == "node/%/view") {
unset($data['tabs'][0]['output'][$key]);
}
}
}
Once taken care of it, it works :)
D8 solution: If you want to hide all "local" tabs on certain pages, remember that "Tabs" is listed in the block library: find it in the "Content" region and exclude by content type, page URL or user role.

Drupal theme preprocess function - primary links

I recently wrote a theme function to add a class to my primary links that works great. I then wrote some css classes to style these links with custom background images. Worked out great. Now comes the problem, the link text for the primary links still is displayed. Normally this isn't a problem as I would just wrap the in a with a custom "hide" class. For example:
<span class="hide">Link Text</span>
So my question is how can I loop through the primary links and wrap the text w/ a <span> like my example? Here's my theme function that I used to add my classes.
function zkc_preprocess_page(&$vars, $hook) {
// Make a shortcut for the primary links variables
$primary_links = $vars['primary_links'];
// Loop thru the menu, adding a new class for CSS selectors
$i = 1;
foreach ($primary_links as $link => $attributes){
// Append the new class to existing classes for each menu item
$class = $attributes['attributes']['class'] . " item-$i";
// Add revised classes back to the primary links temp variable
$primary_links[$link]['$attributes']['class'] = $class;
$i++;
} // end the foreach loop
// reset the variable to contain the new markup
$vars['primary_links'] = $primary_links;
}
Is jQuery an option?
Try something like this:
$(document).ready(function(){
$('#primary li a')
.wrapInner('<span class="hide">' + '</span>');
});
EDIT:
Or if you want to go Drupal, put this guy in your foreach loop:
$link['title'] = '<span class="hide">' . check_plain($link['title']) . '</span>';
If all you want is to hide the link text, why don't you just use something like text-indent: -9999px;?
The correct methods for altering the output of the menu links can be done at the theming layer. You were on the right path with the preprocessing hook use, but there is a little more to it.
Refer to this for more information:
http://drupal.org/node/352924#comment-1189890
http://api.drupal.org/api/function/theme_links/6
Typo?
$primary_links[$link]['$attributes']['class'] = $class;
Should read;
$primary_links[$link]['attributes']['class'] = $class;

fetching only part of a Drupal 6 menu

I'd like to pull out just one section of my navigation menu - a single section of the admin menu structure. I can load the entire navigation menu tree, but I can't see an easy way of pulling out just one segment of it.
Is there an easy way to do this, or do I have to do something hacky?
Have a look at function menu_navigation_links. You pass it a menu name (default = navigation) and a level (default = 0).
Not sure if you'd consider this an easy way, but you could try to grab the whole menu tree via menu_tree_data() or menu_tree_page_data(), find and extract the section you're interested in from the resulting tree structure and render the resulting subtree via menu_tree_output().
EDIT: Stumbled over How to rendering a menu subtree in the meantime - looks like my suggestion could work, but I would definitely not consider this being easy ;)
I found this here which works great for me.
<?php
$menus = menu_tree_page_data(menu_get_active_menu_name()); //get menu tree for active menu
$output='';
foreach($menus as $data) {
if(!empty($data['link']['in_active_trail'])){
$link = theme('menu_item_link', $data['link']);
$extra_class = NULL;
if ($data['below']) {
$output .= theme('menu_item', $link, $data['link']['has_children'], menu_tree_output($data['below']), $data['link']['in_active_trail'], $extra_class);
}
else {
$output .= theme('menu_item', $link, $data['link']['has_children'], '', $data['link']['in_active_trail'], $extra_class);
}
}
}
return theme('menu_tree', $output);
?>
I'm not sure I entirely understand the situation, but you may want to take a look at Menu Block Split which allows you to split levels of navigation into blocks. Here is an excerpt from its project page:
... split any menu block into two different blocks: a first block with the first level menu entries only and a second block with any second level and sub level menu entries. You can have as many splitted blocks as you need.

Resources