can i pass my php code to twig code of timber - wordpress

I would like to know if I can convert any types of PHP code to twig, what I want to know is, for example, whether I can pass the code.
<?php
if (ICL_LANGUAGE_CODE == 'in'):?
to
{{ lang.en }}
Is there a way to add any PHP code and turn it into a twig and recognize it?
I use the Timber template for WordPress.

There is a good way to pass your functions (more correctly, register the function to Twig).
Using Timber Hook: timber/twig
There is a class in filter hook timber/twig could help us pass functions to Twig. It calls Timber\Twig_Function.
new Timber\Twig_Function(
'function_name_that_will_be_called_in_Twig',
'function_name_in_php'
);
// OR
new Timber\Twig_Function(
'function_name_that_will_be_called_in_Twig',
function( $input ) {
// anonymous function is ok too.
}
);
functions.php
add_filter( 'timber/twig', 'add_to_twig' );
function hello_in_php( $name = 'world' ) {
$hello = 'Hello ';
$hello .= $name;
return $hello;
}
function add_to_twig( $twig ) {
$func = new Timber\Twig_Function('hello', 'hello_in_php');
$filter = new Timber\Twig_Function('introduce', function( $name ) {
return "I'm ${name}!";
});
$twig->addFunction($func); //Registering a pre-defined function
$twig->addFunction($filter); //Registering a filter function
return $twig;
}
index.twig:
<p id='a'>{{ hello() }}</p>
<p id='b'>{{ hello('who?') }}</p>
<p id='c'>{{ "Batman"|introduce }}</p>
Result is:
<p id='a'>Hello World</p>
<p id='b'>Hello who?</p>
<p id='c'>I'm Batman!</p>
Source: https://timber.github.io/docs/guides/extending-timber/#adding-functionality-to-twig

You mean something like this comparison ?
{% if constant('ICL_LANGUAGE_CODE') == 'en' %}
{# your output here #}
{% endif %}

Related

Getting Woocommerce product price with Timber

How do I get the Woocommerce product price I would get using <?php echo $product->get_price_html(); ?> in a non Timber Wordpress template?
I tried {{ product.price }} but it triggers an error which says:
price was called incorrectly. Product properties should not be accessed directly.
I know that I can get it through the Woocommerce template using {% do action('woocommerce_single_product_summary') %}, but:
I want the raw unformatted text, not the content of the Woocommerce template.
the Woocommerce action also gets a bunch of other stuff I don't need.
So, how do I access it correctly?
I ended up adding a custom function to Timber that returns the raw price value. This goes in the functions.php file:
public function add_to_twig( $twig ) {
$function = new Twig_Function('myprice', function () {
global $product;
$myprice = $product->get_price();
return $myprice;
});
$twig->addFunction($function);
return $twig;
}
it can be used in any Twig template with {{ myprice() }}

Timber how to implement get_current_url wp

Ive been using Wordpress for more than a year now. But I was stuck with the implementation of Timber twig framework get the current URL. I tried these codes below codes but no luck,.
{{ site.url.current }}
{{ app.request.getRequestUri() }}
Twig templates engine: get current url
Have you tried:
URLHelper::get_current_url()
Doc: https://timber.github.io/docs/reference/timber-urlhelper/#get_current_url
So, you should be able to feed this as a variable into your template.
Or if you want to get a step further and extend Timber's Twig i.e. creating a filter or function like:
$twig->addFilter(new \Twig_SimpleFilter('is_current_url', function ($link) {
return (URLHelper::get_current_url() == $link) ? true : false;
}));
Which should bring things down to:
{{ 'http://example.org/2015/08/my-blog-post' | is_current_url }}
BTW: Internally, get_current_url() returns: $_SERVER['HTTP_HOST']/$_SERVER['SERVER_NAME'] + $_SERVER["REQUEST_URI"]
Adding ['current_url'] in functions.php under add_to_context function worked for me:
public function add_to_context($context)
{
// $context['foo'] = 'bar';
$context['current_url'] = Timber\URLHelper::get_current_url();
$context['site'] = $this;
return $context;
}
You then will be able to use it globally in your twig templates:
<pre>
Current Url: {{ dump(current_url) }}
</pre>

How to get formatted HTML generated by Symfony

I'm using Symfony2 to generate forms, or actually Twig, which uses Symfony's functions, so the view looks like this:
{{ form_start(form) }}
{{ form_widget(form) }}
{{ form_end(form) }}
This generates HTML code without any newlines or indentation. This is unreadable when I look into HTML source code.
Is there any way to force Symfony/Twig to format the generated HTML?
This link explains form customization in twig beautifully. There are numerous ways of applying css styling to form elements. For example, if you have a form with a field name you can add a css class to it this way:
{# render a widget, but add a "foo" class to it #}
{{ form_widget(form.name, {'attr': {'class': 'foo'}}) }}
or to the label:
{{ form_label(form.name, 'Your Name', {'label_attr': {'class': 'foo'}}) }}
Then you can use the css classes to render form elements as per your design. Hope you get the idea. The docs and link provided in the answer are both useful in this regard.
Update: the below "solution" made me a headache precisely this line:
$html = mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8');
It converts all non-ascii characters to entities, which is not very smart. Javascript's confirm and alert functions don't convert it back to UTF-8, they display strings as they are.
Thanks everybody, but I think I wasn't clear enough:) I didn't mean formatting by css or generally changing how the rendered page looks like, but rather changing HTML source code.
Anyway, with these two articles I finally managed to do what I wanted:
How do you format DOM structures in PHP?
http://php-and-symfony.matthiasnoback.nl/2011/10/symfony2-create-a-response-filter-and-set-extra-response-headers/
Step 1.
So, first the response listener, in (for example) AppBundle/EventListener/ResponseListener.php:
namespace AppBundle\EventListener;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\DependencyInjection\ContainerInterface as Container;
class ResponseListener {
private $container;
public function __construct(Container $container) {
$this->container = $container;
}
function tidyHtml($html)
{
$dom = new \DOMDocument();
if (libxml_use_internal_errors(true) === true)
{
libxml_clear_errors();
}
$html = mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8');
$html = preg_replace(array('~\R~u', '~>[[:space:]]++<~m'), array("\n", '><'), $html);
if ((empty($html) !== true) && ($dom->loadHTML($html) === true))
{
$dom->formatOutput = true;
if (($html = $dom->saveXML($dom->documentElement, LIBXML_NOEMPTYTAG)) !== false)
{
$regex = array
(
'~' . preg_quote('<![CDATA[', '~') . '~' => '',
'~' . preg_quote(']]>', '~') . '~' => '',
'~></(?:area|base(?:font)?|br|col|command|embed|frame|hr|img|input|keygen|link|meta|param|source|track|wbr)>~' => ' />',
);
return '<!DOCTYPE html>' . "\n" . preg_replace(array_keys($regex), $regex, $html);
}
}
return false;
}
public function onKernelResponse(FilterResponseEvent $event) {
$request = $event->getRequest();
//only when format == html and environment == dev
if ($request->getRequestFormat() == 'html' && $this->container->get('kernel')->getEnvironment() == 'dev') {
$event->getResponse()->setContent($this->tidyHtml($event->getResponse()->getContent()));
}
}
}
Step 2.
In services.yml:
response_listener:
class: AppBundle\EventListener\ResponseListener
arguments: ['#service_container']
tags:
- { name: kernel.event_listener, event: kernel.response, method : onKernelResponse }

Passing multiple arguments through twig path

I have this twig code:
<div style="padding-left: 5em" class="comment">
<p>{{ comment.author.name }} - {{ comment.created|date('j. n. Y H:i') }}</p>
<p>{{ comment.text }}</p>
<p>Odpovědět na komentář</p>
{% for child in comment.children %}
{% include 'BlogApplicationBundle:Post:_comment.html.twig' with {'comment' : child}%}
{% endfor %}
</div>
and this is function that processes the output from link in twig code:
/**
* #Route("/post/{id}/newcommentresponse", name="comment_response_new")
* #Template("BlogApplicationBundle:Post:form.html.twig")
*/
public function commentResponceAction($id,$idc)
{
$comment = new Comment();
$form = $this->createForm(new CommentType(), $comment);
return array(
'form' => $form->createView()
);
}
when i try to run code i get this error :
Controller "Cvut\Fit\BiWt1\Blog\ApplicationBundle\Controller\CommentController::commentResponceAction()"
requires that you provide a value for the "$idc" argument (because
there is no default value or because there is a non optional argument
after this one).
So it seems that second argument passsed through link is ignored and i have no idea what am i doing wrong.
You are missing the $idc definition in your #Route annotation. It should look something like this:
#Route("/post/{id}/newcommentresponse/{idc}", name="comment_response_new")
or this:
#Route("/post/{id}/{idc}/newcommentresponse", name="comment_response_new")
You can also leave it out of the route and function declaration and grab it directly from the Controller:
/**
* #Route("/post/{id}/newcommentresponse", name="comment_response_new")
* #Template("BlogApplicationBundle:Post:form.html.twig")
*/
public function commentResponceAction($id)
{
$idc = $request->query->get('idc');

How to load a controller function and render it in a twig tag using Symfony2?

I am using Symfony2 and Twig. I have a function (below) in my controller that returns a specific text. Is it possible to call that function directly from my template and change the {{text}} in my template to whatever the function returns, possibly via Ajax?
Here's my function:
public function generateCode($url) {
$url = $_SERVER['SERVER_NAME'] . '/embed/' . $url;
$return = '<iframe>'.$url.'</iframe>';
return $return;
}
Another controller function calls the function above and renders my template:
public function getCodeAction($url) {
$text = $this->generateCode($url);
return $this->render('MyMyBundle:User:code.html.twig', array('text' => $text));
}
In my template I am using:
{{ text }}
to display the value.
In Symfony 2.2, this was changed.
The render tag signature and arguments changed.
Before:
{% render 'BlogBundle:Post:list' with { 'limit': 2 }, { 'alt': BlogBundle:Post:error' } %}
After:
{% render controller('BlogBundle:Post:list', { 'limit': 2 }), { 'alt': 'BlogBundle:Post:error' } %}
or
{{ render(controller('BlogBundle:Post:list', { 'limit': 2 }), { 'alt': 'BlogBundle:Post:error'}) }}
Note: The function is the preferred way.
See https://github.com/symfony/symfony/blob/2.2/UPGRADE-2.2.md
You can use ajax if you have dynamic data, but as far as I can see from your brief info, you can always execute that controller function directly from your view:
{% render "MyMyBundle:User:generateCode" with { 'url': 'your url here' } %}
More Information on this available at:
http://symfony.com/doc/2.0/quick_tour/the_view.html, under Embedding other Controllers
For the record, in new versions you need to use the absolute URL:
{{ render url('my_route_id', {'param': value}) }}
{{ render(controller("AcmeDemoBundle:Demo:topArticles", {'num': 10})) }}
In Silex I solved it like this:
{{ render(url('route_name', {'param': value})) }}
If you do not have the route name, URL can be used:
{{ render(app.request.baseUrl ~ '/some-path/' ~ value) }}
If using URL we should always concat the baseUrl.
Symfony 2.6+
in twig:
{{ render(controller('AppBundle:PropertySearch:featuredProperties', {'limit': 15})) }}
controller:
/**
* featuredPropertiesAction
*
* #param Request $request
* #param int $limit
*
* #return Response
*/
public function featuredPropertiesAction(Request $request, $limit)
{
$search = $this->resultsHelper->featuredSearch($limit);
return $this->render('HASearchBundle::featured_properties.html.twig', [
'search' => $search,
]);
}

Resources