wordcamp cantabria - código mantenible con wordpress

38
Código mantenible con WordPress Asier Marqués @asiermarques

Upload: asier-marques

Post on 17-Feb-2017

972 views

Category:

Technology


0 download

TRANSCRIPT

Código mantenible con WordPress

Asier Marqués @asiermarques

De qué va esta charla

Abrir perspectiva sobre buenas prácticas de desarrollo sobre este CMS

Mostrar código mantenible, cercano al que crearíamos con Symfony2, Silex o Laravel

/meAsier Marqués

simettric.com & 4visionshq.com

linkedin.com/in/asier

@asiermarques

Qué buscamos

• Reutilizar código

• Reutilizar código fuera de WordPress

• Una buena estructura de código

• Que el código sea testable

Tres pilares

• Modelo Vista Controlador

• Inyección de dependencias

• Twig como motor de templates

Inyección de dependencias

¿Por qué?

HTTP vs

WP_Query

Request y ejecución1. Se recibe la petición HTTP

2. El sistema de routing hace el match de la ruta que coincida con la url de la petición

3. Se crea el objeto WP_Query y las query_vars

4. En base al WP_Query se localiza el template

5. Se retorna el resultado

http://codex.wordpress.org/Plugin_API/Action_Reference

Request y ejecución

1. /category/animales = index.php?category=animales

2. new WP_Query( array( “category” => “animales”) );

3. theme/category.php

Inyección de dependenciasNos permite hacer más portable y desacoplado nuestro código.

• Pimple

• Symfony Dependency Injection

Inyección de dependencias

$container[“blog.repository”] = function ($c) use ($wp_query){

return new WP_BlogRepository( $wp_query );

};

$container[“blog.model”] = function($c){

return new BlogModel( $c[“blog.repository”] );

}

class WP_BlogRepository implements RepositoryInterface {

private $query;

function __construct( WP_Query $wp_query ){

$this->query = $wp_query;

}

function getPosts($page=1, $limit=20){

$this->query->query_vars = array( “paged”=>$page, “posts_per_page” => $limit

);

return $this->query->get_posts();

}

}

class MongoDB_BlogRepository implements RepositoryInterface {

[…]

function getPosts($page=1, $limit=20){

$posts = array();

[…]

return $posts;

}

}

class BlogModel {

private $_repository;

function __construct( RepositoryInterface $adapter ){

$this->_repository = $adapter;

}

function getPosts($page, $limit=20){

return $this->_repository->getPosts($page, $limit);

}

}

$model = $container[“blog.model”];

$posts = $model->getPosts();

¿MVC? ¿Twig?

Rutas

task_filter:path: /task/{category}/{custom}controller: TaskController::filterAction

task_detail:path: /task/{id}controller: TaskController::detailAction

Rutas en WordPressadd_action('init', function() {

add_rewrite_rule(

‘^tasks/([^/]*)/([^/]*)/?’,

’index.php?post_type=“task”&category=$matches[1]&custom=$matches[2]',

‘top'

);

       add_rewrite_tag('%custom%', '(([^/]*))');

});

Rutas en WordPressAl crear la WP_Query, se incluyen los anteriores parámetros:

$wp_query->query_vars[“post_type”]

$wp_query->query_vars[“category”]

$wp_query->query_vars[“custom”]

task_filter:path: /task/{category}/{custom}controller: TaskController::filterAction

task_detail:path: /task/{id}controller: TaskController::detailAction

function addRoute($name, $path, $controller_name){

\preg_match_all(‘({\w+})’, $path, $found_params);

$found_params = isset($found_params[0]) && is_array($found_params[0]) ?

$found_params[0] : array();

$url_params = array();

$regexp = $path;

foreach($found_params as $i=>$_param){

$_key = str_replace(array(“{“,”}”), “”, $_param);

$regexp = str_replace($_param, ‘(\w+)’, $regexp);

$url_params[$_key] = ‘$matches[‘.($i+1).’]’;

}

$regexp = ‘^’ . $regexp . ‘$’;

$url = “index.php?” . http_build_query($params, ‘’, “&”);

$url = urldecode($url);

\add_rewrite_rule($regexp, $url, ’top’);

Controlador

Loop personalizadofunction replaceQuery( WP_Query $wp_query ){

if( $wp_query->is_front_page() ){

//cambiamos el loop de la portada$wp_query = new WP_Query(array( “category” => 1 ));

//evitamos un loop infinitoremove_action(“replaceQuery”);

}

};

add_action(“pre_get_posts”, “replaceQuery”);

En el action parse_queryfunction match($wp_query){

if(isset($wp_query->query_vars[“__action”])) {

list( $controller_class, $controller_action ) = explode( “::”, $wp_query->query_vars[“__action”] );

$controller = new $controller_class($this->_container);

$callable = array( $controller, $controller_action );

call_user_func($callable, $wp_query); }

}

Vista

Templates personalizadasadd_filter( 'template_include', function ( $template ) {

if ( is_page( get_option(“landing_page_id”) ) ) {

$template = __DIR__ . “/Templates/landing.php“;

}

return $template;

}

En un controladorclass BlogController extends BaseController{

function indexAction( Request $request, Container $container ) {

$model = $container->get( “blog.model” );

$page = $request->get(“page”, 1);

return $this->render(“blog/posts.php”, array(

“posts” => $model->getPosts( $page );

));

}

}

Render con filtroclass BaseController{

private $container;

function render( $template, $params=array() ){

add_filter( “template_include” , function() use ($template){

[…]

});

}

En un controladorclass BlogController extends BaseController{

function indexAction( Request $request, Container $container ) {

$model = $container->get( “blog.model” );

$page = $request->get(“page”, 1);

return $this->render(“blog/index.html.twig”, array(

“posts” => $model->getPosts( $page );

));

}

}

Twigclass BaseController{

private $container;

function render( $template, $params=array() ){

$twig = $container->get(“twig”);

$html = $twig->render( $template, $params );

wp_die( $html );

}

}

Herramientas

• Gestión de librerías: composer

• Inyección de dependencias: Symfony o Pimple

• Configuración: Yaml y Configuration Component

• Templates: Twig

Un par de cosas más

ComposerWordPress no ofrece gestión de librerías ni componentes por Composer

Por suerte existe el proyecto wpackagist.org

TDDWordPress test framework:

https://github.com/nb/wordpress-tests.git

WP Mock

https://github.com/10up/wp_mock

http://slides.com/jlopezmo/test-driven-development-in-wordpress

//Code is poetry

Gracias.

¿Preguntas?

Asier Marqués @asiermarques [email protected]