Queseo

Search
Close this search box.

Cómo crear un theme para WordPress

Índice del artículo

Diseñar un un template para WordPress parece más difícil de lo que realmente es. Si eres desarrollador front-end y te mueves como pez en el agua con el css, te será bastante fácil.

No soy desarrollador ni diseñador, mi especialidad es el marketing, y este fue el motivo de aprender a desarrollar un theme para WordPress, el optimizar a nivel de velocidad la web.

Ficheros necesarios

Antes que nada, es necesario crear una carpeta a la que pondremos el nombre de nuestro tema. Dentro de este, crearemos una serie de ficheros en blanco que serán:

  • functions.php: aquí se recogen todas las funciones de nuestro tema que interactuarán con nuestro panel de administración
  • sidebar.php: el sidebar va orientado a los plugins de nuestro tema
  • header.php: este fichero será la cabecera que se insertará en todas las páginas. Es donde se cargarán todos los estilos y javascripts
  • index.php: es la página principal de nuestro tema, es decir, la homepage.
  • footer.php: es el fichero que se cargará al final de cada una de las páginas de nuestra web.
  • single.php: este fichero es el encargado de mostrar las páginas de los posts individuales.
  • page.php: este fichero se encarga de mostrar las páginas de nuestro WordPress.
  • style.css: este fichero se encarga de cargar los css de nuestro WordPress

Una vez tengamos todos estos archivos, es necesario introducir un encabezado a todos nuestros archivos completando los datos. Os dejo con un ejemplo de encabezado que podéis copiar y pegar al comenzar todos los ficheros:

/*  
Theme Name: Aquí el nombre de vuestro tema  
Author: Aquí vuestro nombre de autor  
Author URI: vuestra url con info del tema  
Description: descripción del tema  
Version: 1.0  
License: GNU General Public License v3 or later  
License URI: http://www.gnu.org/licenses/gpl-3.0.html  
*/

Después de esto, si subimos la carpeta a nuestro directorio de temas de /wp-content/themes, podremos visualizarla dentro de nuestro activador de temas, en mi caso, llamé al tema theme-wp:

cómo crear theme wordpress
Cómo Crear un Template para WordPress

A pesar de que los ficheros mencionados arriba son los básicos, para este tutorial, agregaré 2 hojas más de estilos:

  • blog.css
  • page.css

Estas hojas de estilo, las usaremos para una carga selectiva de hojas de estilo, donde usaremos el css que más nos interese en función del tipo de página, para limitar la cantidad de código cargado.

functions.php

<?php /*
Theme Name: theme-wp
Author: Queseo
Author URI: http://queseo.es/
Description: My first responsive HTML5 theme
Version: 1.0
License: GNU General Public License v3 or later
License URI: http://www.gnu.org/licenses/gpl-3.0.html
*/

// This function enqueues the Normalize.css for use. 
//The first parameter is a name for the stylesheet, the second is the URL. 
//Here we use an online version of the css file.
function add_normalize_CSS() {
    wp_enqueue_style( 'normalize-styles',
 "https://cdnjs.cloudflare.com/ajax/libs/normalize/7.0.0/normalize.min.css");
}

// Creación de 'sidebar' para insertar widgets
function add_widget_Support() {
                //Sidebar lateral derecho
                register_sidebar( array(
                                'name'          => 'Sidebar',
                                'id'            => 'sidebar',
                                'before_widget' => '<div>',
                                'after_widget'  => '</div>',
                                'before_title'  => '<h3>',
                                'after_title'   => '</h3>',
                ) );
                //Sidebar para footer
                register_sidebar( array(
                                'name'          => 'Footer 1',
                                'id'            => 'footer-1',
                                'before_widget' => '<div class="footer_w1">',
                                'after_widget'  => '</div>',
                                'before_title'  => '<h2>',
                                'after_title'   => '</h2>',
                ) );
                //Sidebar para footer
                register_sidebar( array(
                                'name'          => 'Footer 2',
                                'id'            => 'footer-2',
                                'before_widget' => '<div class="footer_w2">',
                                'after_widget'  => '</div>',
                                'before_title'  => '<h2>',
                                'after_title'   => '</h2>',
                ) );
                //Sidebar para footer
                register_sidebar( array(
                                'name'          => 'Footer 3',
                                'id'            => 'footer-3',
                                'before_widget' => '<div class="footer_w3">',
                                'after_widget'  => '</div>',
                                'before_title'  => '<h2>',
                                'after_title'   => '</h2>',
                ) );
}
// Hook para iniciar el widget y ejecutar nuestra función
add_action( 'widgets_init', 'add_Widget_Support' );

// Crear menús de navegación
function add_Main_Nav() {
// Main menú
  register_nav_menu('header-menu',__( 'Header Menu' ));
// Footer menú
  register_nav_menu('footer-menu',__( 'Footer Menu' ));
}
// Hook para iniciar el menú y ejecutar nuestra función
add_action( 'init', 'add_Main_Nav' );

// thumbnails de las imágenes y tamaños
if ( function_exists( 'add_theme_support' ) )
add_theme_support( 'post-thumbnails' );

// especificación del tamaño de los thumbnails
set_post_thumbnail_size(300, 200);

?>
<?php /*
Theme Name: theme-wp
Author: Queseo
Author URI: http://queseo.es/
Description: My first responsive HTML5 theme
Version: 1.0
License: GNU General Public License v3 or later
License URI: http://www.gnu.org/licenses/gpl-3.0.html
*/
?>

<?php if ( is_active_sidebar( 'sidebar' ) ) : ?>
  <aside id="primary-sidebar" class="primary-sidebar widget-area" role="complementary">
    <?php dynamic_sidebar( 'sidebar' ); ?>
  </aside>
<?php endif; ?>

header.php

<?php /*
Theme Name: theme-wp
Author: Queseo
Author URI: http://queseo.es/
Description: My first responsive HTML5 theme
Version: 1.0
License: GNU General Public License v3 or later
License URI: http://www.gnu.org/licenses/gpl-3.0.html
*/
?>

<!DOCTYPE html>
<html <?php language_attributes(); ?>
 <head>
   <title>
     <?php bloginfo('name'); ?> » <?php is_front_page() ? bloginfo('description') : wp_title(''); ?>
    </title>
   <meta charset="<?php bloginfo( 'charset' ); ?>">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <link rel="stylesheet" href="<?php bloginfo('stylesheet_url'); ?>">
<link href="https://fonts.googleapis.com/css?family=Lato" rel="stylesheet">

   <?php
		if( is_single()):?>
   			<link rel="stylesheet" href="
                        <?php echo esc_url( home_url() ); ?>/wp-content/themes/theme-wp/blog.css">
               <?php ;
		else:?>
			<link rel="stylesheet" href="
                        <?php echo esc_url( home_url() ); ?>/wp-content/themes/theme-wp/pages.css">
        <?php ;
		endif;
	?>
   <?php wp_head(); ?>

 </head>
 <body <?php body_class(); ?>>
    <header class="my-logo">
   		<div class="cont_head">
   			<span>
                           <a href="<?php echo esc_url( home_url( '/' ) ); ?>">
                              <?php bloginfo('name'); ?>
                           </a>
                        </span>
    		<?php wp_nav_menu( array( 'theme_location' => 'header-menu' ) ); ?>
		</div>
 	</header>

index.php

<?php /*
Theme Name: theme-wp
Author: Queseo
Author URI: http://queseo.es/
Description: My first responsive HTML5 theme
Version: 1.0
License: GNU General Public License v3 or later
License URI: http://www.gnu.org/licenses/gpl-3.0.html
*/
?>
<?php get_header(); ?>
<main class="wrap">
  <section class="content-area content-thin">
<?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
      <article class="article-loop">
        <header>
          <h2>
             <a href="<?php the_permalink(); ?>" title="<?php the_title_attribute(); ?>">
                <?php the_title(); ?>
             </a>
</h2>
          <div><?php the_post_thumbnail('medium');?></div>
          <i><?php the_author(); ?></i>
        </header>
        <?php the_excerpt(); ?>
      </article>
<?php endwhile; else : ?>
      <article>
        <p>Sorry, no posts were found!</p>
      </article>
<?php endif; ?>
  </section>
</main>
<?php get_footer(); ?>
<?php /*
Theme Name: theme-wp
Author: Queseo
Author URI: http://queseo.es/
Description: My first responsive HTML5 theme
Version: 1.0
License: GNU General Public License v3 or later
License URI: http://www.gnu.org/licenses/gpl-3.0.html
*/
?>
	<div class="widget-footer">
		<div class="container">
			<?php if ( is_active_sidebar( 'footer-1' ) ) : ?>
			    <?php dynamic_sidebar( 'footer-1' ); ?>
			<?php endif; ?>
			<?php if ( is_active_sidebar( 'footer-2' ) ) : ?>
			    <?php dynamic_sidebar( 'footer-2' ); ?>
			<?php endif; ?>
			<?php if ( is_active_sidebar( 'footer-3' ) ) : ?>
			    <?php dynamic_sidebar( 'footer-3' ); ?>
			<?php endif; ?>		
		</div>
	</div>
	<footer>
    	<?php wp_nav_menu( array( 'theme_location' => 'footer-menu' ) ); ?>
    </footer>
    <?php wp_footer(); ?>

  </body>
</html>

single.php

<?php /*
Theme Name: theme-wp
Author: Queseo
Author URI: http://queseo.es/
Description: My first responsive HTML5 theme
Version: 1.0
License: GNU General Public License v3 or later
License URI: http://www.gnu.org/licenses/gpl-3.0.html
*/
?>

<?php get_header(); ?>
<main class="wrap">
  <section class="content-area content-full-width">
<?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
      <article class="article-full">
        <header>
          <h1><?php the_title(); ?></h1>
			<?php the_post_thumbnail('medium')?>
          By: <?php the_author(); ?>
        </header>
       <?php the_content(); ?>
      </article>
<?php endwhile; else : ?>
      <article>
        <p>Sorry, no post was found!</p>
      </article>
<?php endif; ?>
  </section><?php get_sidebar(); ?>
</main>
<?php get_footer(); ?>

page.php

<?php /*
Theme Name: theme-wp
Author: Queseo
Author URI: http://queseo.es/
Description: My first responsive HTML5 theme
Version: 1.0
License: GNU General Public License v3 or later
License URI: http://www.gnu.org/licenses/gpl-3.0.html
*/
?>

<?php get_header(); ?>
<main class="wrap">
  <section class="content-area content-thin">
<?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
      <article class="article-full">
        <header>
          <h2><?php the_title(); ?></h2>
          By: <?php the_author(); ?>
        </header>
        <?php the_content(); ?>
      </article>
<?php endwhile; else : ?>
      <article>
        <p>Sorry, no page was found!</p>
      </article>
<?php endif; ?>
  </section>
</main>
<?php get_footer(); ?>

style.css

En nuestra hoja de diseño, pondremos algunos css básicos para poder visualizar algo

/*
Theme Name: theme-wp
Author: Queseo
Author URI: http://queseo.es/
Description: My first responsive HTML5 theme
Version: 1.0
License: GNU General Public License v3 or later
License URI: http://www.gnu.org/licenses/gpl-3.0.html
*/

/*relleno interior de los bloques*/
* {
  box-sizing: border-box;
  margin:0px;
  padding:0px;


}
/*Background*/
body {
  margin: 0;
  font-family: 'Lato', sans-serif;

}

/*****************************************************************/
/*****************************CABECERA****************************/
/*****************************************************************/


/*centrar header*/
.my-logo {
  vertical-align: middle;
  text-align: center; /* requerido para alineación horizontal */
  background-color: #333;
}

.cont_head span{
  float:right;
  height: 48px;
  padding: 5px 20px 5px 20px;
  font-size:30px;
  background-color: #4CAF50;
}


.cont_head span a{
  color:white;
}

/*****************************************************************/
/*******************************MENU******************************/
/*****************************************************************/

.menu {
  overflow: hidden;
  background-color: #333;
  display: flex;
  list-style:none;
}

.menu li {
  float: left;
  color: #f2f2f2;
  text-align: center;
  padding: 14px 16px;
  text-decoration: none;
  font-size: 17px;
  border-right: 1px solid white;
}


.menu li:hover {
  background-color: #4CAF50;
}

.menu li:hover a {
  color: white;
}

.menu li a {
  color: #f2f2f2;
}

.current-menu-item {
  background-color: #4CAF50;
  color: white;
}



.sub-menu{
  display:none;
  position: absolute;
  left: 0px;
  margin-top: 14px;
  width: 200px;
  background-color: #333;
}
.sub-menu li{
  width:100%;
}

.menu li:hover .sub-menu{
  display:block;
}
@media all and (max-width: 500px) {

  header, .menu{
    flex-wrap: wrap;
  }
  .cont_head span{
  float: none;
}
  .menu  li {
    flex-basis: 100%;
  }

}


/*****************************************************************/
/*****************************END MENU****************************/
/*****************************************************************/

/*****************************************************************/
/***************************END CABECERA**************************/
/*****************************************************************/




/*****************************************************************/
/*****************************CONTENIDO***************************/
/*****************************************************************/

/*****************************************************************/
/******************************TITULOS****************************/
/*****************************************************************/
h1{
	    font-size: 65px;
	    line-height: 80px;
	    text-align: center;
}
h1, h2, h3{
    font-weight: bold;
    margin: auto;
}

h2, h2 a{
    font-size: 55px;
    line-height: 46px;
	    text-align: center;
}

h3, h4, h5, h6{
	text-align: left;
}
h3{
    font-size: 30px;
    line-height: 29px;
}

h4{    font-size: 25px;
}
h5{    font-size: 20px;
}
h6{    font-size: 15px;
}

/*****************************************************************/
/***************************END TITULOS***************************/
/*****************************************************************/

.content-area{
  display: flex;
  padding: 0 5% 0 5%;
  margin-bottom: 30px;
}

.article-loop{
  flex-wrap: wrap;
  flex-basis: 33%;
  background-color: #e5e5e5;
}
.article-loop h2{
  color: #4CAF50;
  background-color: #333;
  margin-bottom: 10px;
  padding: 20px 0 20px 0;
}
.article-loop h2 a{
  color: #4CAF50;
  text-decoration: none;
  line-height: 55px;
}

.article-loop:hover h2 a{
  color: white;
  text-decoration: none;
}

.article-loop p{
margin-top: 10px;
}

img.attachment-medium.size-medium.wp-post-image{
    width: 100%;
    height: auto;
    display: block;
    margin-bottom: 10px;
}

@media all and (max-width: 500px) {

  .content-area{
    flex-wrap: wrap;
    flex-basis: 100%;
  }
  .article-loop{
  flex-basis: 100%;
}

}

/*****************************************************************/
/***************************END CONTENIDO*************************/
/*****************************************************************/


/*****************************************************************/
/****************************PRE FOOTER***************************/
/*****************************************************************/
.widget-footer{
  padding-bottom: 60px;
  padding-top: 45px;
  background-color:#2B315E;
  color: #fff;
  padding-left: 20%;
  padding-right: 20%;
}
.widget-footer .container{
  margin: 0 auto;
  display: flex;
}
.widget-footer .container div{
    flex-wrap: wrap;

    margin: auto;
}

.container:after {
    content: "\0020";
    display: block;
    height: 0;
    clear: both;
    visibility: hidden;
}

@media all and (max-width: 1200px) {
  .widget-footer{
    padding-left: 10%;
    padding-right: 10%;
  }
}

@media all and (max-width: 730px) {
  .widget-footer{
    padding-left: 0;
    padding-right: 0;
  }
}

@media all and (max-width: 683px) {
  .widget-footer .container div{
      flex-basis: 100%;
  }
  .widget-footer .container{
      flex-wrap: wrap;
      padding: 0 25% 0 25%;
  }
}

/*****************************************************************/
/**************************END PRE FOOTER*************************/
/*****************************************************************/


/*****************************************************************/
/******************************FOOTER*****************************/
/*****************************************************************/
footer {
  width: 100%;
  padding-left: 1%;
  background-color: #333;
  vertical-align: middle;
  text-align: center; /* requerido para alineación horizontal */
  min-height:40px;
}

footer div{
  display: inline-block;
  margin: 30px 0 30px 0;

}

@media all and (max-width: 683px) {

  footer .menu{
    flex-wrap: wrap;
  }

  footer .menu  li {
    flex-basis: 100%;
  }

}
/*****************************************************************/
/****************************END FOOTER***************************/
/*****************************************************************/

blog.css

/*
Theme Name: theme-wp
Author: Queseo
Author URI: http://queseo.es/
Description: My first responsive HTML5 theme
Version: 1.0
License: GNU General Public License v3 or later
License URI: http://www.gnu.org/licenses/gpl-3.0.html
*/
.content-thin {
    width: 70%;
}
.primary-sidebar {
  width: 25%;
  padding: 1%;
  vertical-align: top;
  background-color: #ececec;
  flex-basis: 35%;
  padding: 0 250px 0 30px;
}

.article-loop {
    width: 45%;
    text-align: left;
    margin: 5px;
    padding: 10px;
}

.wrap{
	display: flex;
    flex-wrap: wrap;
}
.content-area {
	flex-basis: 65%;
    padding: 0 30px 0 250px;
}
.primary-sidebar h3{
   margin: 20px 0 20px 0;
}
.primary-sidebar .menu li{
  float:none;
}
.primary-sidebar .menu li a{
	text-decoration: none;
}
.primary-sidebar .menu {
   display: block;
}

#searchsubmit{
	padding: 5px 20px;
    background-color: #4CAF50;
    border: none;
    margin: 10px 0 0 0;
    width: 100%;
    color: white;
    font-weight: bold
}
#searchsubmit:hover{
    background-color: #f6933e;
    color: black;
}

article p{
	margin:30px 0;
	font-size: 20px;
    line-height: 30px;
}
article li{
	    margin-left: 20px;
    font-size: 17px;
    line-height: 40px;
}
article img{
	margin:30px 0;
}
article ul{
	padding-left: 50px;
	list-style: square;
	margin: 25px 0;
}
article h1{
	margin: 20px 0 20px 0;
}
article a{
	color: #4caf50;
}

.wp-block-code, .wp-block-preformatted{
	background-color: black;
    color: green;
    padding: 20px 40px 20px 80px;
    font-weight: bold;
    font-size: 14px;
    border: solid 3px green;
    margin: 30px 0;
	width: 950px;
}
iframe{
	width: 100%;
}

page.css

/*
Theme Name: theme-wp
Author: Queseo
Author URI: http://queseo.es/
Description: My first responsive HTML5 theme
Version: 1.0
License: GNU General Public License v3 or later
License URI: http://www.gnu.org/licenses/gpl-3.0.html
*/

.content-thin {
    width: 100%;
}

.content-area{
	width: 100%;
}

.article-loop {
    width: 32%;
    text-align: left;
    margin: 5px;
    padding: 10px;
}

Explicando el funcionamiento de los hooks y funciones

Ver todos los códigos así, puede ser algo algo confuso. El código anterior está compuesto por html, css y php. Mediante el código en php utilizamos los hooks y funciones para poder coger la información de nuestra base de datos y plasmarla en nuestro front-end.

Básicos

A continuación voy a mostrarte los hooks y funciones que he utilizado en el código anterior con una breve explicación. Para más ayuda sobre estos, te recomiendo que visites  la página de referencia de WordPress para desarrolladores :

  • language_attributes(): inserta el idioma.
  • bloginfo(‘name’): inserta el nombre del blog.
  • is_front_page(): comprueba si la página es una página o un post.
  • bloginfo(‘description’):  inserta las descripción del blog.
  • wp_title(”): muestra el título de la página para todas las áreas del blog.
  • bloginfo( ‘charset’ ): inserta los meta charset.
  • bloginfo(‘stylesheet_url’): inserta la hoja de estilos por defecto.
  • is_single(): nos dice si es una página cargada con single.php.
  • esc_url( home_url() ): esc_url checkea y limpia la url, mientras que home_url devuelve la url de la web actual.
  • wp_head(): escribe scripts o datos en la etiqueta head.
  • body_class(): muestra la clase para el elemento body.
  • wp_nav_menu( array( ‘theme_location’ => ‘header-menu’ ) ): con wp_nav_menu mostramos el menú de navegación, mientras que con  
    array( ‘theme_location’ => ‘header-menu’ ) indicamos el menú que queremos usar que se encuentra declarado dentro de nuestro functions.php.
  • get_header(): carga el header.php.
  • have_posts(): realiza una consulta a WordPress para comprobar si existen posts.
  • the_post(): itera los posts que se muestran dentro del bucle.
  • the_permalink(): muestra el enlace permanente para la página actual.
  • the_title_attribute(): muestra el título actual. similar a la función the_title().
  • the_title(): muestra el título actual.
  • the_post_thumbnail(‘medium’): muestra la imagen destacada de la página o post con un tamaño medio (medium). También existen otros tamaños como thumbnail, large, full, etc.
  • the_author(): muestra el autor.
  • the_excerpt(): muestra el extracto del post.
  • get_footer():  carga el footer.php.
  • the_content(): muestra el contenido del post.
  • is_active_sidebar( ‘sidebar’ ): determina si el sidebar está en uso, es decir, comprueba si existen widgets en el sidebar.
  • dynamic_sidebar( ‘sidebar’ ): muestra el sidebar dinámico, en otras palabras, los widgets incluidos en el sidebar.
  • get_sidebar(): carga el template del sidebar (sidebar.php).
  • wp_footer(): carga los scripts y datos antes de cerrar con las etiquetas body y html.

Bucles de WordPress

El bucle que utilizo dentro de WordPress es para mostrar artículos de forma automática:

<?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
      <article class="article-loop">
        <header>
          <h2>
<a href="<?php the_permalink(); ?>" title="<?php the_title_attribute(); ?>">
<?php the_title(); ?>
</a>
</h2>
          <div><?php the_post_thumbnail('medium');?></div>
          <i><?php the_author(); ?></i>
        </header>
        <?php the_excerpt(); ?>
      </article>
<?php endwhile; else : ?>
      <article>
        <p>Sorry, no posts were found!</p>
      </article>
<?php endif; ?>

Con este código hacemos un bucle condicional, en el que si existen artículos de blog, mientras existan, se irá publicando el título, la imagen, el autor y un pequeño texto de introducción, en que de no tener, mostrará un pequeño mensaje de error en inglés.

Truco de optimización

Realmente, como puedes observar, hay más códigos de los necesarios, esto lo hice con el objetivo de optimizar un poco más el código de tal forma que también fuera para mi más cómodo trabajar a futuro con el template,

Carga selectiva de CSS y JS

Como puedes comprobar en el fichero header.php, realizo una carga selectiva de dos hojas de estilo diferentes, una orientada al blog, y otra orientada a páginas normales. El código en cuestión es este:

<?php
		if( is_single()):?>
   			<link rel="stylesheet" href="
<?php echo esc_url( home_url() ); ?>/wp-content/themes/theme-wp/blog.css">
<?php ;
		else:?>
			<link rel="stylesheet" href="
<?php echo esc_url( home_url() ); ?>/wp-content/themes/theme-wp/pages.css">
<?php ;
		endif;
	?>

Al principio, realiciamos una comprobación de si la página es un artículo del blog o no, con if (is single()). Si es es un artículo de blog, carga el archivo blog.css, mientras que si no lo es, carga el page.css.

Lo que hago para este template, es tener tres css, uno genérico, otro ara para artículos del blog y otro para páginas, esto hace que me sea más fácil mantener un estandar para toda la web, aunque lo realmente óptimo, sería tener un único css para cada página.

Esto luego podemos solucionarlo con algún plugin, ya que habrán otros plugins que dejarán su css y será necesario igualmente unificarlos todos igualmente de una forma práctica.

Conclusiones

Como puedes comprobar, realizar un tema para WordPress es bastante sencillo. Quería incluir algunas cosas más, como la creación de nuevos diseños de páginas y plugins, pero creo que con todo esto es suficiente.

El tema, como podéis comprobar, está un poco en fase beta y la idea es ir mejorándolo poco a poco con el tiempo, así que con paciencia y mucho mimo, iré dando forma a lo que es el diseño de mi blog.

Dejo los archivos en Github por si alguien quiere descargar los archivos y subirlos directamente a su web.

Este artículo y su código es original de Diana que la menciono aquí abajo y te dejo un enlace a su post. El post es el mismo aunque yo incluí algunas modificaciones en el código y agregué algunas cosillas extra.

Si te gustó el post, te agradezco la difusión =)

Fuentes

¿Cómo crear un tema de WordPress responsive usando HTML5? – Diana C.

Sobre la autoría del artículo

Eric Jorge Seguí Parejo es Seo Manager en agenciaSEO.eu, una agencia de marketing especializada en SEO situada en Valencia. Su blog personal es Queseo.es y participa de forma activa en diversos blogs del sector.