Issue with Post Object Timber/Twig WordPress - wordpress

I have an ACF field, It's a Repeater, and inside the Repeater is a Post Object.
Controller
/* Template Name: Strategic Partners */
use Timber\Timber;
use Timber\PostQuery;
use Flynt\Utils\Options;
use const Flynt\Archives\POST_TYPES;
$context = Timber::get_context();
$context['slider'] = get_field('slider');
$context['featured'] = get_field('featured');
if (isset($_GET['contentOnly'])) {
$context['contentOnly'] = true;
}
Timber::render('templates/StrategicPartners/index.twig', $context);
Here's the snippet from the View
{% for partner in Post(featured) %}
{{ partner.link }}
{% endfor %}
I'm var_dumping the context, and it's getting the Timber Post... but {{ partner.title }} does not grab the Post Title, it's blank.
{{ partner.link }} comes out with the direct link.
Output
http://***/strategic-partners/
http://***/strategic-partners/
What am I doing wrong here? I'm using {{ Post() }}} within a seperate repeater, within for foreach itself and that works on another page, but it does not work here either, so I tried Post() included in the foreach and it still is not working.

No one answered this for me. I answered it myself.
There isn't much documentation on this within the formal Timber documentation so I hope this helps somebody.
Do not call Post with your foreach
Do this for a Post Object within a Repeater (ACF)
{% for item in seq %}
{{ Post(item.post_object_name).field }}
{% endfor %}
seq is your ACF Field
post_object_name is the Post Object within the field.
field is the field within the Post Object type.
Hope this helps someone.
For more Context:
Controller
<?php
/* Template Name: Strategic Partners */
use Timber\Timber;
use Timber\PostQuery;
use Flynt\Utils\Options;
use const Flynt\Archives\POST_TYPES;
$context = Timber::get_context();
$context['slider'] = get_field('slider');
$context['featured_sps'] = get_field('featured_strategic_partners');
$context['rebate'] = get_field('rebate_information');
if (isset($_GET['contentOnly'])) {
$context['contentOnly'] = true;
}
Timber::render('templates/StrategicPartners/index.twig', $context);
Twig View
{% for partner in featured_sps %}
{{ Post(partner.featured).title }}
{% endfor %}
Images are more complex
{% for partner in featured_sps %}
<div class="slide">
<a href="{{ Post(partner.featured).link }}">
<img src="{{ Image(Post(partner.featured).logo).src }}" alt="{{ Post(partner.featured.title) }} Logo">
</a>
</div>
{% endfor %}

Related

Add posts with timber twig into an include

On a single page, I need to add an include, on the bottom of the page, that add 3 projects.
I have a content type called projects I made with ACF.
single-project.twig
I have a "single-project.twig" page that display the content of a post (which is also a project). At the bottom of this page, I need to add a block like this:
{% block related %}
{% include 'inc-related.twig' %}
{% endblock %}
inc-related.twig
Into "inc-related.twig", I have this:
{% for post in related_posts %}
{% if post.thumbnail %}
<a href="{{post.link}}" class="l-basicgrid-work work">
<article>
<figure>
<img data-src="{{post.get_thumbnail.src('medium_large')|resize(800, 533)}}" alt="{{post.title}}" class="lazy">
</figure>
<figcaption>
<h2>{{ post.title }}</h2>
</figcaption>
</article>
</a>
{% endif %}
{% endfor %}
related.php
I also create a "related.php" page, that integrate the following rendering:
$context = Timber::get_context();
$context['related_posts'] = Timber::get_posts('post_type=project&posts_per_page=3');
Timber::render('inc-related.twig', $context);
Questions
I have 2 questions:
The project are not displaying into the single page. What I have done
wrong?
Can I select 3 project except the one who is displayed on the
single page?
Thank you
you have include twig template but not send data to him. Your related.php is not include automatically. You should write $context['related_posts'] = Timber::get_posts('post_type=project&posts_per_page=3'); in your single-project.twig. And do not use post name in inc-related.twig. May be conflict with current post object.
To single-project.php add $context['related_posts'] = Timber::get_posts('post_type=project&posts_per_page=3');
This is what I did.
single-project.php
I have created a single-project.php page. It contains the following script:
$context = Timber::get_context();
$args = array(
// Get post type project
'post_type' => 'project',
// Get 3 posts
'posts_per_page' => 3,
// Order random
'orderby' => 'rand',
);
$context['related_posts'] = Timber::get_posts( $args );
Timber::render('single-project.twig', $context);
single-project.twig
On my single-project.twig, I have the code that get the result of the php page. Actually, that code is included into an "inc-related.twig" page. And it works!
{% for post in related_posts %}
{% if post.thumbnail %}
<a href="{{post.link}}" class="l-basicgrid-work work">
<article>
<figure>
<img data-src="{{post.get_thumbnail.src('medium_large')|resize(800, 533)}}" alt="{{post.title}}" class="lazy">
</figure>
<figcaption>
<h2>{{ post.title }}</h2>
</figcaption>
</article>
</a>
{% endif %}
{% endfor %}
But on the same page (single-project.twig), I also have data that display content from Advanced Custom Field.
{% if post.project_images %}
{% for item in post.get_field('project_images') %}
<figure class="{{item.project_media_css}}">
<img data-src="{{TimberImage(item.project_media).src}}" alt="{{item.alt_media}}" class="lazy">
</figure>
{% endfor %}
{% endif %}
The problem now is that the ACF field don't return anything.
How should I modify single-project.php to get content from "related_project" and ACF field?
The ACF context is passed to the single page template via Timber $context, using the get_posts function.
single-project.php
$context['related_posts'] = Timber::get_posts('post_type=project&posts_per_page=3');
Twig sends along the active context by default, so this template is fine as-is.
{% block related %}
{% include 'inc-related.twig' %}
{% endblock %}
Finally, the posts in $context['related_posts'] can be looped over. However, within the for loop, refer to each post by anything other than post, such as rel_post. This avoids conflict with the regular post object.
{% for rel_post in related_posts %}
{% if rel_post.thumbnail %}
...
{% endif %}
{% endfor %}

How to get image metadata from ACF gallery images?

I wanted to display image metadata of images from a gallery added with Advanced Custom Fields, is that possible?
So far, I've tried this (and a few other things too which didn't work either):
front-page.php
<?php
/**
The front page template file
*/
$context = Timber::get_context();
$post = Timber::query_post();
$context['post'] = $post;
Timber::render( 'home.twig', $context );
home.twig
{% extends "base.twig" %}
{% block content %}
{% for image in post.get_field('gallery') %}
{{ post.wp_get_attachment_metadata(TimberImage(image).id) [image_metadata][aperture] }}
{% endfor %}
{% endblock content %}
Thanks for your answer, I hope you can help me! :)
the meta data that you want should be available when converting to a TimberImage object so....
{% for image in TimberImage(post.get_field('gallery')) %}
{{ image|print_r }}
{% endfor %}
The print_r filter will output all the values on the object. That said, if you specifically want the array that WP normally the "fix" for your code would likely be...
{% for image in post.get_field('gallery') %}
{{ function('wp_get_attachment_metadata', TimberImage(image).id). image_meta.aperture }}
{% endfor %}
I say "likely" because the above is untested — give it a shot and let me know!

FormComponent - Pass Entity with Form to Template

Lets say i have a one to many relation:
A company can own several pictures
I have company entity and image entity
Now, I want to display all pictures of a company within a template. And i also want to make theese pictures directly editable. I thought of adding a form to each Entity of the DoctrineArrayCollection and pass them to the template. In Template if somebody clicks on a picture the corresponding should be fade in, the should be able to edit the pictures description and pass it through ajax to a controller.
In my entity I added a field without annotations:
private $form;
public function setForm(MyPictureForm $form)
{
$this->form = $form;
}
public function getForm()
{
return $this->form;
}
Now in my controller I add a form instance to every picture of the company:
//office images with forms
$officeImages = array();
foreach($company->getOfficeImages() as $image)
{
$form = $this->get('companybundle.imagedescription.form.factory')->createForm();
$form->setData($image);
$image->setForm($form->createView());
array_push($officeImages, $image);
}
return $this->render('CompanyBundle:Company:Show/show.html.twig', array(
'company' => $company,
'officeImages' => $officeImages
));
}
And in my template i render it like this way:
{% for image in officeImages %}
<a href="#" title="{% if image.description %}{{ company.description }}{% else %}CLICK HERE FOR EDIT{% endif %}">
{% if image.image %}
<img src="{{ vich_uploader_asset(image, 'image') | imagine_filter('company_office_image_thumb') }}"
alt="{% if image.description %}{{ company.description }}{% endif %}"/>
{% else %}
{% image '#UserBundle/Resources/public/img/nopic_logo.jpg' output='/images/nopic_logo.jpg' %}
<img src="{{ asset_url }}" alt="Joblogo"/>
{% endimage %}
{% endif %}
</a>
{{ form(image.form) }}
{% else %}
<p>Es sind noch keine Images vorhanden</p>
{% endfor %}
At the end there is a lot if javascript stuff which handels the fade in / fade out of the form and their submitting.
Is this the correct way to handle my case? I think not cause passing a form for every picture seems like overhead?
The reason why I am working with forms instead of simply passing data out of a manual added input field is csrf protection and the smart usage of the form component.
As you said keeping form object in entity isn't a good idea. It should represents model data.
I've got two solutions for this:
I. Pass array of forms with image id as a key
$officeImages = array();
$imageForms = array();
foreach($company->getOfficeImages() as $image)
{
$form = $this->get('companybundle.imagedescription.form.factory')->createForm();
$form->setData($image);
$imageForms[$image->getId()] = $form->createView();
}
return $this->render('CompanyBundle:Company:Show/show.html.twig', array(
'company' => $company,
'officeImages' => $officeImages,
'imageForms' => imageForms
));
and in show.html.twig
{% for image in officeImages %}
{# your image display code #}
{{ form(imageForms[image.id]) }}
{% endfor %}
II. render partial for single image
in controller
public function showAndEditImageAction(Image $image)
{
$form = $this->get('companybundle.imagedescription.form.factory')->createForm();
$form->setData($image);
return $this->render(
'CompanyBundle:Company:Show/showAndEditImage.html.twig', array(
'image' => $image,
'imageForm' => $form->createView()
));
}
in twigs
{# CompanyBundle:Company:Show/showAndEditImage.html.twig #}
{# your image display code #}
{{ form(imageform) }}
{# CompanyBundle:Company:Show/show.html.twig #}
{% for image in officeImages %}
{{ render(controller('CompanyBundle:Company:showAndEditImage',
{ 'image': image })) }}
{% endfor %}

Returning a collection in collection from controller to twig in Symfony

I guess this is pretty easy but I am a novice at Symfony so I got troubles with it.
So basiccaly here is what I got in Controller
public function pollResultsAction( $pollId ) {
$poll = $this->get('doctrine')->getRepository('Myproject:Poll')->find( $pollId );
$questions = $poll->getItems();
return array(
'questions' => $poll->getItems()
);
}
where $questions is a Collection of questions of the Poll given
then I have
{% if questions %}
<ul>
{% for question in questions %}
<li> {{ question.question }}</li>
// here I'd like to have answers to given question
{% endfor %}
</ul>
in a Twig file.
I can get to answers like this
$answer = $onequestion->getAnswers();
I'd like to print answers to each question in twig. I think I need to some foreach loop in controller but I don't know how to return it to twig.
Thank you for your help in advance.
In your view:
{% for question in questions %}
{{ qustion.question }}
{% for answer in question.answers %}
{{ answer }}
{% endfor %}
{% endfor %}

Symfony 2 - Access mapped Object property form twig

I hava a entity with the following flied:
/**
* #ORM\ManyToOne(targetEntity="Document", inversedBy="posts")
* #ORM\JoinColumn(name="document_id", referencedColumnName="id")
*/
protected $image;
which I get with the following method:
public function indexAction() {
$posts = $this->getDoctrine()
->getRepository('airpaprcms2Bundle:Post')
->findByPageType(1);
if (!$posts) {
throw $this->createNotFoundException('No posts in Database!');
}
return $this->render('airpaprcms2Bundle:Default:index.html.twig', array('posts' => $posts));
}
How can I access a property of the mapped object form within twig? I tried post.image.file (the mapped entity Document has a property file)
{% for post in posts %}
<div>
<h1>
{{ post.title }}
</h1>
<p>{{ post.text }}</p>
<img src="{{ post.image.name }}" alt="{{ post.title }}" />
</div>
{% endfor %}
and get the following error message:
Item "file" for "" does not exist in airpaprcms2Bundle:Default:index.html.twig at line 11
What is the right syntax to access the mapped document property?
You can access the property of your linked entity with the following twig syntax:
{% for post in posts %}
{{ post.entityName.propertyName }}
{% endfor %}
In your case that would be:
{% for post in posts %}
{{ post.image.propertyName }}
{% endfor %}
Be sure to check that all post entities are linked to an image object. If one post entity has no link to an image, you will get a property not found error when trying to render your page.

Resources