Una página normal muestra lo que dice su código. Una página con tipo de plantilla además recibe registros: el producto que nombra su dirección, las categorías de un listado. Esta guía cubre cómo agregar un tipo de plantilla para un modelo tuyo, los datos que recibe cada tipo, los enlaces entre registros y sus páginas, y la pantalla de categorías.
Qué trae el kit
App\Enums\PageTemplate tiene dos casos:
| Caso | Qué es |
|---|---|
Home |
La página que se sirve en /. No recibe datos. |
SomethingCategory |
Un marcador que muestra la forma de un listado de categorías. Apunta a una relación somethings que ningún equipo tiene, así que una página con él responde un error: reemplázalo por uno tuyo antes de publicar. |
Todo lo demás lo agregas tú, un caso por cada tipo de página que tu producto necesita.
Agregar un tipo de plantilla
Nombra el caso por el modelo y el tipo de página: {Model}Detail, {Model}Category, o cualquier otra cosa para una página sin datos:
enum PageTemplate
{
use IsEnum;
case Home;
case ProductDetail;
case ProductCategory;
}
El equipo lo elige en el campo Plantilla de una página. Cada caso lo atiende la clase del mismo nombre en App\Classes\Templates, cuando escribes una, y si no la clase base que indica su sufijo:
| Sufijo | Clase | Slug que impone | Qué recibe la página |
|---|---|---|---|
Detail |
BaseDetail |
Debe contener {slug}; por defecto products/{slug}. |
El registro cuyo slug está en la dirección, como $product. Un slug que no coincide con nada es un 404. |
Category |
BaseCategory |
Debe contener {?slug}; por defecto categories/products/{?slug}. |
$categories, hasta 20 categorías de ese tipo bajo la de la dirección, o las de primer nivel; $category, la de la dirección, buscada por su slug entre todas las categorías del equipo sin importar su tipo —null solo cuando la dirección no trae slug, y un slug que no coincide con ninguna categoría es un 404—; y $products, los registros activos de esa categoría y de sus hijas, o todos los registros activos del tipo cuando la dirección no trae categoría, 20 por página; vacío cuando el equipo no tiene registros de ese tipo que listar. |
| cualquier otro | Base |
Cualquier slug. | Nada. |
El modelo se lee del nombre: ProductDetail lee team()->products(), BlogEntryCategory lee team()->blogEntries(). Así que la relación debe existir en App\Models\Team, y el modelo debería extender App\Models\BaseTeamCrud, que le da el equipo, el slug, el scope active(), la categoría, los campos personalizados y los helpers de URL de abajo.
Cuando cambia el tipo de plantilla de una página, o su slug, el slug se revisa contra el patrón y se reemplaza por el de por defecto si no encaja. Un patrón de detalle también puede usar {id}, {y}, {m} y {d}, que se comparan con el id y la fecha de creación del registro.
Una clase propia
Cuando la clase base no alcanza, escribe App\Classes\Templates\ProductDetail extendiéndola y sobrescribe lo que necesites: getData($params) para las variables, validateSlug() y defaultSlug() para la dirección.
namespace App\Classes\Templates;
class ProductDetail extends BaseDetail
{
public function getData($data = [])
{
$product = team()->products()->active()->where('slug', $data['slug'] ?? null)->firstOrFail();
return [
'product' => $product,
'related' => team()->products()->active()->where('category_id', $product->category_id)->limit(4)->get(),
];
}
}
Enlazar registros y páginas
Un registro de un modelo BaseTeamCrud conoce su propia dirección: $product->url encuentra la página activa ProductDetail del equipo y llena su patrón con el registro, y responde # cuando no hay ninguna. El nombre del tipo de plantilla de esa página se construye a partir del nombre de la tabla, no del modelo: se pasa a singular y a StudlyCase, y se le agrega Detail, así que products da ProductDetail y una tabla de dos palabras, como blog_posts, da BlogPostDetail. Desde cualquier lugar, team()->getLink( 'ProductCategory', ['slug' => 'shoes']) construye la dirección de la página con ese tipo de plantilla, sin la / inicial que sí tiene $product->url (categories/products/shoes); también responde # cuando no hay ninguna.
Categorías
Un equipo mantiene un árbol de categorías por tipo en /team/categories/{type}. La pantalla no tiene entrada en el menú: enlázala desde tus propias pantallas, con el tipo que lee tu listado —el nombre de la relación en plural, products para ProductCategory—:
/team/categories/products
En esa pantalla el equipo crea una categoría con nombre, slug, descripción y una imagen (el campo Imagen admite una), agrega una subcategoría con Agregar subcategoría, sube y baja las de primer nivel, y las edita o las borra. El campo Slug se puede editar; si se deja vacío, el slug se genera a partir del nombre. Es único dentro del equipo y el tipo de categoría. La imagen se guarda en la biblioteca del equipo, en una carpeta propia de cada categoría, Categories/{category id}, al guardar la categoría.
Para crear o editar una categoría:
- Llena Nombre, y Slug si quieres uno propio.
- Agrega una Descripción y una imagen si la categoría las necesita.
- Pulsa Guardar. El formulario se vacía para la siguiente categoría.
Para cambiar una, pulsa su icono de editar; el formulario se llena con ella. Limpiar vacía el formulario y deja la categoría que estabas editando, o la subcategoría que estabas agregando, sin guardar nada.
El icono de borrar pregunta antes de borrar. Un diálogo Borrar categoría nombra la categoría y, cuando tiene subcategorías, dice cuántas se borrarán con ella, contando todos los niveles de abajo. Pulsa Borrar para borrar la categoría junto con todas sus subcategorías; Cancelar, o cerrar el diálogo, deja todo como estaba. Sus imágenes se quedan en la biblioteca del equipo.
La pantalla no revisa ningún permiso propio. Con la facturación por equipo encendida, pide lo mismo que las demás pantallas del sitio —el permiso manage plans y, cuando los planes están activos, una suscripción del equipo—; con la facturación por equipo apagada, cualquier miembro que llegue al espacio de trabajo del equipo puede usarla.
La pantalla muestra tres niveles, y el tercero no tiene Agregar subcategoría. El padre solo se fija con Agregar subcategoría y no se puede cambiar después. El orden de las categorías de primer nivel es común a todos los tipos, así que mover una puede intercambiarla con una de otro tipo y dejar la lista como estaba.
La página de categoría del tema por defecto muestra cada categoría con su propia imagen. Una categoría sin imagen toma la de uno de sus registros, elegido al azar entre los registros de esa categoría y de sus subcategorías que tienen imagen; cuando ninguno tiene, la categoría no muestra imagen, en lugar de una rota.

