7.8 KiB
Hooks & Server-Side API
Hooks
Hooks are PHP files in the hooks/ directory that execute server-side logic. They can also live inside a module at template/estandar/modulos/<module-id>/hook.php.
Testing Hooks
To test hooks, the site's Docker container must be running. Make a curl request to the Docker URL with the hook path. For example, if a hook is named hooks.example_hook.php:
curl http://{DOCKER_URL_AND_PORT}/hooks/example_hook/
Replace {DOCKER_URL_AND_PORT} with your local Docker address (e.g., localhost:8080) and parse hook name for url endpoint.
Do not use X-Hooks-Token because its not needed on developer environment.
How to Call Hooks
From Twig:
{{ 'hooks/module_id/' | hook({param1: 'value1', param2: variable}) }}
From HTML (with result):
<hook result="myVar" endpoint="/hooks/module_id/" :param1="value1" :param2="'string'"></hook>
<p>{{ myVar }}</p>
From JavaScript:
CmsApi.hook('/hooks/module_id/', { param1: 'value1' }, function(response) {
console.log(response);
});
From c-form: Hooks are automatically triggered on form submission when configured.
Hook Parameters
Parameters are received as PHP variables:
<?php
// Called with: 'hooks/my_hook/' | hook({category: 'electronics', limit: 10})
// Available as:
$category; // 'electronics'
$limit; // 10
Hook Return Values
Hooks can echo or return values. When called from Twig or <hook> tag, the output is captured into the result variable.
CmsApi (PHP)
Server-side API for database operations. Available in all hooks.
Read Records
// Get all records
$products = CmsApi::get('productos');
// With WHERE condition
$active = CmsApi::get('productos', ['active' => 1]);
// With order and limit
$latest = CmsApi::get('noticias', [], 'fecha DESC', 5);
// With operators
$expensive = CmsApi::get('productos', ['precio' => ['>=' => 100]]);
$search = CmsApi::get('productos', ['nombre' => ['LIKE' => '%keyword%']]);
$inList = CmsApi::get('productos', ['categoria_num' => ['IN' => [1, 2, 3]]]);
Insert Records
$newRecord = CmsApi::insert('contacto', [
'nombre' => 'John',
'email' => 'john@example.com',
'mensaje' => 'Hello',
]);
Update Records
CmsApi::update('productos',
['precio' => 29.99, 'activo' => 1], // fields to update
['num' => 42] // where condition
);
Delete Records
CmsApi::delete('productos', ['num' => 42]);
Important Rules
- Table names without
cms_prefix - Primary key is always
num, neverid - Upload fields are handled separately (not via insert/update)
- Operators:
=,!=,>,>=,<,<=,LIKE,IN
CmsApi (JavaScript — Client-Side)
// Hook call
CmsApi.hook('/hooks/module_id/', { param: 'value' }, function(response) {
// response is the hook output
});
// Record operations (if exposed via hooks)
CmsApi.get('tableName', { where: conditions }, function(records) {
// records array
});
CocoDB
Low-level database abstraction layer used internally by CmsApi. Use directly from hooks when you need more control.
CocoDB::get($table, $where, $order, $limit, $options)
Reads records from a table. This is the same method CmsApi::get wraps.
// Basic query
$records = CocoDB::get('productos', ['activo' => 1], 'orden ASC', 10);
// With advanced where (array syntax for operators)
$records = CocoDB::get('productos', [
['column' => 'precio', 'value' => 100, 'operator' => '>='],
['column' => 'categoria_num', 'value' => [1, 2, 3], 'operator' => 'IN'],
]);
// OR conditions
$records = CocoDB::get('productos', [
['column' => 'nombre', 'value' => '%keyword%', 'operator' => 'LIKE'],
['column' => 'descripcion', 'value' => '%keyword%', 'operator' => 'LIKE', 'or' => true],
]);
// NOT condition
$records = CocoDB::get('productos', [
['column' => 'estado', 'value' => 'borrador', 'operator' => '=', 'not' => true],
]);
// IS NULL
$records = CocoDB::get('productos', [
['column' => 'fecha_baja', 'value' => '', 'operator' => 'IS NULL'],
]);
// Limit with offset
$records = CocoDB::get('productos', [], 'num DESC', ['limit' => 10, 'offset' => 20]);
Options for get()
| Option | Type | Default | Description |
|---|---|---|---|
uploads |
bool | true |
Include upload field data |
relations |
bool/array | true |
Resolve foreign key relations. Pass array to limit: ['category'] |
relationsDepth |
int | 2 | Depth of nested relation resolution |
translates |
string | current lang | Language code for translations |
groupBy |
string | null | GROUP BY clause |
aggregates |
array | [] |
Aggregate functions |
onlyFields |
array | null | Select specific fields only |
debug |
bool | false | Output SQL query for debugging |
redis |
bool | null | Force Redis cache |
redis_expire |
int | 60 | Redis cache TTL in seconds |
CocoDB::insertRecords($table, $records, $functions, $options)
Insert one or multiple records.
// Single record
$count = CocoDB::insertRecords('contacto', [
'nombre' => 'John',
'email' => 'john@example.com',
]);
// Returns number of inserted records. Use mysql_insert_id() to get the new num.
// Multiple records
$count = CocoDB::insertRecords('productos', [
['nombre' => 'Product A', 'precio' => 10],
['nombre' => 'Product B', 'precio' => 20],
]);
Options for insert/update
| Option | Description |
|---|---|
forceNum |
Allow setting the num field manually |
ignoreSchema |
Skip schema validation |
ignoreFields |
Array of field names to skip |
CocoDB::updateRecords($table, $records, $where, $functions, $options)
Update records matching a where condition.
CocoDB::updateRecords('productos',
['precio' => 29.99, 'activo' => 1], // fields to update
['num' => 42] // where condition
);
// With operator in where
CocoDB::updateRecords('productos',
['activo' => 0],
[['column' => 'stock', 'value' => 0, 'operator' => '<=']]
);
CocoDB::deleteRecords($table, $where, $options)
Delete records matching a where condition.
CocoDB::deleteRecords('productos', ['num' => 42]);
// With operator
CocoDB::deleteRecords('logs', [
['column' => 'fecha', 'value' => '2024-01-01', 'operator' => '<']
]);
Where Clause Syntax
The $where parameter supports two formats:
Simple (key-value):
['campo' => 'valor'] // campo = 'valor'
Advanced (array of conditions):
[
'column' => 'field_name', // Required
'value' => 'match_value', // Required
'operator' => '=', // =, !=, <, >, <=, >=, LIKE, IN, IS NULL
'or' => false, // Use OR instead of AND
'not' => false, // Negate the condition
'raw_key' => false, // Skip column existence check
]
Functions Parameter
The $functions parameter lets you apply MySQL functions to values during insert/update:
CocoDB::insertRecords('logs', [
'mensaje' => 'Login exitoso',
'fecha' => '',
], [
'fecha' => 'NOW()', // Will use MySQL NOW() instead of the value
]);
Table Schemas
Table schemas are stored as JSON in cms/data/schema/. Each file defines:
- Field names and types
- Validation rules
- Relationships (foreign keys)
- Display configuration
Field Format Types
| Type | PHP Format | Notes |
|---|---|---|
| Text | String | Plain text |
| Date/time | YYYY-MM-DD HH:mm:ss |
MySQL datetime format |
| Checkbox | 1 or 0 |
Boolean as integer |
| WYSIWYG | HTML string | Rich text with Tailwind classes |
| List | String or num | Foreign key if linked to table |
| Multivalores | JSON string | Serialized array |
| Upload | — | Handled separately, never in insert/update |