How-to library · Developer docs

How-to library

Task-shaped pages: a title that starts with a verb, the situation in a few lines, the steps, the working code in both engines, and why this way rather than another. Found from a search, done, and left.

Share a partial between several page types

Put the fragment in includes/, pass what it needs by name, and never let it read the page's record directly, because the record arrives under a different name on every page type. Document its inputs at the top.

Context

Context. A card, a call to action, a share bar: the same fragment on pages, posts and products. The record arrives under a different name on each (page, post, product), and an included partial sees the caller's variables, so a partial that reads $page works on pages and breaks everywhere else. Pass the record under a name of your choosing and read only that.

Steps

  1. Create the partial under templates/includes/ and start it with a comment listing every variable it expects.
  2. Read only the variables you were passed; give optional ones a default.
  3. Include it from each page type, passing the record under the agreed name. In Twig, isolate it with only if you want to be sure it reads nothing else.

Template code

Template code
{* templates/includes/share-bar.html
   @param mixed  $item   required  any record with getFullPath() and getName()
   @param string $label  optional  default 'Share' *}
{$label = $label|default:'Share'}
{$url = $_request->getSchemeAndHost()|cat:$item->getFullPath()}
<div class="share">{$label|escape}:
  <a href="https://www.linkedin.com/sharing/share-offsite/?url={$url|escape:'url'}">LinkedIn</a>
  <a href="mailto:?subject={$item->getName()|escape:'url'}&body={$url|escape:'url'}">Email</a>
</div>

{* on a page template *}
{include 'includes/share-bar.html' item=$page}
{* on a post template *}
{include 'includes/share-bar.html' item=$post label='Share this post'}
{# templates/includes/share-bar.html
   @param item   required  any record with getFullPath() and getName()
   @param label  optional  default 'Share' #}
{% set label = label|default('Share') %}
{% set url = _request.getSchemeAndHost() ~ item.getFullPath() %}
<div class="share">{{ label|e }}:
  <a href="https://www.linkedin.com/sharing/share-offsite/?url={{ url|url_encode }}">LinkedIn</a>
  <a href="mailto:?subject={{ item.getName()|url_encode }}&body={{ url|url_encode }}">Email</a>
</div>

{# on a page template #}
{{ include('includes/share-bar.html', {item: page}, with_context = false) }}
{# on a post template #}
{{ include('includes/share-bar.html', {item: post, label: 'Share this post'}, with_context = false) }}

Why this and not that

Not reading $record: it is set on every record page, so it is tempting, but it is not set inside a component or a listing loop, and a partial that works in three places and fails in the fourth is worse than one that always needs its input. Not a component: a component is content an author places; a partial is markup a developer reuses. In Smarty, a partial always sees the caller's variables, so a variable it was not passed can arrive by accident from the caller; the explicit parameter and the comment are the defence.

Go deeper

Was this page helpful?

Your answer goes to the docs team.