How to Return HTML Snippet Using Content Representation

Hi all! I’ve started playing with HTMX in our projects, and it’s great! Unlike most javascript libraries and frameworks out there, however, HTMX expects the server to return a fully-formatted HTML snippet, rather than raw json.

The best way to achieve this, in some places, will be using routes. But in other places, the easiest way would be if we could just create a different content representation of the page. Except that instead of returning json, I’d like to return an HTML snippet. What is the easiest way to set this up? In particular:

  1. Do I use “*.html.php” for the extension of my new content template and controller? - eg., ‘article.html.php’? Or should I use an arbitrary ‘type’, eg. “article.card.php”?

  2. Do I need to send a header specifying the response type? If so, how do I do that?

Many thanks in advance for any guidance.

2 Likes

Igor, do you want to use the same template for both the html (default) and json content representation?

@bvdputte there will be 2 HTML templates (no json involved):

  • a full page template - which renders the entire page, and
  • a card template - which returns just an HTML snippet: a <div> formatted as a ‘card’, with basic information to be displayed on the page (eg., card with article image thumbnail, title, author, pub.date, link to article page, etc.)

The idea being, that:

  • if the visitor navigates to “example.com/article”, the server should return the full page to the browser
  • if the browser requests (via ajax) “example.com/article.card”, the server should return just the HTML card snippet (= different content representation of the same article)

A content representation should be a perfect match for this AFAIK.

You’ld need 2 templates:

  1. The default article.php
  2. The specific representation for card: article.card.php

That’s what I thought :+1:

Do I need to set a header with a specific response type? What is the ‘kirby way’ to do that?..

no, just adding .myrepresentation at the end of the URL and be sure there exists a site/templates/mytemplate.php AND site/templates/mytemplate.myrepresentation.php should do the job.

@bvdputte just for curiosity’s sake: do you know how Kirby ‘guesses’ the response content-type - and what content types it knows about internally?

For example, does it guess that the response is going to be ‘application/json’ because of the extension on the template? - eg., “article.json.php” generates an ‘application/json’ response, but if the template is “article.xml.php” it will return a header with content type ‘text/xml’?..

And what does it do with content types that it can’t possibly recognise - like ‘card’? Does it default to ‘text/html’, or do we have to send a specific header, to be sure?..

I’m not sure, my experience with it is either;

  1. Extend an existing template via a content representation
  2. Use it as an argument via the $page->render() function

Maybe it works with headers too? Or it derives them based on the type (e.g. .json will be returned as application/json automagically)? I can only assume if Kirby doesn’t recognize it, it’ll fallback to text/html?

In the docs, I just read that if you set correct headers in the request you could even work without a default controller; but I have no experience with that way of working.

If the representation exists, the template will be loaded and Kirby will send a correct content type header if possible.

You will have to send a content type header manually, if Kirby cannot get the right content type. It probably guesses it from the extension. The default is html.

Thank you @bvdputte and @pixelijn!

I’ve done some code archaeology, and found that Kirby has a Mime Class, which has quite a long list of content-types it recognises, and a couple of different methods to try and ‘guess’ a file’s type (eg., based on its extension and/or content).

In the case of our content representations, it seems Kirby will use the extension of the template to send the appropriate header - using the built-in list from the Mime class. So, if we name our template “article.yaml.php”, “article.json.php”, “article.html.php”, etc., using any of the common extensions listed there, we should be right: no need to set specific headers.

But if we use a content type not on the list - eg., “article.card.php”, “article.listing.php”, “article.hash.php” - then Kirby will assume the content-type to be “text/html”. If we want/need to set a specific content-type, we can do it as described here in the docs. For example, if our ‘article.hash.php’ template is returning ‘plain text’, we could implement it like this:

<?php

$kirby->response()->type('text/plain');
// code to generate article hash:
// $hash = ...

echo $hash;

Once again, many thanks for the guidance, guys!

@texnixe it might be helpful to have a link in the content representation docs to the section of the docs that talks about setting representation types - it’s all pretty easy, once you find it! :wink:

4 Likes

:white_check_mark:

1 Like

Related to the HTMX use case, what would be a nice way to get HTML partials that are not based on a single page’s content, but are freely structured according to one’s needs? Virtual pages maybe?