I am using Twigpress with Wordpress. According to the Twigpress doc, you can pass variables to the template with twigpress_render_twig_template($vals = array(), $template = false, $echo = true).
I'm trying to pass variables to the template with the following code but it doesn't work. What am I doing wrong?
single.php:
$vals = array( 'foo' => 'bar' );
twigpress_render_twig_template($vals);
single.twig:
{{ vals.foo }} # Does not print anything #
{{ foo }} # Same #
{{ dump(vals) }} # Prints 'null' #
Please enlighten a n00b! Thanks. :)
You have to enable debug in your twig setting.
This is how I do it for my Twig initialization. I put this in a separate file call twig-init.php and just require_once where i need to use twig.
$loader = new Twig_Loader_Filesystem('/blah/twig/templates');
$settings = array(
'cache' => '/blah/twig/compiled',
'debug' => true
);
$twig = new Twig_Environment($loader, $settings);
if ($settings['debug'])
$twig->addExtension(new Twig_Extension_Debug());
When you dump it, you can just do {{ dump() }} to dump everything instead.
In addition, you may need to access your array value via the _context. Try to {{ dump(_context['foo']) }}
If you really want to access the variable via vals, you will have to do the following to your array:
$blah = array('vals' => array('foo' => 'bar'));
Then {{ vals.foo }} will work.
See: http://twig.sensiolabs.org/doc/functions/dump.html
Related
I'm working on this flexible field where I have set it up so that the user in wp-admin can change the order of the content and also add new content modules. But if one module is used more than one time it's only the last one that will work. I believe its something I have made wrong in my loop. You can see the code below:
Basically, if the user adds two of the "overview_layout" the last one will work, the first one won't render. How would you solve this?
My ACF: https://pastebin.com/xAuqEtma
$context = Timber::get_context();
$post = new Timber\Post();
$context['post'] = $post;
$context['layout'] = get_field('cancer_type_layout');
if(have_rows('cancer_type_layout')):
while(have_rows('cancer_type_layout') ): the_row();
if(get_row_layout() == 'overview_layout'):
$context['overview'] = array (
'title' => get_sub_field('ct_overview_title'),
'text' => get_sub_field('ct_overview_text'),
'image' => get_sub_field('ct_overview_picture'),
'class' => 'bg-gray-100',
'gradient' => true
);
elseif(get_row_layout() == 'video_layout'):
$context['video'] = get_sub_field('ct_video_url');
elseif(get_row_layout() == 'statlist_layout'):
$context['statlist'] = array (
'title' => get_sub_field('ct_statlist_title'),
'text' => get_sub_field('ct_statlist_text'),
'list' => get_sub_field('ct_statlist_statlist'),
'button' => get_sub_field('ct_statlist_button'),
'buttontext' => get_sub_field('ct_statlist_button_text'),
'buttonlink' => get_sub_field('ct_statlist_button_link'),
'buttonfile' => get_sub_field('ct_statlist_button_file')
);
elseif(get_row_layout() == 'text_layout'):
$context['text'] = array (
'text' => get_sub_field('ct_text_text'),
'button' => get_sub_field('ct_text_button'),
'buttontext' => get_sub_field('ct_text_button_text'),
'buttlink' => get_sub_field('ct_text_button_link')
);
elseif(get_row_layout() == 'image_layout'):
$context['image'] = get_sub_field('ct_image_image');
elseif(get_row_layout() == 'qoutelist_layout'):
$context['quotelist'] = get_sub_field('ct_quotelist_quotes');
elseif(get_row_layout() == 'postlist_layout'):
$context['postlist'] = get_sub_field('ct_postlist_posts');
endif;
endwhile;
endif;
The main problem is that you overwrite variables in your context in each loop. When you set $context['overview] inside a loop, the content you set is not added to the existing content, but it overwrites what you already have. If you wanted that to work, you’d have to use an array and add your data there.
$context['overview'] = array();
if ( have_rows( 'cancer_type_layout' ) ):
while ( have_rows( 'cancer_type_layout' ) ): the_row();
if ( get_row_layout() == 'overview_layout' ):
$context['overview'][] = array(
'title' => get_sub_field( 'ct_overview_title' ),
'text' => get_sub_field( 'ct_overview_text' ),
'image' => get_sub_field( 'ct_overview_picture' ),
'class' => 'bg-gray-100',
'gradient' => true
);
By using $context['overview'][], you add the data to your existing array, instead overwriting it. However, if you do that for every single layout you have, you end up writing a lot of code. And you split the data into different variables. This will break the order of your layouts, because you only grouped the same Flexible Content layouts into on array.
I’d recommend to use a different approach, where you don’t have to prepare all the data in PHP and reduce the amount of code you have to write.
First, when you use get_field(), then you’re not making use of Timber’s functionality. You can use $post->meta() instead.
$context['layout'] = $post->meta( 'cancer_type_layout' );
Then, in your Twig file, you can loop over the layouts and include a file that displays the block:
{% if layout is not empty %}
{% for block in layout %}
{% include 'block/' ~ block.acf_fc_layout ~ '.twig' ignore missing %}
{% endfor %}
{% endif %}
For each of the layouts you have, you can now create a new Twig file with the name of the layout. In that file, all your data in the layout is available under the block variable.
block/overview_layout.twig
{{ block.title }}
{{ block.text }}
{# … #}
block/statlist_layout.twig
{{ block.title }}
{{ block.text }}
{{ block.list }}
{{ block.buttontext }}
{# … #}
Seems that I can't get the value out off the field “overview_title” on line 29. which is a subfield of the “overview_layout”.
JSON: https://pastebin.com/BLBb6cjx.
I can get the “overview_layout” field. but its subfields won't return anything. anyone?
What I'm trying to do is to get the values of those 3 custom fields. But I get nothing.
This is what i'm trying in Timber:
$post = new Timber\Post();
$context['post'] = $post;
$context['layout'] = get_field('cancer_type_layout');
$context['overview'] = array (
'title' => get_field('overview_title'),
'text' => get_field('overview_text'),
'image' => get_field('overview_picture')
);
Timber::render('templates/pages/template-cancer.twig', $context);```
When you work with Flexible Content fields in Timber, you mustn’t access subfields by more calls to get_field(). All data of the subfields is already there when you get the data with the name of the Flexible Content field.
$post = new Timber\Post();
$context['post'] = $post;
// Everything you need will be in block.
$context['block'] = $post->meta( 'cancer_type_layout' );
Timber::render( 'templates/pages/template-cancer.twig', $context );
In Twig, you can then access your data directly from the block variable:
{% if 'overview_layout' === block.acf_fc_layout %}
{{ block.overview_title }}
{{ block.overview_text }}
{{ block.overview_picture }}
{% endif %}
There is the following code
$form->with('Item')->add('parent', null, array(
'label' => 'Category',
'required' => true,
'query_builder' =>
function($er) use ($id) {
$qb = $er->createQueryBuilder('p');
if ($id){
$qb->where('p.id <> :id')
->setParameter('id', $id);
}
$qb->orderBy('p.root, p.lft', 'ASC');
return $qb;
}
.........
Result is the entity-objects collection which is given to the string (__toString method).
It return name-field.
But I need get the another field - url.
How to get url value instead the name in the select-list form?
The query_builder type return object => how to change this form that it works likewise query_builder?
I didn't work with SonataAdminBundle forms, but I think that it works absolutely like symfony forms. All that you need here is to add 'class' and 'property' values to your options list:
$form->with('Item')->add('parent', null, array(
'class' => 'Acme\DemoBundle\Entity\Category',
'property' => 'url',
'label' => 'Category',
'required' => true,
'query_builder' =>
function($er) use ($id) {
$qb = $er->createQueryBuilder('p');
if ($id){
$qb->where('p.id <> :id')
->setParameter('id', $id);
}
$qb->orderBy('p.root, p.lft', 'ASC');
return $qb;
}
property - is the name of the field in your entity that will represent your Entity's value instead of calling __toString().
But also... If you need always represent your Entity as URL you can simply override __toString() method in the Entity class to something like that:
public function __toString() {
return $this->url;
}
In my case, ->orderBy() used in query_builder worked, but was overwritten for unknown reasons "somewhere" later. Fun fact: when I used extended => true, everything was rendered like sorted in the query_builder. But by using extended => false my <option>s are re-sorted before select2 touched it.
As a workaround I did this:
config/packages/twig.yaml
twig:
paths:
'%kernel.project_dir%/templates': '%kernel.project_dir%/templates'
# This is to prevent a infinite loop when extending the parent template
'vendor/sonata-project/admin-bundle/src/Resources/views': SonataAdminBundleOriginal
And then I done the sorting I wanted again in twig for the project entity:
templates/bundles/SonataAdminBundle/Form/form_admin_fields.html.twig:
{% extends '#SonataAdminBundleOriginal/Form/form_admin_fields.html.twig' %}
{%- block choice_widget_options -%}
{% if name == 'project' %}
{% set options = options|sort((a, b) => a.data.numberSortable <=> b.data.numberSortable)|reverse %}
{% endif %}
{{ parent() }}
{%- endblock choice_widget_options -%}
Just in case if someone needs to "filter" an entity by a FK (foreign key) just like i needed (and searched for 3 days), here is the solution:
In the __construct you can set/find what you need. In my case i work this "sessions" (year). So i find the session->status=true:
$this->sessionActive = $this->sessionRepository->findOneBy(['status'=>true]);
Then in the QueryBuilder:
protected function configureQuery(ProxyQueryInterface $query): ProxyQueryInterface
{
$rootAlias = current($query->getRootAliases());
$query
->select($rootAlias)
->where($rootAlias.'.session = :id')
->addOrderBy($rootAlias.'.dateStart', 'ASC')
->setParameter('id', $this->sessionActive->getId());
return $query;
}
Note: I have always one Session->status set to "true". If you might have null values don't forget to make a condition so that it doesn't give you an error!
Regards.
Im new to Symfony / Twig and am having problems passing object values to my twig templates.
Here is some of my controller code that shows the content of the object:
$prevArticles = $section->getArticles();
print_r($prevArticles);
die()
Displays:
Array
(
[0] => Imagine\NewsletterBundle\Entity\Article Object
(
[id:protected] =>
[title:protected] =>
[headline:protected] =>
[link:protected] =>
[image:protected] =>
[excerpt:protected] =>
[check:protected] =>
[attachment:protected] =>
[field1:protected] =>
[field2:protected] =>
[field3:protected] =>
[magazines:protected] =>
[top_logo_advert:protected] => /uploaded_images/cece0b1859ea2b1af95f1f274620ba77.jpg
[top_logo_alt:protected] => Picture of blomange
[top_logo_link:protected] => www.google.com
)
)
So then I pass my object to my twig template like so:
return $this->render('ImagineNewsletterBundle:Section:'.$builder->getTemplate(), array('prevArticles' => $prevArticles));
Then in my twig template I want to display the value of 'top_logo_advert' but its not working:
{% for article in prevArticles %}
{{ article.top_logo_advert }}
{% endfor %}
I get the error message:
Method "top_logo_advert" for object "Imagine\NewsletterBundle\Entity\Article" does not exist in ImagineNewsletterBundle:Section:build_advert.html.twig at line 62
You must access it via :
{{ article.topLogoAdvert }} or {{ article.getTopLogoAdvert() }}
Both solutions works. Next time, just reminder that properties like 'my_property_1' is converted into myProperty1 in the twig engine.
I have a problem with Symfony2 and Twig: I don't know how to display all fields of my entity which is loaded dynamically. Here is my code (displays nothing!!)
Controller :
public function detailAction($id)
{
$em = $this->container->get('doctrine')->getEntityManager();
$node = 'testEntity'
$Attributes = $em->getRepository('TestBetaBundle:'.$node)->findOneById($id);
return $this->container->get('templating')->renderResponse('TestBetaBundle:test:detail.html.twig',
array(
'attributes' => $Attributes
));
}
detail.html.twig :
{% for key in attributes %}
<p>{{ value }} : {{ key }}</p>
{% endfor %}
Don't settle for just the public properties! Get the private/protected as well!
public function detailAction($id){
$em = $this->container->get('doctrine')->getEntityManager();
$node = 'testEntity'
$Attributes = $em->getRepository('TestBetaBundle:'.$node)->findOneById($id);
// Must be a (FQCN) Fully Qualified ClassName !!!
$MetaData = $em->getClassMetadata('Test\Beta\Bundle\Entity\'. $node);
$fields = array();
foreach ($MetaData->fieldNames as $value) {
$fields[$value] = $Attributes->{'get'.ucfirst($value)}();
}
return $this->container
->get('templating')
->renderResponse('TestBetaBundle:test:detail.html.twig',
array(
'attributes' => $fields
));
}
OK. What you are trying to do cannot be done with a Twig for loop over your attributes object. Let me try to explain:
The Twig for loop iterates over an ARRAY of objects, running the inside of the loop for each of the objects in the array. In your case, $attributes is NOT an array, it is an OBJECT which you retrived with your findOneById call. So the for loop finds that this is not an array and does not run the inside of the loop, not even once, that is why you get no output.
The solution proposed by #thecatontheflat does not work either, as it is just the same iteration over an array, only that you have access to both the keys and values of the array, but since $attributes is not an array, nothing is accomplished.
What you need to do is pass the template an array with the properties of the $Attributes object. You can use the php get_object_vars() function for this. Do something like:
$properties = get_object_vars ($Attributes);
return $this->container->get('templating')->renderResponse('TestBetaBundle:test:detail.html.twig',
array(
'attributes' => $Attributes
'properties' => $properties
));
And in the Twig template:
{% for key, value in properties %}
<p>{{ value }} : {{ key }}</p>
{% endfor %}
Take into account that this will only show the public properties of your object.
For Symfony3
$em = $this->getDoctrine()->getEntityManager();
$MetaData = $em->getClassMetadata('TestBetaBundle:Node');
$fields = $MetaData->getFieldNames();
return $this->render('test/detail.html.twig', array('fields'=>fields));
You should change it to
{% for key, value in attributes %}
<p>{{ value }} : {{ key }}</p>
{% endfor %}