Un thème premium qui se respecte comporte des modèles de pages de type portfolio, très utile pour mettre en valeur vos créations artistiques notamment. La plupart d’entre eux sont dotés d’un système de filtre basé sur les termes d’une taxonomie spécialement créée pour l’occasion et le redimensionnement de la fenêtre réajuste automatiquement les éléments avec une transition en CSS3. Ce tutoriel va vous apprendre comment mettre en place un tel système sous WordPress et sans avoir recours à un plugin.

Avant-propos

Ce tutoriel est réservé à des utilisateurs avertis. Elle requiert de multiples connaissances de base en termes d’intégration, de développement Web et plus. Il serait impossible de tout expliquer ligne par ligne d’où cet avertissement. Les utilisateurs peu à l’aise avec le code préféreront le recours à un plugin.

Résultat final / démonstration

Une démonstration est disponible sur mon site Neticpro et une variante sur le site de ddesign.

wpchannel-isotope-portfolio-1

Mon portfolio (pas mis à jour) avec ouverture d’une détaillée

wpchannel-isotope-portfolio-2

Le portfolio de Christèle & Déborah avec effet fancyBox

Étape n°1 – Création du custom post type ‘Portfolio’

Il nous faut dans un premier temps générer un type de contenu sur-mesure qui sera entièrement dédié à la saisie des éléments du portfolio.

Récupérez donc ce code à insérer dans votre fichier functions.php (ou dans un fichier dédié pour ceux qui veulent aller plus loin) :

/* Portfolio */
function cpt_ntp_portfolio() {
$labels = array(
 'name' => _x( 'Portfolio', 'Post Type General Name', 'ntp_framework' ),
 'singular_name' => _x( 'Portfolio', 'Post Type Singular Name', 'ntp_framework' ),
 'menu_name' => __( 'Portfolio', 'ntp_framework' ),
 'parent_item_colon' => __( 'Portfolio parent :', 'ntp_framework' ),
 'all_items' => __( 'Tous les portfolios', 'ntp_framework' ),
 'view_item' => __( 'Voir le portfolio', 'ntp_framework' ),
 'add_new_item' => __( 'Ajouter un portfolio', 'ntp_framework' ),
 'add_new' => __( 'Nouveau portfolio', 'ntp_framework' ),
 'edit_item' => __( 'Editer un portfolio', 'ntp_framework' ),
 'update_item' => __( 'Mettre à jour le portfolio', 'ntp_framework' ),
 'search_items' => __( 'Rechercher des produits', 'ntp_framework' ),
 'not_found' => __( 'Aucun portfolio trouvé', 'ntp_framework' ),
 'not_found_in_trash' => __( 'Aucun portfolio trouvé dans la corbeille', 'ntp_framework' ),
 );
 $rewrite = array(
 'slug' => 'portfolio',
 'with_front' => true,
 'pages' => false,
 'feeds' => false,
 );
 $args = array(
 'label' => __( 'portfolio', 'ntp_framework' ),
 'description' => __( 'Les créations de votre entreprise', 'ntp_framework' ),
 'labels' => $labels,
 'supports' => array( 'title', 'editor', 'thumbnail', 'revisions', 'custom-fields', ),
 'taxonomies' => array( 'type' ),
 'hierarchical' => false,
 'public' => true,
 'show_ui' => true,
 'show_in_menu' => true,
 'show_in_nav_menus' => true,
 'show_in_admin_bar' => true,
 'menu_position' => 20,
 'menu_icon' => '',
 'can_export' => true,
 'has_archive' => true,
 'exclude_from_search' => true,
 'publicly_queryable' => true,
 'query_var' => 'portfolio',
 'rewrite' => $rewrite,
 'capability_type' => 'page',
 );
 register_post_type( 'portfolio', $args );
}
add_action( 'init', 'cpt_ntp_portfolio', 0 );

Vous pouvez changer le textdomain par le vôtre, à la place de ntp_framework.

Vérifiez que le type de contenu apparaît bien dans votre administration WordPress puis ajoutez quelques éléments d’exemples.

Aucun champ particulier n’a été ajouté, notez que l’image à la une nous servira pour afficher les vignettes dans la galerie.

Étape n°2 – Création de la taxonomie personnalisée ‘Type’

Il s’agit ni plus ni moins que des catégories liées au items du portfolio. Je l’ai nommé Type pour l’exemple :

/* Type */
function ct_ntp_type() {
$labels = array(
 'name' => _x( 'Types', 'Taxonomy General Name', 'ntp_framework' ),
 'singular_name' => _x( 'Type', 'Taxonomy Singular Name', 'ntp_framework' ),
 'menu_name' => __( 'Types', 'ntp_framework' ),
 'all_items' => __( 'Tous les types', 'ntp_framework' ),
 'parent_item' => __( 'Type parent', 'ntp_framework' ),
 'parent_item_colon' => __( 'Type parent :', 'ntp_framework' ),
 'new_item_name' => __( 'Nouveau type', 'ntp_framework' ),
 'add_new_item' => __( 'Ajouter un type', 'ntp_framework' ),
 'edit_item' => __( 'Editer un type', 'ntp_framework' ),
 'update_item' => __( 'Mettre à jour', 'ntp_framework' ),
 'separate_items_with_commas' => __( 'Séparer les types par des virgules', 'ntp_framework' ),
 'search_items' => __( 'Rechercher des types', 'ntp_framework' ),
 'add_or_remove_items' => __( 'Ajouter ou supprimer des types', 'ntp_framework' ),
 'choose_from_most_used' => __( 'Choisir parmi les types les plus utilisés', 'ntp_framework' ),
 );
 $rewrite = array(
 'slug' => 'type',
 'with_front' => true,
 'hierarchical' => true,
 );
 $args = array(
 'labels' => $labels,
 'hierarchical' => true,
 'public' => true,
 'show_ui' => true,
 'show_admin_column' => true,
 'show_in_nav_menus' => true,
 'show_tagcloud' => true,
 'query_var' => 'type',
 'rewrite' => $rewrite,
 );
 register_taxonomy( 'type', 'portfolio', $args );
}
add_action( 'init', 'ct_ntp_type', 0 );

Étape n°3 – Création de la page d’archive du portfolio

A présent que les données sont saisies dans le back-office de WordPress, il nous faut les afficher. Avec les types de contenu personnalisé, on reprend simplement la hiérarchie des thèmes WordPress, à savoir :

  • archive-portfolio.php : la page qui affichera la liste complète des éléments dont le lien correspondra au nom du type de contenu (à moins que vous n’ayez passé des règles de réécriture) ;
  • single-portfolio.php : pour afficher le détail d’un item du portfolio ;

Le premier fichier est le plus important, le second facultatif si bien que nous ne l’utiliserons pas dans ce tutoriel afin de simplifier.

Voici un exemple de fichier archive-portfolio.php, je dis un exemple dans la mesure où vous devrez l’adapter en fonction de votre thème en reprenant la même structure HTML / CSS.

Notez que le code est basé sur le framework Bootstrap 2.3 pour les aspects responsive. Je compte le passer en Bootstrap 3.0 prochainement.

/* Page d’archive du portfolio */

<?php get_header(); ?>
<div id="content" class="container">
	<div class="row">
		<div id="main" class="span12" role="main">

			<div class="page-header">
				<h1 class="archive_title h2">
					<?php post_type_archive_title(); ?> - <small><?php _e('Some of our best work', 'ntp_framework'); ?></small>
				</h1>
			</div>

			<?php 
				$terms = get_terms("type"); 
				$count = count($terms); 
				echo '<ul id="portfolio-filter" class="filter">'; 
				echo '<li class="active-tag btn btn-small"><a href="#all" data-filter="*" title="Tout">Tout</a></li>'; 
				if ( $count > 0 ) { 
					foreach ( $terms as $term ) { 
						$termname = ($term->slug); 
						echo ' <li class="btn btn-small"><a href="#'.$termname.'" title="" data-filter=".'.$termname.'" rel="'.$termname.'">'.$term->name.'</a></li>'; 
					} 
				} 
				echo "</ul>"; 
			?>

			<div id="portfolio-wrapper">
				<ul id="portfolio-list" class="thumbnails isotope">

				<?php if (have_posts()) : while (have_posts()) : the_post(); ?>

					<li id="post-<?php the_ID(); ?>" <?php post_class('item-portfolio'); ?> role="article">
						<?php
							$image_id = get_post_thumbnail_id();
							$image_url = wp_get_attachment_image_src($image_id, 'large');
							$image_url = $image_url[0];
						?>

						<a class="fancybox thumbnail" id="post-<?php the_ID(); ?>" href="<?php echo $image_url ?>" title="<?php the_title_attribute(); ?>"><?php the_post_thumbnail('medium', array('class' => 'aligncenter photo')); ?></a>
					</li>

				<?php endwhile; ?> 

				<?php else : ?>

					<article id="post-not-found">
						<header>
							<h1><?php _e("No portfolio yet", "ntp_framework"); ?></h1>
						</header>

						<section class="post_content">
							<p><?php _e("Sorry, What you were looking for is not here.", "ntp_framework"); ?></p>
						</section>
					</article>

				<?php endif; ?>

				</ul>
			</div>
		</div> 
	</div> 
</div>
<?php get_footer(); ?>

Étape n°4 – Intégration des scripts JavaScript

Nous aurons recours au script Isotope qui dispose de nombreux paramètres de personnalisation pour celles et ceux qui voudront aller plus loin.

Nous devons enregistrer le script et l’appeler sur la page d’archive de notre portfolio de façon optimale. Toujours dans le fichier functions.php :

/* Ajout des scripts JavaScript */
function ntp_js() {
wp_register_script('isotope', get_template_directory_uri().'/inc/js/jquery.isotope.min.js', array('jquery'), '1.5.19', true);if (is_post_type_archive('portfolio')) {
wp_enqueue_script('isotope');
}
}
add_action('wp_enqueue_scripts', 'ntp_js');

Il nous faut également récupérer les slugs des termes de la taxonomie liée au portfolio pour les insérer automatiquement dans la galerie. C’est de cette manière que le système de filtrage opère via Isotope.

/* Ajout des termes dans les classes CSS des éléments du portfolio */
function ntp_item_portfolio_class( $classes, $class, $ID ) {
 $taxonomy = 'type';
 $terms = get_the_terms( (int) $ID, $taxonomy );
 if( !empty( $terms ) ) {
 foreach( (array) $terms as $order => $term ) {
 if( !in_array( $term->slug, $classes ) ) {
 $classes[] = $term->slug;
 }
 }
 }
 return $classes;
}
add_filter('post_class', 'ntp_item_portfolio_class', 10, 3);

Comme vous l’aurez remarqué, nous aurons recours au transformations et animations via le CSS de niveau 3 que la plupart des navigateurs supportent dorénavant et non pas à jQuery.

Il nous maintenant initialiser le script et activer les différents effets sur la page concernée :

/* Ajout du JavaScript isotope sur le portfolio */
function ntp_isotope_js() { 
 if (!is_admin() && is_post_type_archive('portfolio')) { ?>
 <script> 
 jQuery(function($) {
 $(window).load(function() {

 /* Code principal */
 function ntp_portfolio_isotope() {
 var $container = $('#portfolio-list');
 $container.imagesLoaded(function(){
 $container.isotope({
 itemSelector: '.item-portfolio',
 layoutMode: 'masonry' 
 });
 });
 } ntp_portfolio_isotope();

 /* Filtre */
 $('.filter a').click(function() {
 var selector = $(this).attr('data-filter');
 $('#portfolio-list').isotope({ filter: selector });
 $(this).parents('ul').find('a').removeClass('active');
 $(this).addClass('active');
 return false;
 });

 /* Redimensionnement */
 var isIE8 = $.browser.msie && +$.browser.version === 8;
 if (isIE8) {
 document.body.onresize = function () {
 ntp_portfolio_isotope();
 };
 } else {
 $(window).resize(function () {
 ntp_portfolio_isotope();
 });
 }

 /* Orientation */
 window.addEventListener("orientationchange", function() {
 ntp_portfolio_isotope();
 });

 });
 });
</script> 
<?php } }
add_action ('wp_footer', 'ntp_isotope_js');

Étape n°5 – Ajout des classes CSS

Pour un rendu correct, il nous faut ajouter quelques lignes de code CSS. Attention à ne pas modifier le nom des classes CSS précédemment ajoutées dans les fichiers PHP.

/*--------------------------------------------------------------
    Portfolio
-------------------------------------------------------------- */

/* Grille portfolio */
ul#portfolio-list { 
    margin-top: 20px;    
}
ul#portfolio-list h2 { 
    font-weight: lighter;
}
.thumbnail { 
    width: 85%;
}
.isotope, .isotope .isotope-item {
    -webkit-transition: all 0.6s ;
    -moz-transition: all 0.6s ;
    -ms-transition: all 0.6s ;
    -o-transition: all 0.6s ;
    transition: all 0.6s ;
}
.isotope {
    transition-property: height, width;
}
.isotope .isotope-item {
    transition-property: transform, opacity;
}
.isotope.no-transition, .isotope.no-transition .isotope-item, .isotope .isotope-item.no-transition {
    transition-duration: 0s;
}
ul#portfolio-filter {
    margin-top: 20px;
}
a.thumbnail:hover, a.thumbnail:focus {
    border-color: #27AAE2;
    box-shadow: none;
    outline: 0 none;
}
.thumbnail {
    border: 1px solid #EEEEEE;
    border-radius: 0 0 0 0;
    box-shadow: none;
}
.single-portfolio header {
    text-align: center;
}
.single-portfolio h1 {
    margin: 50px auto 0;
}
.single-portfolio h2 {
    font-family: Georgia, serif;
    font-size: 18px;
    font-style: italic;
    font-weight: lighter;
    margin: 0;
}
#bg-portfolio {
    background: rgb(69,72,77); /* Old browsers */
    background: -moz-linear-gradient(top,  rgba(69,72,77,1) 0%, rgba(0,0,0,1) 100%); /* FF3.6+ */
    background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(69,72,77,1)), color-stop(100%,rgba(0,0,0,1))); /* Chrome,Safari4+ */
    background: -webkit-linear-gradient(top,  rgba(69,72,77,1) 0%,rgba(0,0,0,1) 100%); /* Chrome10+,Safari5.1+ */
    background: -o-linear-gradient(top,  rgba(69,72,77,1) 0%,rgba(0,0,0,1) 100%); /* Opera 11.10+ */
    background: -ms-linear-gradient(top,  rgba(69,72,77,1) 0%,rgba(0,0,0,1) 100%); /* IE10+ */
    background: linear-gradient(to bottom,  rgba(69,72,77,1) 0%,rgba(0,0,0,1) 100%); /* W3C */
    filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#45484d', endColorstr='#000000',GradientType=0 ); /* IE6-9 */
    border-bottom: 1px solid #D4D4D4;
    border-top: 1px solid #D4D4D4;
    margin: 20px 0;
    padding: 50px 0;
}
ul#project-details li {
    margin: 10px 0;
}
.single-portfolio .carousel img {
    height: auto;
    left: 0;
    margin: 0 auto;
    min-width: inherit;
    position: relative;
    top: 0;
}

Étape n°6 – Vérifier le résultat final

Pour terminer, il nous faut ajouter un lien d’accès au portfolio. Sous Apparence puis Menus, rajoutez un Lien avec l’URL du portfolio typiquement : http://neticpro.fr/portfolio/

Pour aller plus loin

#1 – Augmenter le nombre d’éléments affichés dans la galerie

Le nombre d’éléments affichés est limité au paramètre défini dans les réglages de lecture de WordPress. Vous pouvez rajouter ce bout de code dans le fichier de fonctions pour en afficher 99 bien que je ne vous conseille pas de dépasser 50 éléments avec ce type de script.

/* Nombre d'items à afficher dans le portfolio */
function ntp_cpt_item( $query ) {
 if ( is_post_type_archive( 'portfolio' ) ) {
 $query->set( 'posts_per_page', 99 );
 return;
 }
}
add_action( 'pre_get_posts', 'ntp_cpt_item', 1 );

#2 – Ajouter un effet fancyBox sur les éléments

Si vous ne souhaitez pas ouvrir une page détaillée pour décrire l’item, vous pouvez tout aussi bien afficher l’image en plus grand via un effet fancyBox. C’est le cas actuellement sur le site des collègues de chez ddesign.

Pour ce faire, intégrer le script fancyBox puis appelez en se basant sur les mêmes méthodes décrites ci-dessus pour Isotope. Je n’irais pas plus loin ici car cela pourrait faire l’objet d’un autre tutoriel.

#3 – Activer le responsive si absence de Twitter Bootstrap

Dans mes exemples, les images disposent d’une taille en pourcentage ce qui autorise une adaptation en fonction de la résolution de la fenêtre. Si vous n’utilisez pas une telle solution, vous devriez lire la documentation relative à ce sujet sur le site Isotope.

Vous disposez à présent d’un portfolio de vos plus belles créations avec un code optimisé, adaptatif et entièrement conçu pour WordPress. Des suggestions d’améliorations ?

44 commentaires

  1. Merci pour ce tuto.
    Par contre j’ai dû manquer une étape car lorsque je tente d’accéder à la page archive-portfolio.php, j’ai l’erreur suivante : « Fatal error: Call to undefined function get_header() in C:\wamp\www\wordpress\wp-content\themes\Pronto\achive-portfolio.php on line 1″

    J’utilise le thème Pronto et j’aurais aimé le rendre un peu plus dynamique grâce à votre tutoriel.

    Merci pour votre aide.

  2. Bonjour Aurélien, merci pour ce tuto que je ne manquerai pas de mettre à profit quand je serai un peu plus familiarisé avec WordPress… Etant relativement débutant, et disons le, amateur, connaîtrais-tu une extension permettant d’arriver à un résultat similaire? En effet le thème que j’utilise actuellement permet de créer de très belle pages portfolio, mais pas de les filtrer par catégorie ou mots clés…

    1. Oui il existe beaucoup de plugins mais il est vrai que de nombreux le proposent en natif (ce qui peut poser des bugs de compatiblité avec des plugins). Pas de plugins en tête, mais une recherche dans le répertoire officiel ou en premium te fournira sans doute de très bon résultats.

  3. Je rencontre un petit problème : l’animation ne s’effectue pas, les items sont là, mais dès que l’on clic dessus rien ne se passe. Quelqu’un peut-il m’aider ?

    1. Après vérification, j’ai vu que : sur ce passage
      function ntp_isotope_js() {
      if (!is_admin() && is_post_type_archive(‘portfolio’)) { ?>

      jQuery(function($) {
      Uncaught ReferenceError: jQuery is not defined
      $(window).load(function() {

      On me signale « Uncaught ReferenceError: jQuery is not defined  » à la ligne JQuery function. Personne pour m’aider ?

  4. Bonjour,

    J’apprécie vraiment ton blog car il me fait gagner un temps fou moi qui ne suis pas développeur … Par contre j’ai vu quelques points à corriger dans la page PHP sauf erreur de ma part ?

    echo  »;
    echo ‘Tout‘;

    à remplacer par

    echo  »;
    echo ‘Tout‘;

    sinon la fonction js ne point pas sur les bons éléments.

    Merci
    SR

    1. zut … visiblement problème d’interprétation, html dans le commentaire …

      je disais qu’il manque : class= »filter clearfix » dans le id= »portfolio-filter »

      et : class= »active » dans le href= »#all »

      @+
      SR

  5. Merci pour le tuto.
    Malheureusement, lorsque je fais charger le fichier jquery.isotope.min.js, celui ci ne l’est apparemment pas, puisqu’il n’apparaît pas dans les fichiers chargés (F12/Ressource).
    Aurais-je fais une mauvaise manipulation ?

  6. Salut Aurélien, tout d’abord un grand merci pour ce tutorial grandement utile !

    Cependant, mes filtres ne marches pas… Lorsque je clique sur un « type », il y a juste mon URL qui change /portfolio/#exemple-type.

    Voilà, je voulais savoir si tu savais pourquoi, car j’ai refais plusieurs fois le tuto et rien ne change.

    Deuxième question, mes contenant les posts sont plus grand que le thumbnail en lui même, pourquoi ?

    En attendant ta réponse, je te souhaite une bonne soirée !

    Merci

    Ludo

    1. (je rectifie car la balise -li- a été prise en compte )

      Deuxième question, mes -li- contenant les posts sont plus grand que le thumbnail en lui même, pourquoi ?

    2. Si le changement sur le type – autrement dit la bascule, ne s’effectue pas, alors il faut vérifier que les scripts se chargent bien via la console de Firebug par exemple sous Firefox.

      Pour la seconde question, il peut y avoir des régénération de miniatures à opérer également.

      Ma réponse est plutôt technique mais ce tutoriel s’adresse plutôt à des utilisateurs avertis.

  7. Bonjour,
    Je voudrais savoir comment récupérer le « type » de chaque item du portfolio en php.
    J’ai essayé avec la variable $termname mais celle-ci reste toujours la même, elle ne change pas en fonction de l’item

      1. Oui c’est ça. J’ai tout essayé ($termname, $term->name, la fonction get_term() …) mais sans succès.
        Je voudrais afficher sa catégorie à chaque item juste en dessous de celui-ci.

  8. Très bon article ! C’est justement ce que je recherchais. Dommage qu’il n’y ait pas plus d’info sur la page « single-portfolio.php »

  9. Bonjour !

    tout d’abord merci pour ce tuto très bien fait.
    Ensuite je souhaiterais signaler si certains d’entre ont les filtres qui ne fonctionnent pas qu’il manque deux fois « filter » dans le code html de archive-portfolio.php.
    à remplacer par

    quelques lignes plus loin :
    à remplacer par ;

    En tous pour moi cela fonctionne, sinon les filtres n’étaient pas actifs

    Pour finir j’aurais une question : comment afficher les archives du portfolio sur deux colonnes ?
    J’essaie désespérement depuis quelques heures mais je galère.
    J’ai bien vu que la boucle affichait un par boulot. Peut-être une boucle qui en affiche deux (un par colonne) ?

    Merci

      1. Voici le code du début de archive-portfolio.php
        http://pastebin.com/ciSZEi8c

        Je tente toujours d’afficher les items sur deux colonnes, en vain.
        J’ai essayé plusieurs mode layout, ai défini des largeurs de colonnes (ou pas), etc. rien n’y fait. Les items sont affichés en deux colonnes au chargement de la page (les 2 premières secondes), puis se repositionnent l’un en dessous de l’autre.
        Est-ce que cela pourrait venir du fait que tu utilises des UL et LI au lieu de DIV ?
        Sinon quelqu’un aurait-il la solution svp ?

        Merci

        1. Il y a une évolution : maintenant les items sont bien affichés sur deux colonnes lorsqu’on arrive sur la page. Mais si on clique sur un filtre, les items se repositionnent l’un en dessous de l’autre et non plus sur deux colonnes.

  10. Salut,

    Merci pour ce tuto vraiment très bien fait.
    J’ai une petite question concernant la personnalisation des thumbnails. J’ai beau changer le code css, retirer les « border : solid » mes thumbnails s’affichent systématiquement avec un rebord aux coins arrondis. Je ne sais pas où trouver le bon code css pour changer cela.

    Une idée ?

    Merci

  11. Bonjour
    Il y a une erreur dans le code de l’étape #3 à la ligne 31.
    Après le li id, apparaît {{{PHP7}}} alors qu’on devrait voir post_class(‘item-portfolio’); à l’intérieur d’une balise php pour que les classes puissent être ajouté aux items de portfolio.

    Sinon, très bonne explication de comment intégrer isotope dans WordPress.

  12. Bonjour, en effet cela ne peut pas marcher déjà à cause de la fonction wp_enqueue_script(), son paramètre $deps doit être un array or ici c’est un string donc écrire plutôt array(‘jquery’) ensuite ce code {{{PHP7}}} on ne voit pas très bien à quoi cela correspond.

    On ne comprend pas bien pourquoi le code js est mis dans le footer avec une balise script. On pourrait très bien l’enqueue en le faisant dépendre de isotope.non?

    a +

      1. Corrections effectuées pour la dépendance dans un tableau et le bug PHP7 – Pastacode bugue avec mon site mais problème signalé.

        Oui je suis d’accord avec toi pour l’inclusion du script. Ça revient au même en fin de compte…

        Et merci pour le if(!is_admin) qui est inutile, on m’avait fait la remarque au WordCamp mais je n’ai pas pensé à éditer les tutoriels qui en parlent.

Laisser un commentaire