SummArg | Cursos y recursos para webmasters

Clase 17: Custom Post Types: Portfolio y plantilla de taxonomías.

En esta clase vamos a encarar la plantilla de taxonomías y, de yapa, vamos a construir una página para ver todo el portfolio de un modo un poco mas interesante.

Volviendo, como siempre, a la jerarquía de plantillas, vemos que el formato de archivo que tenemos que usar para poder visualizar nuestros elementos por “tipo” es taxonomy-$taxonomy.php. Entonces daremos a nuestro archivo el nombre de taxonomy-portfoliotaxonomies.php, ya que así lo llamamos en el archivo functions.php.

<?php get_header(); ?>
<div class="wrapperPortfolio">
<?php
if ( have_posts() ) : while ( have_posts() ) : the_post();
$cliente = get_post_meta(get_the_id(), 'cliente', TRUE);
$descripcion = get_post_meta(get_the_id(), 'descripcion', TRUE); ?>
	<div class="portfolioItem">
		<a href="<?php the_permalink() ?>" title="<?php the_title(); ?>">
			<?php the_post_thumbnail('portfolioitem'); ?>
			<div class="portfolioItemDetalle">
				<h2><?php the_title(); ?></h2>
				<?php
				if ($cliente) { echo '<p><div class="detalleTitulo">Cliente</div> '.$cliente; }
				if ($descripcion) { echo '<br /><div class="detalleTitulo">Descripcion</div> '.$descripcion.'</p>'; } ?>
			</div>
		</a>
	</div><!-- end of portfolioItem -->
<?php endwhile; endif; ?>
<div class="navigation"><?php wp_pagenavi(); ?></div>
</div>
<?php get_footer(); ?>

Lo que hicimos en nuestro template es buscar el contenido de los custom fields “cliente” y “descripcion” y guardarlo en variables. Luego, dentro del bucle, nos fijamos si $cliente tiene algún contenido, de tenerlo entonces imprime lo que está luego del echo. Mismo caso para $descripcion.

Como verán añadimos un tamaño de thumbnail mas, así que lo tenemos que añadir a nuestro functions.php, en la sección en donde están los demás tamaños.

add_image_size( 'portfolioitem', 230,230, true );

Y ya que estamos podemos añadir un snippet a nuestro functions.php que nos va a facilitar la carga de productos también. Este trozo de código ya lo hemos visto en otras oportunidades en Summarg y resulta muy práctico. Básicamente lo que hace es tomar la primer imagen que encuentre en la entrada y la convierte en destacada, salvo que el usuario haya elegido específicamente una.

function autoset_featured() {
 global $post;
 $already_has_thumb = has_post_thumbnail($post->ID);
 if (!$already_has_thumb) {
 $attached_image = get_children( "post_parent=$post->ID&post_type=attachment&post_mime_type=image&numberposts=1" );
 if ($attached_image) {
 foreach ($attached_image as $attachment_id => $attachment) {
 set_post_thumbnail($post->ID, $attachment_id);
 }
 }
 }
 } //end function
add_action('the_post', 'autoset_featured');
add_action('save_post', 'autoset_featured');
add_action('draft_to_publish', 'autoset_featured');
add_action('new_to_publish', 'autoset_featured');
add_action('pending_to_publish', 'autoset_featured');
add_action('future_to_publish', 'autoset_featured');

Buscaremos que nuestra plantilla tenga el siguiente formato:

taxo

Llegado este punto, y si ya tienen varios elementos cargados, necesitan regenerar las miniaturas para que muestre el nuevo formato. Pueden usar el plugin Regenerate Thumbnails que les va a ahorrar mucho tiempo y esfuerzo.

Vamos con el CSS.

/* plantilla taxonomia */
.portfolioItem {
width: 230px;
height:230px;
float:left;
position:relative;
margin:0;
padding:0;
}
.portfolioItem a {
color:white;
text-decoration:none;
}
.portfolioItem a img {
border:none;
margin:0;
}

Necesitamos que .portfolioItem tenga position:relative ya que el contenedor que le sigue tendrá que superponerse a nuestra imagen para lograr el efecto deseado, para  lo cual usará position:absolute y le indicaremos que se posicione en top:0 y left:0.

.portfolioItemDetalle {
display:none;
position:absolute;
top:0;
left:0;
background-image:url(images/darky.png);
background-repeat:repeat;
padding: 10px;
width: 210px;
height:210px;
color:white;
margin:0;
}
.portfolioItemDetalle h2 {
text-align:center;
margin-top:20px;
color:white;
}

Al contenedor con el título y los detalles del trabajo le damos un display:none para ocultarlo, ya que queremos que se muestre únicamente cuando el usuario pase el mouse por arriba del elemento y luego se oculte. Con la siguiente línea completamos el truco:

.portfolioItem:hover .portfolioItemDetalle {
display:block;
}

¡Listo! El truco funciona. Aunque… ¿Qué tal si ponemos un poquito de jQuery para animar esas ventanitas un poco? De ese modo podemos suavizar el efecto al pasar el mouse por arriba.

Comentemos o eliminemos el último trozo de CSS y coloquemos el siguiente código en la plantilla de taxonomía luego del endif;

<script type="text/javascript">
 $(function() {
 $(".portfolioItem").hover(function() {
 $(this).children(".portfolioItemDetalle").show("fast");
 },function(){
 $(this).children(".portfolioItemDetalle").hide("fast");
 });
 });
</script>

Con esto ya tenemos un bonito modo de mostrar nuestros items y dejamos las bases bien plantadas para que los lectores puedan tomar su propio rumbo a la hora de usar Custom Post Types. Pueden ver el producto terminado en el demo online.

Página personalizada para el portfolio con jQuery Isotope

Todavía podemos hacer algo mas, un poco mas complicado y personalizado pero que va a quedar muy bien para lucir nuestro porfolio. Fuera de programa les vamos a regalar una integración entre el plugin jQuery Isotope y nuestro portfolio.

Creamos una página personalizada de nombre page-portfolio.php y colocamos en su interior exactamente lo que ya tenemos para taxonomía con pequeñas diferencias:

  • Agregamos el encabezado con el template name.
  • Modificamos los argumentos de la query para que muestre cantidad ilimitada de elementos dentro del post_type que nos interesa.
  • Eliminamos la línea de paginación ya que no vamos a usar ninguna.
<?php
/*
template name: Portfolio + Isotope
*/
get_header(); ?>
<div class="wrapperPortfolio">
<?php
 $args= array(
 'posts_per_page' => 9999,
 'post_type' => 'Portfolio'
 );
 query_posts($args);
if ( have_posts() ) : while ( have_posts() ) : the_post();
$cliente = get_post_meta(get_the_id(), 'cliente', TRUE);
$descripcion = get_post_meta(get_the_id(), 'descripcion', TRUE); ?>
 <div class="portfolioItem">
 <a href="<?php the_permalink() ?>" title="<?php the_title(); ?>">
 <?php the_post_thumbnail('portfolioitem'); ?>
 <div class="portfolioItemDetalle">
 <h2><?php the_title(); ?></h2>
 <?php
 if ($cliente) { echo '<p><div class="detalleTitulo">Cliente</div> '.$cliente; }
 if ($descripcion) { echo '<br /><div class="detalleTitulo">Decripcion</div> '.$descripcion.'</p>'; } ?>
 </div>
 </a>
 </div><!-- end of portfolioItem -->
<?php endwhile; endif; ?>
<script type="text/javascript">
 $(function() {
 $(".portfolioItem a").hover(function() {
 $(this).children(".portfolioItemDetalle").show("fast");
 },function(){
 $(this).children(".portfolioItemDetalle").hide("fast");
 });
 });
</script>
</div>
<?php get_footer(); ?>

Creamos una página y le asignamos la plantilla que estamos construyendo. Descargamos desde Isotope el plugin y lo anexamos a nuestro header.

<script type="text/javascript" language="javascript" src="<?php bloginfo('template_directory'); ?>/scripts/jquery.isotope.min.js"></script>

Ahora bien, el plugin nos pide que respetemos una estructura de marcado determinada el menú y para los elementos. Pueden ver aquí la documentación (específicamente en lo que respecta a sorting) y les transcribimos el código del demo de Isotope para que se den una buena idea.

<ul id="sort-by">
  <li><a href="#name">name</a></li>
  <li><a href="#symbol">symbol</a></li>
  <li><a href="#number">number</a></li>
  <li><a href="#weight">weight</a></li>
  <li><a href="#category">category</a></li>
</ul>
<div id="container">
  <div class="element transition metal" data-category="transition">
    <p class="number">79</p>
    <h3 class="symbol">Au</h3>
    <h2 class="name">Gold</h2>
    <p class="weight">196.966569</p>
  </div>
  <div class="element metalloid" data-category="metalloid">
    <p class="number">51</p>
    <h3 class="symbol">Sb</h3>
    <h2 class="name">Antimony</h2>
    <p class="weight">121.76</p>
  </div>
</div>

Entonces nosotros intentaremos adaptar esa estructura a nuestro trabajo para que funcione el plugin. Debajo de la llamada de get_header() insertamos el menú desde el que llamaremos a cada una de las taxonomías para que se muestren.

<div id="options">
<ul id="filters" data-option-key="filter">
<li><a href="#filter" data-option-value="*">Todos</a></li>
<li><a href="#filter" data-option-value=".Logos">Logos</a></li>
<li><a href="#filter" data-option-value=".Packaging">Packaging</a></li>
<li><a href="#filter" data-option-value=".Websites">Sitios Web</a></li>
<li><a href="#filter" data-option-value=".Tarjetas">Tarjetas</a></li>
</ul>
</div>

Inmediatamente después de que se inicia el bucle necesitamos obtener el nombre de la taxonomía para colocarla en la clase de cada elemento, de ese modo el plugin puede traer a cada elemento cuando el usuario clickee en el menú.

$terms = get_the_terms( $post->ID , 'portfoliotaxonomies' );
foreach ( $terms as $term ) { $isotopeClass = $term->name; }

El nombre de la taxonomía se almacena en $isotopeClass, y ahora debemos imprimirla en nuestros elementos.

<div class="portfolioItem isotopeElement <?php echo $isotopeClass; ?>">
 <a href="<?php the_permalink() ?>" title="<?php the_title(); ?>">
 <?php the_post_thumbnail('portfolioitem'); ?>
 <div class="portfolioItemDetalle">
 <h2><?php the_title(); ?></h2>
 <?php
 if ($cliente) { echo '<p><div class="detalleTitulo">Cliente</div> '.$cliente; }
 if ($descripcion) { echo '<br /><div class="detalleTitulo">Descripcion</div> '.$descripcion.'</p>'; } ?>
 </div>
 </a>
 </div><!-- end of portfolioItem -->

Con esto ya tenemos el marcado necesario y podemos proceder a añadir el código javascript para que se ejecute el plugin. El siguiente código debe anexarse al que ya habíamos colocado para animar la aparición de los detalles del item.

<script type="text/javascript">
 $(function(){
 var $container = $('#isotopeArea');
 $container.isotope({
 itemSelector : '.isotopeElement',
 animationEngine : 'best-available'
 });
 var $optionSets = $('#options .option-set'),
 $optionLinks = $optionSets.find('a');
$optionLinks.click(function(){
 var $this = $(this);
 // don't proceed if already selected
 if ( $this.hasClass('selected') ) {
 return false;
 }
 var $optionSet = $this.parents('.option-set');
 $optionSet.find('.selected').removeClass('selected');
 $this.addClass('selected');
 // make option object dynamically, i.e. { filter: '.my-filter-class' }
 var options = {},
 key = $optionSet.attr('data-option-key'),
 value = $this.attr('data-option-value');
 // parse 'false' as false boolean
 value = value === 'false' ? false : value;
 options[ key ] = value;
 if ( key === 'layoutMode' && typeof changeLayoutMode === 'function' ) {
 // changes in layout modes need extra logic
 changeLayoutMode( $this, options )
 } else {
 // otherwise, apply new options
 $container.isotope( options );
 }
 return false;
 });
 });
</script>

Con el parámetro animationEngine : ‘best-available’ estamos indicando al plugin que utilice animaciones CSS3 cuando el navegador lo permita, y animaciones javascript en caso contrario. Así que en nuestro CSS lo que tenemos que incluir son dichas transiciones.

/** Isotope **/
.isotope,
.isotope .isotope-item {
 /* change duration value to whatever you like */
 -webkit-transition-duration: 0.8s;
 -moz-transition-duration: 0.8s;
 -ms-transition-duration: 0.8s;
 -o-transition-duration: 0.8s;
 transition-duration: 0.8s;
}
.isotope {
 -webkit-transition-property: height, width;
 -moz-transition-property: height, width;
 -ms-transition-property: height, width;
 -o-transition-property: height, width;
 transition-property: height, width;
}
.isotope .isotope-item {
 -webkit-transition-property: -webkit-transform, opacity;
 -moz-transition-property: -moz-transform, opacity;
 -ms-transition-property: -ms-transform, opacity;
 -o-transition-property: -o-transform, opacity;
 transition-property: transform, opacity;
}
/**** disabling Isotope CSS3 transitions ****/
.isotope.no-transition,
.isotope.no-transition .isotope-item,
.isotope .isotope-item.no-transition {
 -webkit-transition-duration: 0s;
 -moz-transition-duration: 0s;
 -ms-transition-duration: 0s;
 -o-transition-duration: 0s;
 transition-duration: 0s;
}

Y para concluir damos estilo al menú que acabamos de agregar, que dicho sea de paso será igual al #menu-top que construimos al principio del taller.

/** Menu isotope **/
ul#filters {
margin:20px 20px 0 0;
float:right;
list-style-type:none;
height:30px;
width: 920px;
}
ul#filters li a{
list-style-type:none;
text-decoration:none;
float:right;
color: #7ec5ff;
font-weight:bold;
padding: 7px 10px;
font-size:12px;
}
ul#filters li a:hover {
text-decoration:none;
background-color: #7ec5ff;
color:#fff;
font-weight:bold;
padding: 7px 10px;
}

Nota: para que este código les funcione tal cual está aquí, deben crear exactamente las mismas taxonomías en Portfolio que nosotros publicamos. Sino simplemente efectúen las modificaciones en donde corresponda en el menú.

Demo online

isoto

Descargar la clase de hoy: themeTaller 17 (156)

Dejar un comentario

  1. Hola gracias por este fantastico curso de wordpress, me han servido mucho, estoy pensando en la realizacion de un libro con estos apuntes y con toda mi experiencia en wordpress y php.

  2. […] Clase 17: Custom Post Types: Portfolio y plantilla de taxonomía. […]

  3. […] Clase 17: Custom Post Types: Portfolio y plantilla de taxonomía. […]

  4. Victor

    Hola, muchas gracias por este curso. Si quisiera cambiar el nombre de portfolio por algún otro, ¿debo hacer el cambio de la palabra en todos los archivos o solo en algunos? De nuevo, muchas gracias,

  5. Cristhian Bórquez

    Excelente Tutorial. ¿Como crear un plugin con este ejemplo maravilloso?

    Saludos

Dejar un comentario