I'm very beginner with Timber.
I want to redo (reproduce) one of my wordpress themes with Timber.
I try to call a theme_mod in my template but nothing is showing up.
Any answer or advise would be appréciate.
My original wp header.php
//***********************************Phone******************************************************//
$idbbase_very_top_header_phone = get_theme_mod( 'idbbase_very_top_header_phone', esc_html__( '(+9) 0999.500.400', 'idweb' ) );
$idbbase_very_top_header_phone = apply_filters( 'idbbase_translate_single_string', $idbbase_very_top_header_phone, 'Very Top Header' );
$idbbase_very_top_header_phone_text = get_theme_mod( 'idbbase_very_top_header_phone_text', esc_html__( 'Call us: ', 'idweb' ) );
$idbbase_very_top_header_phone_text = apply_filters( 'idbbase_translate_single_string', $idbbase_very_top_header_phone_text, 'Very Top Header' );
if ( ! empty( $idbbase_very_top_header_phone ) || ! empty( $idbbase_very_top_header_phone_text ) ) {
echo '<div class='.$class.'><i class="fa fa-phone"></i>';
echo '<span><strong class="idbbase_very_top_header_phone_text">';
echo $idbbase_very_top_header_phone_text.'</strong>';
echo '<p class="idbbase_very_top">' .wp_kses( $idbbase_very_top_header_phone, 'post', $allowed_protocols ) . '</p></span>';
echo '</div>';
} elseif ( isset( $wp_customize ) ) {
echo '<div id="idbbase_very_top_header_phone" class="idbbase_only_customizer '.$class.'"><span><strong>'.$idbbase_very_top_header_phone_text.'</strong><p class="idbbase_very_top_header_phone_text">' .wp_kses( $idbbase_very_top_header_phone, 'post', $allowed_protocols ) . '</p></span></div>';
}
My Timber header.php
//*************Phone******************************************************//
$idagency_very_top_header_phone = get_theme_mod(
'idagency_very_top_header_phone', esc_html__( '(+9) 0999.500.400', 'idweb' )
);
$idagency_very_top_header_phone2 = apply_filters(
'idagency_translate_single_string', $idagency_very_top_header_phone, 'Very
Top Header' );
$idagency_very_top_header_phone_text = get_theme_mod(
'idagency_very_top_header_phone_text', esc_html__( 'Call us: ', 'idweb' ) );
$idagency_very_top_header_phone_text2 = apply_filters(
'idagency_translate_single_string', $idagency_very_top_header_phone_text,
'Very Top Header' );
$context['idagency_very_top_header_phone'] =
$idagency_very_top_header_phone;
$context['idagency_very_top_header_phone'] =
$idagency_very_top_header_phone2;
$context['idagency_very_top_header_phone_text'] =
$idagency_very_top_header_phone_text;
$context['idagency_very_top_header_phone_text'] =
$idagency_very_top_header_phone_text2;
$GLOBALS['timberContext'] = Timber::get_context();
ob_start();
Timber::render( 'base.twig', $context );
My base.twig
{% if idbbase_very_top_header_phone %}
<div class="col-md-3">
<a href="#">
<i class="fa fa-phone"></i>
</a>
<span>
<strong>{{ idbbase_very_top_header_phone_text }}</strong>
<p>{{ idbbase_very_top_header_phone }}</p>
</span>
</div>
{% endif %}
Timber's philosophy of separating data from markup requires a significant conceptual shift when compared to the standard Wordpress template architecture.
The root of your problem is that you are treating your header like a template when it is actually a partial.
In Timber terms, a template corresponds to a post or an archive and consists of two files:
A Twig file with your html markup mixed with some variables and logic, and a PHP file that, at minimum, defines the following:
The Timber context for a given post generated with Timber::context() (formerly get_context(), which has been deprecated)
Which twig file (or files) should be used to render the template
The very simplest Timber PHP template file could look like this:
<?php
/*
* This is the `single.php` template
*/
$context = Timber::context();
Timber::render( 'single.twig', $context );
This would generate the rendered contents of single.twig along with some global context values. In order to pass real values to the template, you have to assign them to $context, as you have attempted to do with $context['idagency_very_top_header_phone'], etc. However, these values cannot be assigned at the level of a partial — they must be assigned at the template level or higher.
To do what you are trying to do, you're going to need to set up a template (e.g. single.php and single.twig), and then include the header.twig file inside your template Twig file using {% include 'header.twig' %}.
Then you need to define your context values so that they are available to single.twig and all of its included partials, which in this case would include header.twig. You can define these directly inside the single.php file, after $context is defined. For simplicity, I'm only defining one of your values:
/* single.php */
$context = Timber::context();
$idagency_very_top_header_phone = get_theme_mod(
'idagency_very_top_header_phone',
esc_html__( '(+9) 0999.500.400', 'idweb')
);
$context['idagency_very_top_header_phone'] = $idagency_very_top_header_phone;
Timber::render( 'single.twig', $context );
If you need these values to be global across all templates, you can also define them in your theme's functions.php using the (poorly documented) timber/context filter. Then the values will be available in any template where that Timber::context() is used:
/* This would be placed in your functions.php file
* (or a separate file that's been included in functions.php)
*/
add_filter( 'timber/context', function( $context ) {
$idagency_very_top_header_phone = get_theme_mod(
'idagency_very_top_header_phone',
esc_html__( '(+9) 0999.500.400', 'idweb')
);
$context['idagency_very_top_header_phone'] = $idagency_very_top_header_phone;
return $context;
} );
This leaves out some key steps for setting up a full template, like including the data from the actual post, but that is all decently documented in Timber's Getting Started guide.
The key, TL;DR points are:
The Timber context is defined once per post
The context and all of its values are passed directly from the post's PHP template to its Twig template
Twig partials are not tied directly to partial-specific PHP files.
Partials included within a Twig template inherit the Timber context from that template. The same goes for partials nested within those partials.
This is late, but for any future dwellers, the above answers only show how to do it the WordPress way in timber, whereas, there's a simpler native way to achieve this in timber.
This is how you can get any current theme mod in timber twig view files natively:
{{ site.theme.theme_mod('mod_name_here') }}
How it works: Timber supplies the current theme object in the default global object (you don't need to add this manually, anywhere).
From Timber's documentation (here), timber theme object has this method: theme_mod
Hope this helps anyone stuck in future.
Related
I want to include some template and append on button click (by js), and I need each included template to have a unique id.
Here is the logic where I appending the templates:
<button type="submit" id="addTranslationFields">Add translations</button>
// and js
$('#addTranslationFields').on('click', function (event) {
event.preventDefault();
event.stopPropagation();
let part = `{% include 'translationPart.twig' with {'languages': languages,}%}`;
$('.table tbody').append(part);
});
Here is the how I generate uuid in the translationPart.twig
{% set uuid = uuid() %}
{{ uuid }}
The issue is that UUID is the same for all of the created templates. I understand why it's happening, it's b-z twig generated server-side and at the moment of generation it sees only one include. But is there some option to rerender included template for each new included copy? Or maybe some other way to set different UUIDs for each of the included templates.
Updated
uuid() is a custom twig function
$twig->addFunction(
new TwigFunction(
'uuid',
static function(): string {
return Uuid::uuid4()->toString();
}
)
);
You can achieve this via ajax calls, or string replacement.
String replacement
Twig template (translationPart.twig)
{% set uuid = '#_SOME_STRING_TO_REPLACE_#' %}
{{ uuid }}
Javascript
<button type="submit" id="addTranslationFields">Add translations</button>
// and js
$('#addTranslationFields').on('click', function (event) {
event.preventDefault();
event.stopPropagation();
let generatedUuid = generateUuidByJavascript();
let part = `{% include 'translationPart.twig' with {'languages': languages,}%}`.replace('#_SOME_STRING_TO_REPLACE_#', generatedUuid);
$('.table tbody').append(part);
});
Uuidjs can be used for generating uuid.
I need to add a new OpenCart template file into another template file.
Essentially I've created a new head file in /theme/customtheme/template/common/ called "header_home.twig".
Then in home.twig, I've changed {{ header }} to say {{ header_home }}, but it's not displaying anything.
Basically, all I did was copy header.twig and rename it to header_home.twig, and put in "xxxxx" to see if it was calling the new file, which it's not. Instead, it's not displaying anything.
Here's what my home.twig now looks like:
{{ header_home }}
<div id="common-home" class="container">
<div class="row">{{ column_left }}
{% if column_left and column_right %}
{% set class = 'col-sm-6' %}
{% elseif column_left or column_right %}
{% set class = 'col-sm-9' %}
{% else %}
{% set class = 'col-sm-12' %}
{% endif %}
<div id="content" class="{{ class }}">{{ content_top }}{{ content_bottom }}</div>
{{ column_right }}</div>
</div>
{{ footer }}
I assume I'm somehow missing a step when it comes to adding a new template file? If someone could help me with adding in a new twig file, that would be fantastic.
You can either:
Change the name of Twig rendering template on the OpenCart level in the controller/common/header as #bogalakon pointed out (preferably to do this via ocmod so that your future OpenCart updates will not overwrite your hack).
or include another template on the Twig level
I.e.:
{{ header }} {# Original rendered to HTML OpenCart header - you can move it to your header_home.twig or just drop it #}
{% include customtheme/template/common/header_home.twig %}
<div id="common-home" class="container">
...
Twig is very powerful template language. And you can do much more than just a simple include! It's nice that OpenCart officially accepted it. But for now it's just Twig 1.24.2. Please refer to the Twig documentation.
I haven't learn OpenCart 3.x, but I guess you need to change
return $this->load->view('common/header', $data);
to
return $this->load->view('common/header_home', $data);
in catalog/controller/common/header.php.
In order to connect another template via the {{header_home}} construct, you need to create the header_home.php in the folder /controller/common/directory, create the header_home.twig file in the theme /*theme_name*/template/common/ folder and in the controller , which is responsible for the formation of the page, for example in the directory /controller/common/home.php
add a line:
'$ data [' header_home '] = $ this-> load-> controller (' common / header_home '); '
before:
'$ this-> response-> setOutput ($ this-> load-> view (' common / home ', $ data)); '
To add your own custom twig file and include it inside another existing one you need to do three things:
Create the actual custom twig file.
In your case it will be:
catalog/view/theme/customtheme/template/common/header_home.twig
Create a controller for that twig file. In your case you can just copy:
/catalog/controller/common/header.php and rename that to header_home.php. Edit this controller and change the class name to ControllerCommonHeaderHome usually on line 2.
Lastly, since you are going to include header_home inside home.twig, edit /catalog/controller/common/home.php and add the line $data['header'] = $this->load->controller('common/header_home'); after $data['header'] = $this->load->controller('common/header');
That's it. After you've done the steps above, you can now include {{ header_home }} inside home.twig. If you are editing the files directly, I find that sometimes I need to login to the admin of the website, go to design>theme editor, open up the files I added or changed, hit reset, and save. Refresh your website and you should see the changes.
The answer of #bogalakon is right but if you update your OpenCart core files you will lose your changes so, I suggest you to copy the header.php controller file and rename it to header_home.php and then edit the file and replace the line
return $this->load->view('common/header', $data);
with:
return $this->load->view('common/header_home', $data);
There are several ways to give a different value.
For example:
Consider the controller
$data['header'] = $this-> load-> controller ('common / header');
A variable {{header}} is available in the template
You can place a new template in another file (header_home.twig), and then you can immediately download a new template for use:
$data['**header**'] = $this-> load-> controller ('common / ***header_home***');
If you want use {{header}} in the template.
Or,
$data['**header_home**'] = $this-> load-> controller ('common / header_home');
For use {{header_home}} in the template.
How to disable particular layout(example:menus.phtml) for particular pages in controller in ZF2?? In the below example menus.phtml should be disable for specific pages. Remaining pages must contain menus.phtml like header and footer.
<div>
header.phtml
</div>
<div>
menus.phtml
</div>
<div>
<?php echo $this->content; ?>
</div>
<div>
footer.phtml
</div>
There are various aproaches to this. Also modules.zendframework has quite a few modules here that may help you out.
If you are still keen on writing that yourself you could add variables to your layout within your controllers like so:
<?php
//YourController.php
public function someAction()
{
...
$this->layout()->footer = 'default';
...
}
//layout.phtml
<?php if ($this->footer === 'default') : ?>
//show the footer
<?php endif; ?>
Doing this is pretty inefficient though. Just imagine you'd need to do this to every action in all the controllers... I sure would not like to do that.
Now zf2 has a service and event layer that could help us out quite a bit here. This is a pretty nice read and introduction to it. You'd just write a service and trigger a event on your controllers/routes/whatever. Now you would also probably like to configure what is shown and what is hidden right? Thats pretty easy, too. Just write yourself a config file and merge it with the global.config like so:
<?php
//CustomModule/module.php
public function getConfig() {
$config = array();
$configFiles = array(
include __DIR__ . '/config/module.config.php',
include __DIR__ . '/config/module.customconfig.php',
);
foreach ($configFiles as $file) {
$config = \Zend\Stdlib\ArrayUtils::merge($config, $file);
}
return $config;
}
Source: Where to put custom settings in Zend Framework 2?
First, get the controller or action name:
$controllerName =$this->params('controller');
$actionName = $this->params('action');
then in your layout/view script add a simple logic.
<?php if ($actionName != 'action that you want to disable the layout/menu'): ?>
echo $this->render('menus.phtml');
<?php endif; ?>
I have this route:
_view_tag:
pattern: /topic/{tid}
defaults: {_controller: "MyCoreBundle:ViewTag:index" }
And I want to show url like this: example.com/topic/Web+development. I use href="topic/{{ topicname|url_encode() }}". It is works, but of course it is not proper way, so I change to href="{{ path('_view_tag', {'tid': topicname|url_encode() } ) }}". But it is not showing example.com/topic/Web+development, it shows example.com/topic/Web%2Bdevelopment.
I also try this:
{% set _tid = topicname|url_encode() %}
<a href="{{ path('_view_tag', {'tid': _tid } ) }}" ...
But still not working
My question is, how to make it show example.com/topic/Web+development using twig path function?
The path function takes care of url-encoding for you. Your problem is that your space got encoded twice: first to a +, then that got converted to %2b. This will work:
path('_view_tag', { 'tid': topicname } )
I am using a customised version of search-theme-form.tpl
When I use the search box, I do get transferred to the search page. But the search does not actually take place. The search box on the search results page does work though. This is my search-them-form.tpl.php file (demo :
<input type="text" name="search_theme_form_keys" id="edit-search-theme-form-keys" value="Search" title="Enter the terms you wish to search for" class="logininput" height="24px" onblur="restoreSearch(this)" onfocus="clearInput(this)" />
<input type="submit" name="op" id="edit-submit" value="" class="form-submit" style="display: none;" />
<input type="hidden" name="form_token" id="edit-search-theme-form-form-token" value="<?php print drupal_get_token('search_theme_form'); ?>" />
<input type="hidden" name="form_id" id="edit-search-theme-form" value="search_theme_form" />
There is also a javascript file involved. I guess it's use is pretty clear from the code:
function trim(str) {
return str.replace(/^\s+|\s+$/g, '');
}
function clearInput(e) {
e.value=""; // clear default text when clicked
e.className="longininput_onfocus"; //change class
}
function restoreSearch(e) {
if (trim(e.value) == '') {
{
e.value="Search"; // reset default text onBlur
e.className="logininput"; //reset class
}
}
}
What can be the problem and how can I fix it?
Apparently, you cannot directly modify the HTML in search-theme-form.tpl.php since thats not the right way to do it. So my adding the class and onFocus and onBlur attributes was the problem.
The correct way to do it is to modify the themes template.php file. Basically we will be using form_alter() to modify the form elements. Since using the HTML way is wrong. Take a look at the code below (taken from : here )
<?php
/**
* Override or insert PHPTemplate variables into the search_theme_form template.
*
* #param $vars
* A sequential array of variables to pass to the theme template.
* #param $hook
* The name of the theme function being called (not used in this case.)
*/
function yourthemename_preprocess_search_theme_form(&$vars, $hook) {
// Note that in order to theme a search block you should rename this function
// to yourthemename_preprocess_search_block_form and use
// 'search_block_form' instead of 'search_theme_form' in the customizations
// bellow.
// Modify elements of the search form
$vars['form']['search_theme_form']['#title'] = t('');
// Set a default value for the search box
$vars['form']['search_theme_form']['#value'] = t('Search this Site');
// Add a custom class and placeholder text to the search box
$vars['form']['search_theme_form']['#attributes'] = array('class' => 'NormalTextBox txtSearch',
'onfocus' => "if (this.value == 'Search this Site') {this.value = '';}",
'onblur' => "if (this.value == '') {this.value = 'Search this Site';}");
// Change the text on the submit button
//$vars['form']['submit']['#value'] = t('Go');
// Rebuild the rendered version (search form only, rest remains unchanged)
unset($vars['form']['search_theme_form']['#printed']);
$vars['search']['search_theme_form'] = drupal_render($vars['form']['search_theme_form']);
$vars['form']['submit']['#type'] = 'image_button';
$vars['form']['submit']['#src'] = path_to_theme() . '/images/search.jpg';
// Rebuild the rendered version (submit button, rest remains unchanged)
unset($vars['form']['submit']['#printed']);
$vars['search']['submit'] = drupal_render($vars['form']['submit']);
// Collect all form elements to make it easier to print the whole form.
$vars['search_form'] = implode($vars['search']);
}
?>
In yourthemename_preprocess_search_theme_form - 'yourthemename' will obviously reflect the name of your custom theme. Basically the code is self-explanatory. what with the comments and all.
So, basically thats the way it works.