Skip to content

Commit 1a7abe0

Browse files
committed
docs(tutorial): address 8 review findings
- Show explicit ExtensionRegistry setup instead of claiming auto-registration - Document generate_canonical_url requires XOOPS_URL (no HTTP_HOST fallback) - Fix xo_module_url example to show full URL when XOOPS_URL is set - Add base64_encode_file section with web-root restriction note - Add HTML-output warnings for nl2p, highlight_text, linkify, breadcrumbs, pagination, and render_alert (avoid double-escaping) - Add defensive <{if}> patterns for functions that return empty: parse_url, canonical URL, embed_pdf, session data, avatar - Rewrite hashing section: checksums only, not passwords; drop md5 example - Add xo_render_block example with block interface note
1 parent c74ddea commit 1a7abe0

1 file changed

Lines changed: 105 additions & 13 deletions

File tree

docs/TUTORIAL.md

Lines changed: 105 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,37 @@ This tutorial walks through practical usage of each extension in XOOPS templates
1919

2020
## Getting Started
2121

22-
The extensions are registered automatically by the XOOPS bootstrap. Once loaded, all plugins are available in every `.tpl` template.
22+
### Registration
23+
24+
Extensions must be registered with your Smarty instance before they can be used in templates. In a standalone setup, do this explicitly:
25+
26+
```php
27+
use Xoops\SmartyExtensions\ExtensionRegistry;
28+
use Xoops\SmartyExtensions\Extension\TextExtension;
29+
use Xoops\SmartyExtensions\Extension\FormatExtension;
30+
use Xoops\SmartyExtensions\Extension\NavigationExtension;
31+
use Xoops\SmartyExtensions\Extension\DataExtension;
32+
use Xoops\SmartyExtensions\Extension\SecurityExtension;
33+
use Xoops\SmartyExtensions\Extension\FormExtension;
34+
use Xoops\SmartyExtensions\Extension\XoopsCoreExtension;
35+
use Xoops\SmartyExtensions\Extension\RayDebugExtension;
36+
37+
$registry = new ExtensionRegistry();
38+
$registry->add(new TextExtension());
39+
$registry->add(new FormatExtension());
40+
$registry->add(new NavigationExtension());
41+
$registry->add(new DataExtension());
42+
$registry->add(new SecurityExtension($xoopsSecurity, $grouppermHandler));
43+
$registry->add(new FormExtension($xoopsSecurity));
44+
$registry->add(new XoopsCoreExtension());
45+
$registry->add(new RayDebugExtension());
46+
47+
$registry->registerAll($smarty);
48+
```
49+
50+
If XOOPS Core performs this registration in its bootstrap, all plugins will be available in every `.tpl` template without any additional setup in your module code.
51+
52+
### Plugin types
2353

2454
There are three types of Smarty plugins:
2555

@@ -64,7 +94,9 @@ Use `truncate_words` to limit by word count:
6494

6595
### Converting newlines to paragraphs
6696

67-
The `nl2p` modifier converts double newlines into `<p>` tags and single newlines into `<br>`:
97+
The `nl2p` modifier converts double newlines into `<p>` tags and single newlines into `<br>`.
98+
99+
> **HTML output warning**: `nl2p` returns raw HTML markup. The input is not escaped, so pass only trusted or pre-sanitized content. Do not apply `|escape` after `nl2p` or the tags will be visible as text.
68100
69101
```smarty
70102
<{$userBio|nl2p}>
@@ -75,6 +107,8 @@ Output: `<p>First paragraph.</p><p>Second paragraph.<br>With a line break.</p>`
75107

76108
### Highlighting search terms
77109

110+
> **HTML output warning**: `highlight_text` wraps matches in `<span>` tags and returns raw HTML. Ensure the source text is already escaped or trusted. Do not apply `|escape` after this modifier.
111+
78112
```smarty
79113
<{* Wrap matches in <span class="highlight"> *}>
80114
<{$article.title|highlight_text:$searchQuery}>
@@ -229,11 +263,13 @@ NavigationExtension provides URL manipulation, breadcrumbs, pagination, and soci
229263

230264
### Canonical URLs
231265

232-
Builds a full URL using `XOOPS_URL`:
266+
Builds a full URL by prepending `XOOPS_URL`. Returns an empty string if `XOOPS_URL` is not defined (it will not fall back to `HTTP_HOST` to prevent host-header poisoning). Always check the result before using it:
233267

234268
```smarty
235269
<{generate_canonical_url path="modules/news/article.php?id=42" assign="canonical"}>
236-
<link rel="canonical" href="<{$canonical}>">
270+
<{if $canonical}>
271+
<link rel="canonical" href="<{$canonical}>">
272+
<{/if}>
237273
```
238274

239275
### URL segments
@@ -263,6 +299,8 @@ Works with `youtube.com/watch?v=`, `youtu.be/`, `youtube.com/embed/`, and `youtu
263299

264300
### Making URLs clickable
265301

302+
> **HTML output warning**: `linkify` returns raw HTML with `<a>` tags. The surrounding text is not escaped. Pass only trusted or pre-sanitized content to avoid XSS. Do not apply `|escape` after this modifier.
303+
266304
```smarty
267305
<{$comment.body|linkify}>
268306
```
@@ -279,9 +317,13 @@ Input: `"https://example.com/page"` becomes `example.com/page`
279317

280318
### Parsing URLs
281319

320+
Returns `false` for seriously malformed URLs. Always check before accessing components:
321+
282322
```smarty
283323
<{assign var="parts" value=$url|parse_url}>
284-
Host: <{$parts.host}>, Path: <{$parts.path}>
324+
<{if $parts}>
325+
Host: <{$parts.host}>, Path: <{$parts.path}>
326+
<{/if}>
285327
```
286328

287329
### Social sharing
@@ -303,6 +345,8 @@ Supported platforms: `twitter`, `facebook`, `linkedin`, `reddit`, `email`.
303345

304346
### Breadcrumbs
305347

348+
> **HTML output note**: `render_breadcrumbs`, `render_pagination`, and `render_alert` all return Bootstrap 5 HTML markup. Do not apply `|escape` to their output. Their parameters are escaped internally.
349+
306350
Renders Bootstrap 5 breadcrumb navigation:
307351

308352
```smarty
@@ -390,6 +434,19 @@ Also works with JSON strings (decodes, then re-encodes with formatting).
390434
<{$htmlContent|strip_html_comments}>
391435
```
392436

437+
### Base64-encoding files
438+
439+
Encode a file as a base64 string, for example to inline images in emails or data URIs. For security, this function only reads files under `XOOPS_ROOT_PATH` (or `DOCUMENT_ROOT` outside XOOPS). If neither is set, the function returns an empty string.
440+
441+
```smarty
442+
<{base64_encode_file path=$imagePath assign="b64"}>
443+
<{if $b64}>
444+
<img src="data:image/png;base64,<{$b64}>" alt="Inline image">
445+
<{/if}>
446+
```
447+
448+
Paths that resolve outside the web root are silently rejected.
449+
393450
### CSV generation
394451

395452
```smarty
@@ -398,8 +455,13 @@ Also works with JSON strings (decodes, then re-encodes with formatting).
398455

399456
### Embedding PDFs
400457

458+
Returns an empty string if `url` is empty.
459+
401460
```smarty
402-
<{embed_pdf url="/uploads/report.pdf" width="100%" height="600"}>
461+
<{embed_pdf url=$pdfUrl width="100%" height="600" assign="viewer"}>
462+
<{if $viewer}>
463+
<{$viewer}>
464+
<{/if}>
403465
```
404466

405467
### XML sitemap generation
@@ -425,8 +487,13 @@ Also works with JSON strings (decodes, then re-encodes with formatting).
425487

426488
### Session data
427489

490+
Returns `null` (via `assign`) or an empty string (direct output) if the key does not exist.
491+
428492
```smarty
429493
<{get_session_data key="user_preference" assign="pref"}>
494+
<{if $pref}>
495+
<p>Your preference: <{$pref|escape}></p>
496+
<{/if}>
430497
```
431498

432499
### HTTP referrer
@@ -593,12 +660,18 @@ Use the `xo_permission` block to conditionally show content:
593660

594661
### Hashing
595662

663+
For checksums, cache keys, and fingerprints. **Not for password storage** — use `password_hash()` in PHP for that.
664+
596665
```smarty
597-
<{$value|hash_string}> <{* Default: SHA-256 *}>
598-
<{$value|hash_string:"md5"}> <{* MD5 *}>
599-
<{$value|hash_string:"sha512"}> <{* SHA-512 *}>
666+
<{* Default: SHA-256 (recommended for most uses) *}>
667+
<{$value|hash_string}>
668+
669+
<{* SHA-512 for stronger fingerprints *}>
670+
<{$value|hash_string:"sha512"}>
600671
```
601672

673+
Any algorithm supported by PHP's `hash_algos()` can be used. Returns an empty string for unrecognized algorithms.
674+
602675
---
603676

604677
## XOOPS Core Helpers
@@ -642,19 +715,25 @@ The returned array contains: `uid`, `uname`, `name`, `email`, `groups`, `is_admi
642715

643716
### Module URLs
644717

718+
Builds a module-relative URL. When `XOOPS_URL` is defined, the output is a full URL; otherwise it starts with `/modules/`.
719+
645720
```smarty
646-
<{xo_module_url module="news" path="article.php" params=$queryParams}>
721+
<{xo_module_url module="news" path="article.php" params=$queryParams assign="articleUrl"}>
722+
<a href="<{$articleUrl}>">Read article</a>
647723
```
648724

649-
Output: `/modules/news/article.php?id=42`
725+
Example output with `XOOPS_URL` = `https://example.com`: `https://example.com/modules/news/article.php?id=42`
650726

651727
### User avatars
652728

729+
Returns an empty string if no avatar can be resolved (no XOOPS avatar and no email for Gravatar). Check when using with `assign`:
730+
653731
```smarty
654732
<{* By user ID (looks up XOOPS avatar, falls back to Gravatar) *}>
655-
<{xo_avatar uid=$userId size=64 class="rounded-circle"}>
733+
<{xo_avatar uid=$userId size=64 class="rounded-circle" assign="avatar"}>
734+
<{if $avatar}><{$avatar}><{/if}>
656735
657-
<{* By email (Gravatar only) *}>
736+
<{* By email (Gravatar only) — direct output *}>
658737
<{xo_avatar email=$userEmail size=48}>
659738
```
660739

@@ -686,6 +765,19 @@ Only renders when XOOPS debug mode is active:
686765

687766
Renders as an expandable `<details>` element with a `<pre>` dump.
688767

768+
### Rendering blocks
769+
770+
Renders a XOOPS block from its options array. This is primarily used by theme templates and the block system; most module developers will not call it directly.
771+
772+
```smarty
773+
<{xo_render_block options=$blockOptions assign="blockHtml"}>
774+
<{if $blockHtml}>
775+
<div class="block-content"><{$blockHtml}></div>
776+
<{/if}>
777+
```
778+
779+
The `options` array must contain a `block` key with a block object that implements a `getContent()` method (the standard XOOPS block interface).
780+
689781
### Module admin menu
690782

691783
```smarty

0 commit comments

Comments
 (0)