# Views and Templates

https://dev.wisecp.com/es/views-and-templates

A controller collects named values and hands them to the view with a template name. The template reads those names as variables and prints the page.

## Overview

Producing a page takes two calls. `chose()` picks the template directory; `render()` runs a template inside it with the data collected so far. The data arrives in the template as ordinary variables named after the keys, so a template never fetches anything for itself.

The admin panel's templates are plain PHP and ship with the product. The website's are a theme's, and the same call selects the active theme instead of a fixed directory.

## Reference

### Signatures

All five are instance methods. Inside a controller the instance is `$this->view`; anywhere else it is the singleton `View::$init`.

```php
public function chose($dir, $noTemplate = false): self;
public function render($_name = null, $data = [], $return_output = false, $source = false): mixed;

public function get_template_dir($type = 'website'): string;   // TEMPLATE_DIR . $type . DS
public function get_template_url($type = 'website'): string;   // APP_URI . "/templates/{$type}/"
public function get_resources_url($str = '', $l_slash = true, $r_slash = false): string;
```

### The Four Parameters of `render()`

- **$_name**: Template path relative to the chosen directory, **without** the extension: `'widgets/list'` resolves to `templates/admin/widgets/list.php`. A missing file returns an empty string rather than raising.
- **$data**: Key/value map extracted into variables before the template runs. Pass the controller's collected data, `$this->data`. Anything that is not an array is treated as empty.
- **$return_output**: `false` prints the markup and returns an empty string; `true` returns it instead. A page method returns its page, so it passes `true`.
- **$source**: `true` includes the file and hands back **the value the file returns**, printing nothing. This is how a template that is really a data file (a returned array) is read. `false` when the file is missing.

### What chose() Accepts

| Argument | Resolves to | When |
| --- | --- | --- |
| `'admin'` | `templates/admin/`, plain PHP | Every admin screen |
| `'website'` | The active theme's directory and engine | A visitor request. In an admin or cron context this falls back to `templates/website/` as plain PHP |
| `'system'` | `templates/system/`, plain PHP | Fatal error, maintenance, invoice document |
| any path with `$noTemplate = true` | The path exactly as given | A module using its own template directory |

### How Data Reaches a Template

Values added by the controller are extracted into variables before the template runs. A value added under the name `rows` is read as `$rows`. On top of those, the view adds five of its own to every call:

- **$template_dir**: Filesystem path of the chosen directory, with a trailing separator. This is what lets one template include another without knowing where it lives.
- **$ui_lang**: The language resolved for this request, e.g. `'en'`. Only set when the controller did not already supply it.
- **$ui_dir**: Writing direction for that language, `'ltr'` or `'rtl'`. Print it on the root element; never hard-code a direction.
- **$badress, $tadress, $sadress**: Base address of the installation, of the chosen template directory, and of the shared resources directory. Use them for asset links instead of composing URLs by hand.
- **$setting**: Themed website pages only: the active theme's merged settings, schema defaults included. Absent in admin and system templates.

## Example

The two halves together: the controller names the values, the template reads those exact names back.

```php
public function page_list(&$links, &$meta, &$breadcrumbs): string
{
    $this->addData('rows', $this->model->list());
    $this->addData('total', $this->model->list(true));

    // Third argument true: return the markup instead of printing it, because the
    // page method's job is to RETURN the rendered page.
    return $this->view->chose('admin')->render('widgets/list', $this->data, true);
}
```

```php
<?php if (!defined("CORE_DIR")) exit(); ?>

<h1><?= Language::g("widgets-title") ?> (<?= (int) ($total ?? 0) ?>)</h1>

<?php foreach (($rows ?? []) as $row): ?>
    <div class="card">
        <span><?= htmlspecialchars($row['name'] ?? '') ?></span>
    </div>
<?php endforeach; ?>

<?php include $template_dir . "inc" . DS . "footer.php"; ?>
```

Reading a template that returns data instead of printing it, and producing a theme view from a background job:

```php
// $source = true: the file's own return value comes back, nothing is printed.
$columns = View::$init->chose('admin')->render('tables/widgetList', [], false, true);

// Outside a visitor request (cron, mail, PDF) the theme is NOT resolved by chose('website').
// Ask the theme itself, which resolves engine and directory regardless of context.
$html = Theme::active()->render('account/invoice-pdf', ['invoice' => $invoice]);
```

## Pitfalls

> **Escape everything a person typed**
> 
> An admin template is plain PHP with no automatic escaping. A value that came from a form, an API or a remote provider appears exactly as it arrived. Escaping it is your job.

> **A background job cannot select the theme with chose('website')**
> 
> Theme resolution is skipped outside a visitor request, so the call falls back to plain PHP. It looks for a `.php` file the theme does not have and returns an **empty string with no error**. Produce the view through the theme object instead.

> **A template refuses to be entered directly**
> 
> Every template starts by exiting when the application's constants are absent. Without that line the file is a URL that runs part of a page with no session, no permissions and no data.

> **Read every key with a default**
> 
> A missing key inside a loop raises one warning per row, and each warning is a disk write. In a list template that is the difference between a fast page and a slow one.

## Related Articles

- [Controllers and Routing](https://dev.wisecp.com/en/controllers-and-routing)
- [Interface Components](https://dev.wisecp.com/en/interface-components)
- [Template Variables](https://dev.wisecp.com/en/template-variables)
- [Error Handling](https://dev.wisecp.com/en/error-handling)
