I'm very new in Drupal 8 and I have issue now with hook. Mainly I though that I don't clearly understand structure and hook definition in Drupal 8.
So my main problem is that I have some hook to interact with main menu (add custom class name to ul, li and link, a tag). I can do it by changing template file and now try to do it with any hook.
Although I found that some hook relating to menu ex. hook_contextual_links_alter (link: https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Menu%21menu.api.php/function/hook_contextual_links_alter/8.9.x).
At the end of this hook we have the code related:
function hook_contextual_links_alter(array &$links, $group, array $route_parameters) {
if ($group == 'menu') {
// Dynamically use the menu name for the title of the menu_edit contextual
// link.
$menu = \Drupal::entityTypeManager()
->getStorage('menu')
->load($route_parameters['menu']);
$links['menu_edit']['title'] = t('Edit menu: #label', [
'#label' => $menu
->label(),
]);
}
}
So I have installed devel module with kint function and in my .theme file and try:
function hook_contextual_links_alter(array &$links, $group, array $route_parameters) {
kint($links);
}
and then reload my Home page but nothing showed. But I can get some information about other like:
function eg_learn_theme_suggestions_page_alter(&$suggestions, $variables) {
kint($suggestions);
}
So what happens here? Can you help to explain if how I can print the variable of this hook (in .theme file) and the site page to see the printing variable?
In general when I found a hook, how I can print there array and check it in website?
There are some problems about your approach:
When implementing a hook, you must replace "hook" with the module name/theme name where you put the hook function inside. For example, if you want implement hook_contextual_links_alter in your_custom module, it becomes your_custom_contextual_links_alter().
Not all hook can be implemented in the theme. Some hook can only be implemented in modules (in .module file). You can read more here.
In your case, I think hook_preprocess_menu would be more suitable. You can implement it in your custom theme like this:
function <your_theme_name>_preprocess_menu(&$variables) {
if ($variables['menu_name'] == 'main') {
kint($variables);
}
}
Related
I am making a plugin which adds a bunch of pages to the admin view of WP. I'd really like to use Timber, specifically, the Twig templating functionality to render these pages.
While I have next to zero experience in WP and PHP in general, what attracts me to this approach is my previous familiarity with Django / Flask templates which allow me to extend a base template and specify blocks for header, content, footer. That seems trivial to do with Timber when using it to create a theme, but I can't for the life of me figure out how to make this setup work within a plugin. Sure, I can do something like this:
add_action( 'admin_menu', 'test_setup_menu' );
function test_setup_menu() {
add_menu_page(
'Tables',
'Tables',
'manage_options',
'test-tables',
'admin_page_test'
);
}
function admin_page_test() {
Timber::Render( 'test.twig');
}
But that of course will render test.twig with header and footer parts already populated from the theme. The issue specifically is that I want to be able to add information to the header or footer blocks. I know I can do this like so:
add_action('admin_head', 'add_to_head')
function add_to_head() {
...
}
But this is precisely the type of thing I'm trying to avoid, I wish to encapsulate this type of logic in a Twig template. Is there any way to make this work?
Here's an example of how to add a custom admin page for a plugin.
<?php
/**
* Plugin Name: Test Run
*/
add_action('admin_menu', 'admin_menu_cb');
function admin_menu_cb()
{
// Ref: https://developer.wordpress.org/reference/functions/add_menu_page/
add_menu_page('Test Run Admin Page', 'Test Run', 'manage_options', 'test-run', 'render_menu_page_cb', 'dashicons-schedule', 3);
}
function render_menu_page_cb()
{
Timber::$locations = __DIR__.'/views';
$data = [];
Timber::render('main.twig', $data);
}
For a more full example please see the below repo. I created it recently as a guide for anyone to use Timber in a wordpress plugin.
https://github.com/chanakasan/a-wordpress-plugin-using-timber
I'm creating a new wordpress plugin, which only be displayed in posts, but to detect it's a post, I'm trying to use is_single(), but it does not work.
class myplugin{
//my plugin code here
}
function load_plugin($plugin_class, $priority = 10) {
if (class_exists($plugin_class)) {
add_action("init",
create_function('', "global \$$plugin_class; \$$plugin_class = new $plugin_class();"),
$priority);
}
}
if(is_single()){ // witout this, the plugin is displayed everywhere, but whit it it's not displayed at all
load_plugin(myplugin);
}
I even tried to see the output of is_single
echo"<script>alert('".is_single()."');</script>";
i get "undefined"
edit // witout the is_single and just loading my plugin, my plugin works on every page of wordpress.
Conditional tags, like is_single, are not available until the the wp hook has fired. You're trying to use it too early, which is why it returns undefined.
Add your function to a hook after that and do the is_single test there. There is very little overhead in this so don't worry about performance issues.
[For Drupal 6] Let's say I've created a content type called "my_content_type". I can override the default template for that entire content-type by creating "page-node-my_content_type.tpl.php". But, what would be the best way to then further customize a single node of that content type (e.g., node 5555)?
I tried the following, but none worked:
page-node-5555.tpl.php
page-node-my_content_theme-5555.tpl.php
node-5555.tpl.php
None of these work. They all continue to use my original content-type template.
Drupal's page templates work on a suggestion system. Based on the current URL, an array of possible template files is created. It loops through the array (in reverse order) looking for template files that exists. The first one it finds, it will use.
drupal's theme system provides a hook for you to modify the template suggestions.. open up your template.php and find
function phptemplate_preprocess_page(&$vars) {
the $vars variable is what contains the suggestions, specifically $vars['template_files']
By default the only page suggestions that are available are
page.tpl.php
page-node.tpl.php
page-node-[node_id].tpl.php
As far as im aware, page-node-[node_type].tpl.php does not work by default, so its likely you have already modified the preprocess_page template to added in this functionality.
However if you want to add more specific templates you could do something like this...
function phptemplate_preprocess_page(&$variables) {
if ($variables['node']->type != "") {
$variables['template_files'][] = "page-node-" . $variables['node']->type;
$variables['template_files'][] = "page-node-" . $variables['node']->type . "-" . $variables['node']->nid;
}
}
this will allow the following hierarchy of template suggestions
page.tpl.php
page-node.tpl.php
page-node-[node_id].tpl.php
page-node-[node_type].tpl.php
page-node-[node_type]-[node_id].tpl.php
In Drupal 7 just copy the page.tpl.php template and rename it as
page--node--[node:id].tpl.php
Clear cache and start tweaking..
function phptemplate_preprocess_page(&$variables) {
if ($variables['node']->type != "") {
$variables['template_files'][] = "page-node-" . $variables['node']->type;
$variables['template_files'][] = "page-node-" . $variables['node']->type . "-" . $variables['node']->nid;
}
}
This code should not work because hook_preprocess_page() does not get passed any node information. hook_preprocess_node() does. So you can easily create a custom node.tpl, but you cannot easily create a custom page.tpl for a specific node. Not that I've been able to figure out anyway :)
Later...
In default Drupal, page-node-NID.tpl.php will work with no special coding. On a site of mine, it wasn't working, however, and I used the following code to make it work:
/**
* Implementation of hook_preprocess_page().
*/
function MYMODULE_preprocess_page(&$variables) {
// Allow per-node theming of page.tpl
if (arg(0) == 'node' && is_numeric(arg(1))) {
$variables['template_files'][] = "page-node-" . arg(1);
}
}
I'm currently coding a WP plugin and would need to override templates.
My filter hook looks like that - and it executes:
add_filter('template_include', 'mcd_set_template',10);
function mcd_set_template() just returns the required path as string - or the default WP template in case the file not exists.
I'm toying with this for hours already, even could include that alternate template (but it appears at the bottom of the page).
So my question is, how to force WP 3.2.1 to just load another template file instead - and which priority is required??
Update:
Also I noticed when using var_dump ... it outputs almost at the end of the file - but should appear before the opening HTML tag...
According to this ticket it should work with template_include hook: http://core.trac.wordpress.org/ticket/11242
Or is the only way to hook these filters instead:
http://codex.wordpress.org/Template_Hierarchy#Filter_Hierarchy
?
You could use template_redirect as shown above, but that does require exit, and it does trample on everything else WordPress would normally do to find the current template. You may want to let that happen and then apply logic to the current template.
Using some of what is above...
add_action('template_include', 'mcd_set_template');
function mcd_set_template() {
return locate_template('templatename.php');
}
That is fairly simple, you can also pass an array to locate_template() to define a hierarchy. If you were to use 'template_redirect as shown above, you should still be using locate_template, and this is how.
add_action('template_redirect', 'mcd_set_template');
function mcd_set_template() {
/**
* Order of templates in this array reflect their hierarchy.
* You'll want to have fallbacks like index.php in case yours is not found.
*/
$templates = array('templatename.php', 'othertemplate.php', 'index.php');
/**
* The first param will be prefixed to '_template' to create a filter
* The second will be passed to locate_template and loaded.
*/
include( get_query_template('mcd', $templates) );
exit;
}
Finally, the best way would be to filter specific types instead of the whole hierarchy. For example you could filter 'category_template' or 'page_template'. That would be more specific, it would avoid messing with the whole template hierarchy if you don't want to - and it lets WordPress do more of the heavy lifting
For example:
add_filter('category_template', 'filter_category_template');
function filter_category_template($template){
/* Get current category */
$category = get_queried_object();
/* Create hierarchical list of desired templates */
$templates = array (
'category.php',
'custom-category-template.php',
'category-{$category->slug}.php',
'category-{$category->term_id}.php',
'index.php'
);
return locate_template($templates);
}
You can of course create that array of hierarchical templates any time you use locate_template(). Using this method, its easy to see how easily you could create all sorts of very detailed and specific hierarchies either as part of or separate from the native Template Hierarchy.
Have you tried using an add_action instead? For example, you might want to try something like the following in your plugin:
add_action('template_redirect', 'mcd_set_template');
//Redirect to a preferred template.
function mcd_set_template() {
$template_path = TEMPLATEPATH . '/' . "templatename.php";
if(file_exists($template_path)){
include($template_path);
exit;
}
}
Here is a helpful reference: http://www.mihaivalentin.com/wordpress-tutorial-load-the-template-you-want-with-template_redirect/
i'm on Drupal 7 and i have aspecific tpl.php file for a content field_image: "field--field_image.tpl.php". I need to create a preprocess function for this field and for my theme.
Supposing my theme name is "My Theme"
It should look like
function my_theme_preprocess_field(&$variables, $hook) {
$variables['classes_array'][] = 'aClassName';
}
but it doesn't work. I am wrong. But where?
Thanks
You can use template_preprocess_field() (like you do in your code above) but just test the particular field is the right one for you:
function my_theme_preprocess_field(&$variables, $hook) {
$element = $variables['element'];
if (isset($element['#field_name'])) {
if ($element['#field_name'] == 'field_image') {
$variables['classes_array'][] = 'aClassName';
}
}
}
Once you've implemented the hook don't forget to clear your caches, hook implementations are cached in Drupal 7 so won't be picked up until the cache is cleared.
You could declare a mytheme_preprocess_field(&$variables, $hook) in your theme's template.php where you can check your field and do operations on its label or markup, add classes, anything. So you wouldn't need field specific tpls. - eg.
function mytheme_preprocess_field(&$variables, $hook) {
if ($variables['element']['#field_name'] == 'field_machine_name') {
$variables['items'][0]['#markup'] = 'add custom markup';
}
}
Hope this helps someone.
In drupal 7 you can rewrite output of the field in template_preprocess_node() by altering "#markup" value of the field.
Also you can use regexp to change whatever you want in page content :)