Jump to content
Anders

Clean syntax for rendering pages with specific template?

Recommended Posts

Consider this example, where I want to print a list of teasers (linked title + summary) for news articles:

$content = "";

foreach ($pages->find("template=article") as $article) {
    $content .= wireRenderFile('teaser', array("item" => $article));
}

It works, but I find the code quite ugly. I would much prefer to be able to switch the call to wireRenderFile to something more like this:

$article->renderWith("teaster");

Or even better, replace the whole thing with something like this:

$pages->find("template=article")->renderAllWith("teaser");

Are there  any functions like that? I searched the API, but couldn't find anything. Or is there any other way to make my code look better? Or is my quest completely misquided here?

I just started out with PW today, so I have no clue what I am doing yet. I already love it though!

Share this post


Link to post
Share on other sites

Welcome to the PW forums @Anders!

32 minutes ago, Anders said:

Consider this example, where I want to print a list of teasers (linked title + summary) for news articles:

There are many different ways you could do this and at the end of the day it comes down to personal preference.

Myself, if this was a one-off listing of teasers that wasn't to be used on other templates I would tend to build the markup directly in the template file and not render any other files. And if it was a listing that was to be used in several template files I would tend to render a file that looped over multiple pages and I would pass those pages to the rendered file. I prefer to output markup directly and make use of the Markup Regions feature, but to keep with your case of populating a $content variable it would be something like this:

$content .= $files->render('teasers', ['items' => $pages->find("template=article")]);

BTW, the wireRenderFile() function is sort of obsolete as far as I can see because it is just an alias for $files->render().

But if you wanted to render a page with something similar to your example...

37 minutes ago, Anders said:

$article->renderWith("teaster");

...then you could look at the (largely undocumented) $page->render() method. The best resource that I know of for this method is Ryan's post here:

Also you can read the comments for PageRender::renderPage() in /wire/modules/PageRender.module (which is what $page->render() calls behind the scenes).

So you could do something like:

foreach ($pages->find("template=article") as $article) {
    $content .= $article->render('teaser.php');
}

 

  • Like 2

Share this post


Link to post
Share on other sites

Your last code block (with $article->render) seems to render not only the teaser, but the full page of the article after that!

But it doesn't matter, because I think I like your $file->render suggestion the best anyway. I'll go with that. Thanks a lot for the help!

Share this post


Link to post
Share on other sites

On second thought.. Turns out module development is so simple due to the elegant API, so I went ahead and wrote myself a module:

<?php namespace ProcessWire;

class RenderWith extends WireData implements Module {

    public static function getModuleInfo() {
        return [
        'title' => 'RenderWith',
        'summary' => 'API extention for rendering pages with different templates.',
        'version' => 1,
        'autoload' => true
        ];
    }

    public function ready() {
        $this->addHook('Page::renderWith', $this, 'renderWith');
        $this->addHook('PageArray::renderWith', $this, 'renderManyWith');
    }

    public function renderWith($event) {
        $page = $event->object;
        $template = $event->arguments(0);
        $event->return = wireRenderFile($template, ["item" => $page]);
    }

    public function renderManyWith($event) {
        $pages = $event->object;
        $template = $event->arguments(0);
        $content = "";
        foreach ($pages as $page) {
            $content .= wireRenderFile($template, ["item" => $page]);
        }
        $event->return = $content;
    }

}

No idea if I am breaking any design principles or anything here, so viewer discretion is adviced.

  • Like 3

Share this post


Link to post
Share on other sites
26 minutes ago, Anders said:

Your last code block (with $article->render) seems to render not only the teaser, but the full page of the article after that!

Perhaps you have auto-prepended and/or auto-appended template files in your /site/config.php, in which case you would want to use the $options array to override those when rendering the page, e.g.

foreach ($pages->find("template=article") as $article) {
    $content .= $article->render('teaser.php', ['appendFile' => null]);
}

 

  • Like 3

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...