49
Conociendo Bolt CMS Asier Marqués @asiermarques

Introducción a Bolt

Embed Size (px)

Citation preview

Conociendo Bolt CMSAsier Marqués @asiermarques

Sobre míAsier Marqués @asiermarques linkedin/in/asier

Demo

Content Types

Content Typesnews: name: News singular_name: NewsItem slug: news singular_slug: news-detail fields: title: type: text class: large slug: type: slug uses: title image: type: image text: type: html height: 300px record_template: newsitem.twig listing_template: news.twig

Relacionesnews: name: News singular_name: NewsItem fields: [..] relations: authors: multiple: false label: Select an author order: -id [..]

Taxonomías

• Tags

• Categories

• Grouping

Taxonomías

tipo_motor: slug: tipo-motores singular_slug: tipo-motor behaves_like: grouping options: [ diesel, gasolina ]

Taxonomías

{% if record.taxonomy.tags is defined %} {% for tag in record.taxonomy.tags %} {{ tag }}<br> {% endfor %}{% endif %}

Menús

Menús

main: - label: Inicio title: Etiqueta title del menú path: homepage class: first - path: entry/1 label: Artículo destacado submenu: - […]

Menús

{{ menu('foo', '_menu_foo.twig') }}

Rutas

Rutas por defecto

• /{content-type-plural} -> listado de contenidos

• /{content-type-singular}/{slug} -> detalle de contenido

Rutas por defecto/libros -> listado de contenidos de tipo libro

1. Si está configurado un archivo twig en el listing_template para ese tipo de contenido, se usa este.

2. Si no, buscará el archivo libros.twig por convención

3. Si no, se buscará el parámetro listing_template en la configuración general del config.yml.

4. Si no ha encontrado nada de lo anterior, utilizará el archivo listing.twig.

Personalizando rutasLas rutas por defecto para las páginas serían:

/pages/{slug_de_la_página}

Para que sean solamente el /slug_de_la_página configuraríamos en el routing:

ruta_de_páginas: path: /{slug_de_la_página} defaults: _controller: ‘Bolt\Controllers\Frontend::record' contenttypeslug: 'page' contenttype: pages

Rutas personalizadasnombre_de_la_ruta:

path: /{parameter}/

defaults:

_controller: ‘Controlador::método’

_before: 'before' # optional

_after: 'after' # optional

requirements:

parameter: required-regexp

host: hostname # optional

contenttype: contenttype # optional

Controladores por defecto

• Bolt\Controllers\Frontend::record

• Bolt\Controllers\Frontend::template

Frontend::templatepagina_estatica:

path: /about

defaults:

_controller: 'Bolt\Controllers\Frontend::template',

template: 'about'

Templates

{% include '_header.twig' %}

<article>

<h1><a href="{{ content.link }}">{{ content.title }}</a></h1>

{% if content.image!="" %}

<img src="{{ content.image|thumbnail(320, 240) }}">

{% endif %}

{{ content.body }}

Posted by {{ content.user.displayname }}

on {{ content.datecreated|date("M d, ’y")}}

</article>

{% include '_footer.twig' %}

{% for content in records %}

<h1><a href="{{ content.link }}">{{ content.title }}</a></h1>

{{ page.video.responsive }}

{{ page.geolocation.latitude }},{{ page.geolocation.longitude }}

{% for content_related in content.related_contents %}

<h2>{{content_related.title}}</h2>

{% endfor %}

{% endfor %}

{% for content in records %}

<h1><a href="{{ content.link }}">{{ content.title }}</a></h1>

{% for image in content.slider %}

<a href="{{ image.filename|image }}">

<img src="{{ image.filename|thumbnail(100,100) }}">

</a>

{% endfor %}

{% endfor %}

Malas prácticasRecuperar una página:

{% setcontent about = 'page/about' %}

{{ about.title }}

Recuperar las 4 últimas entradas de un contenido:

{% setcontent records = 'books/latest/5' %}

Live editor

Live Editor

En la configuración se activa con:

liveeditor: true

En Twig basta con indicar de esta forma <h1 data-bolt-field=“title"> {{ record.title }}</h1>

Extensiones

Crear extensión

Las extensiones se basan son personalizaciones del Bolt Extension Starter https://github.com/bolt/bolt-extension-starter

composer create-project --no-install bolt/bolt-extension-starter <extensión>

namespace Bolt\Extension\YourName\ExtensionName;use Bolt\Application;use Bolt\BaseExtension;class Extension extends BaseExtension{ public function initialize() { $this->addCss('assets/extension.css'); $this->addJavascript('assets/start.js', true);

} public function getName() { return "ExtensionName"; }}

Añadir un filtro para twigfunction initialize(){ $this->addTwigFunction(

'EUR2USD', 'convertEuroToUSD'

);

}

//en twig

{{ number|EUR2USD }}

Añadir un html a la vistafunction initialize(){

$this->addSnippet('endofbody', '<!-- un código HTML -->'

);

}

Añadir un html a la vistastartofhead - after the <head>-tag.

aftermeta - after the last <meta [..] >-tag.

aftercss - after the last <link [..] >-tag.

beforejs - before the first <script [..] >-tag.

afterjs - after the last <script [..] >-tag.

endofhead - before the </head>-tag.

startofbody - after the <body>-tag.

endofbody - before the </body>-tag.

endofhtml - before the </html>-tag.

afterhtml - after the </html>-tag.

Eventos

preSave

postSave

preDelete

postDelete

Eventos$app[‘dispatcher']->addListener(

\Bolt\Events\StorageEvents::POST_SAVE,

‘postSaveCallback'

);

function postSaveCallback(\Bolt\Events\StorageEvent $event){

$id = $event->getId();

invalidarCache( $id );

}

Field Types

Crear un nuevo Field Type

class Extension extends BaseExtension{

public function __construct(Application $app) { parent::__construct($app);

$this->app[‘config']->getFields()->addField( new ColourPickField() );

if ($this->app['config']->getWhichEnd()=='backend') { $this->app['htmlsnippets'] = true; $this->app['twig.loader.filesystem']->prependPath(__DIR__."/twig"); }

}

public function initialize() { $this->addCss('assets/colourpicker.css'); $this->addJavascript('assets/colourpicker.js', true); }

public function getName() { return "colourpicker"; }

}

class ColourPickField implements FieldInterface{

public function getName() { return 'colourpicker'; }

public function getTemplate() { return '_colourpicker.twig'; }

public function getStorageType() { return 'text'; }

public function getStorageOptions() { return array('default'=>''); }

}

{% set attr_opt = { class: field.class|default(''), name_id: key, required: field.required|default(false), readonly: field.readonly|default(false)}%}

<fieldset class="colourpicker"> <div class="col-sm-12"> <div> <label class="control-label">{{field.label|default(key)}}</label> </div> <select data-colourpicker {{ macro.attr(attr_opt) }}> {% for key, value in field.values %}

{% set isSelected = (key == context.content.get(key|capitalize)) %}

<option value=“{{key}}" {% if isSelected %} selected="selected"{% endif %}> {{value}} </option>

{% endfor %} </select> </div></fieldset>

content_type: type: colourpicker label: “Elige un color" values: "#000": Negro "#E1E1E1": Gris claro "#444": Gris "#FF0011": Rojo

Crear un nuevo Field Type

Servicios internos

Servicios internos

• $app[‘db’] -> Doctrine DBAL

• $app[‘mailer’] -> SwifMailer

• $app[‘logger.system’] -> Monolog

• $app[‘twig’]

Servicios internos

• $app[‘config']

• {{ dump(config.get('general/homepage_template')) }}

• $app[‘config']->get('general/homepage_template')

• $app[‘users’]

• Bolt/Users.php (Modelo de Usuarios)

i18n

i18n e i10n

• La i18n del contenido no se soporta por defecto :(

• La i18n de la interfaz se consigue con una extensión llamada labels https://github.com/bolt/labels

Asier Marqués@asiermarques linkedin.com/in/asier

Gracias!