4

How do I pass a post ID to a Twig/Timber function like edit_post_link?

Reading the docs at https://timber.github.io/docs/guides/functions/#function-with-arguments

A function like edit_post_link will try to guess the ID of the post you want to edit from the current post in The Loop. the same function requires some modification in a file like archive.twig or index.twig. There, you will need to explicitly pass the post ID.

And that is what happens; when I use this

{{ function('edit_post_link', 'Edit', '<span class="edit-link">', '</span>', post.ID) }}

in index.twig, all the edit links have the post ID of the page that displays the loop of custom post types, not the post ID of each custom post type that is in the loop.

I'm using the function below in functions.php, which also forces a target="_blank" on edit links:

add_filter( 'edit_post_link', 'newwindow_edit_post_link', 10, 3 );

global $post;
$post_id = $post->ID;

    function newwindow_edit_post_link( $link, $post_id, $text ) {
        if( !is_admin() )
            $link = str_replace( '<a ', '<a target="_blank" ', $link );
        return $link;
    }

This is the basic loop on index.twig. "people" is a standard WordPress custom post type:

 {% if people %}

            {% for person in people %}

                    <a href="{{ person.link }}">{{ person.name }}</a>

                        {{ function('edit_post_link', 'Edit', '<span class="edit-link">', '</span>', post.ID) }}

            {% endfor %}

    {% else %}

 {% endif %}

That results in all of the edit links pointing to that page, not each custom post type "person."

So how do I call the post ID? Do I need to call the post ID in the custom Post Type function?

The main index.php file has standard Twig functions:

$context = Timber::get_context();
$context['posts'] = Timber::get_posts();
$templates = array( 'index.twig' );
Timber::render( $templates, $context );
BlueDogRanch
  • 721
  • 1
  • 16
  • 43
  • If `person` is a post (`WP_Post`) object, try `person.ID` instead of `post.ID`. – Sally CJ Oct 26 '18 at 18:33
  • Hmm.... but no, that doesn't work. – BlueDogRanch Oct 26 '18 at 19:22
  • In `index.php`, how do you define the `people`? Can you show the code? – Sally CJ Oct 26 '18 at 23:56
  • I added index.php, but it is a standard Twig function. The CPT person is a standard WordPress CPT. – BlueDogRanch Oct 27 '18 at 01:47
  • I meant, don't your `$context` have a `people` (`$context['people']`)? If yes, where is it being defined? If not, then from where is the `people`? Maybe you can show the full code in your `index.twig` file? Or temporarily add `{{ fn( 'var_dump', person ) }}` in your `for` loop, and share the output. – Sally CJ Oct 27 '18 at 17:24
  • Interesting; using `{{ dump(person) }}` showed me the ID, and using `{{ person.id }}` displays the ID in index.twig. But it must be lowercase id, not ID. But the whole function still doesn't work. – BlueDogRanch Oct 29 '18 at 02:17
  • I can test your code, but I need to see how the `people` is defined. Or is it something like `get_posts( 'post_type=person' )`? And by "function", you're referring to the `newwindow_edit_post_link()`, right? – Sally CJ Oct 29 '18 at 02:23
  • Sorry I mean, is it the `{{ function('edit_post_link', ...) }}` that doesn't work, and if so, how is it not working? No output, not the expected output, or? – Sally CJ Oct 29 '18 at 02:30
  • No output at all from `{{ function('edit_post_link', ...) }}` – BlueDogRanch Oct 29 '18 at 02:37
  • Try `{{ function( 'get_edit_post_link', person.id ) }}`, just to see if that leads to a proper output. – Sally CJ Oct 29 '18 at 02:49
  • Alternatively, as the [documentation](https://timber.github.io/docs/guides/functions/#make-functions-available-in-twig) says, make `edit_post_link` available in Twig by using `Timber\Twig_Function` inside the `timber/twig` hook. And use `{{ edit_post_link(...) }}`. If that still doesn't work, then maybe the problem is with `person.id`. – Sally CJ Oct 29 '18 at 03:00
  • What is in the Twig docs doesn't work. No output from `{{ function( 'get_edit_post_link', person.id ) }}`. `{{ person.id }}` does work, so I made a manual edit link using `{% if user %}` for logged in. – BlueDogRanch Oct 29 '18 at 03:38
  • Not sure what's wrong in your case, but I tested your code (though I used `front-page.php`) and everything worked fine for me. – Sally CJ Oct 29 '18 at 06:53
  • But of course, [`edit_post_link()`](http://developer.wordpress.org/reference/functions/edit_post_link/) would return no output if the current user doesn't have any permissions to edit the post. – Sally CJ Oct 29 '18 at 07:35

3 Answers3

1

Looking at the Twig 2.x documentation there is no {{ function }} Twig function by default. I've certainly never seen this in my years of using Symfony so I suspect this is something custom?

I've just Googled "timber/twig" and this is in fact a WordPress plug-in to provide Twig functionality on your theme templates, therefore I believe you've put the Symfony tag on your question by mistake. I'd suggest removing this and adding wordpress instead so you can attract answers more useful than mine.


We would need to see the PHP source for your custom edit_post_link Twig function for assurance. However it would appear that you simply need to map in your arguments the same order both on the PHP side and Twig side. For example if your function is:

function edit_post_link(string $label, string $openingHtml, string $closingHtml, int $postId) {
    // blah blah blah
}

After you've registered this function with Twig (although Timber appears to claim you may not need to do this, do check) you really would then use it exactly as you wrote:

{{ function('edit_post_link', 'Edit', '<span class="edit-link">', '</span>', post.ID) }}

I sense this may not be what you're getting at though, possibly you're wondering how you grab hold of post.ID in the first place. If that's the case then your issue isn't about {{ function }}, and we'd need to see more of your Twig template source along with the variables you've exposed to it from PHP.

Adambean
  • 1,096
  • 1
  • 9
  • 18
  • Thanks, I did mistakenly tag Symphony. And I don't have a function called edit_post_link in functions.php Sounds like I need one that will grab the post ID? – BlueDogRanch Oct 24 '18 at 18:50
  • If you don't have a PHP function that has been registered to Twig with alias `edit_post_link` I'd suspect Twig would throw this as an exception. Do a search for "edit_post_link" to be sure you haven't already got this alias registered to the wrong function by mistake. – Adambean Oct 24 '18 at 18:54
  • Ah, I do have a filter which forces a target="_blank"; added to my question. You're right; that must be why I don't get fatal errors. So does it make sense to add the post ID to that function? – BlueDogRanch Oct 24 '18 at 19:47
  • Yep, your "edit_post_link" filter would need an argument to receive the post ID. Doesn't matter which argument it is providing your front end Twig usage matches the order. – Adambean Oct 24 '18 at 19:55
  • OK, but now I'm not sure how to do that. Sounds like I need global $post; $post_id = $post->ID; to get the id for each post outside of the loop. – BlueDogRanch Oct 24 '18 at 20:10
  • Yep, though that's a WordPress issue, which is where my expertise ends. (Your Twig stuff seems to be fine.) Isn't there a PHP function like `the_post()` to get this information? – Adambean Oct 25 '18 at 09:05
1

So how do I call the post ID?

If the people in the loop in your index.twig template is an array of posts (i.e. each post is a WP_Post / Timber\Post instance), then you can (or should be able to) retrieve the post ID via person.ID or person.id (yes, both are actually set). So these worked well for me:

{{ function('edit_post_link', 'Edit', '<span class="edit-link">', '</span>', person.id) }}
{{ function('edit_post_link', 'Edit', '<span class="edit-link">', '</span>', person.ID) }}

How I confirmed the above

  1. I installed and activated the official Timber starter theme.

  2. I created front-page.php:

    <?php
    $context = Timber::get_context();
    
    // Here, I defined the `people`.
    $context['people'] = Timber::get_posts( [
        'post_type'      => 'post', // yours would be 'person' and not 'post'
        'posts_per_page' => 3,
    ] );
    
    // This I used for testing only.
    $context['post'] = new Timber\Post();
    
    $templates = array( 'front-page.twig' );
    Timber::render( $templates, $context );
    
  3. Then I created templates/front-page.twig:

    {% extends "base.twig" %}
    
    {% block content %}
        <h2>The queried page's title: {{ post.title }}</h2>
        <p>The queried page's ID: <b>{{ post.id }}</b></p>
        {% if people %}
    
            {% for person in people %}
    
            <a href="{{ person.link }}">{{ person.name }}</a>
    
            {{ function('edit_post_link', 'Edit', '<span class="edit-link">', '</span>', person.id) }}<br>
    
            {% endfor %}
    
        {% else %}
    
        {% endif %}
    
        {% include 'partial/pagination.twig' with { pagination: posts.pagination({show_all: false, mid_size: 3, end_size: 2}) } %}
    {% endblock %}
    

And everything worked just fine for me — the edit_post_link() got called properly and displays the post link with the target="_blank" in the markup. (I put the newwindow_edit_post_link stuff in functions.php)

Sally CJ
  • 15,362
  • 2
  • 16
  • 34
1

This is ugly, but if you can't get the edit_post_link function to work in a template.twig, and {{ person.id }} does work, you could use this setup in your twig template.

It determines if a user is logged in and can edit and if so, displays an edit link - dynamic with {{ person.id }} - that opens in a new tab:

{% if user %}
<a class="style-me" target="_blank"
href="{{ site.url }}/wp-admin/post.php?post={{ person.id }}&action=edit">Edit</a>
{% endif %}
markratledge
  • 17,322
  • 12
  • 60
  • 106