Grunt et WordPress

Introduction

Petite pause dans mes articles du WCEU. Je vais aujourd’hui vous expliquer comment mettre en place un grunt pour vos développements de plugins/themes.

Pourquoi grunt ?

Grunt est un lanceur de tâches, en gros lorsque vous développez du javascript ou du css avec less ou sass ou autre, il incombe une étape de test/compilation/concaténation/qualité de code etc. Ces étapes sont rébarbatives, longues et surtout ne sont pas infaillibles en tant qu’humain.

C’est là que Grunt entre en action il permet, entre autre, de concaténer des scripts, de les compresser, de compiler du less, du sass, faire des tests unitaitres, lancer un jshint/lint etc.

Il faut savoir que WordPress lui même implémente ce genre de procédure et le tout est disponible sur http://develop.svn.wordpress.org/trunk/.

Vous allez donc automatiser vos constructions de ressources statiques de façon sûre et créer un code de qualité.

Installer Node.js

La première étape est d’installer node.js, il suffit de se rendre sur leur site http://nodejs.org/ et de télécharger l’installeur. Etant sur Windows, l’installation est rapide et facile, rien à faire et tout fonctionne. Sur les autres plateformes c’est encore plus facile.

Installer Grunt

Pour installer grunt il suffit d’ouvrir une invite de commande en faisant Démarrer > Executer > cmd.exe puis entrée.
Puis entrer le code suivant :

npm install -g grunt-cli

Vous devriez avoir quelque chose du genre :
grunt-install

Jusque là, tout va bien.

Créer son plugin avec grunt

Nous allons donc créer une extension qui va utiliser à son avantage les fonctionnalités de npm et aussi de grunt.
La première étape est donc de créer un dossier dans plugins, faisons ça tout doucement, il suffit de créer un dossier pour le plugin dans le dossier plugins.

A partir de là, il faut que depuis sa console on arrive jusqu’au dossier du plugin comme par exemple :
grunt-plugin-folder

Pas besoin de créer le fichier racine pour le plugin, on va juste mettre en place grunt avec ses ressources.

Créer le fichier package.json

Pour créer le plugin correctement il faut ajouter le fichier package.json, ce fichier va servir à décrire le plugin, sa version, ses dépendance l’auteur etc.. Bref un fichier readme.txt d’un plugin WordPress normal mais cette fois en json :

{
	"name": "plugin-grunt",
	"version": "0.0.0",
	"description": "",
	"author": ""
}

Là on a pratiquement rien mis, mais c’est déjà la base. Pour que notre projet soit bien décris, il est important de donner les dépendances de celui-ci dans grunt, c’est à dire en spécifiant celles-ci :

{
	"name": "plugin-grunt",
	"version": "0.0.0",
	"description": "",
	"author": "",
	"devDependencies": {
		"grunt": "~0.4.1",
		"grunt-contrib-jshint": "~0.6.3",
		"grunt-contrib-uglify": "~0.2.2",
		"grunt-contrib-concat":"~0.3.0",
		"grunt-contrib-watch":"~0.5.3",
		"grunt-contrib-imagemin" : "~0.3.0",
		"grunt-contrib-csslint" : "~0.1.2",
		"grunt-contrib-cssmin" : "~0.7.0"

	}
}

Donc là le gestionnaire de dépendances saura que pour faire fonctionner notre plugin avec grunt il va falloir avoir les modules de nodejs suivants installés. La liste des modules pour grunt est disponible sur http://gruntjs.com/plugins.
Petite description rapide des modules installés :

  • jshint : Vérification de la qualité du code js basé sur des « standards », ; oublié, virgule en trop à la fin d’un  objet javascript etc.. Les petites erreurs de code sont évitées.
  • uglify : Comme son nom l’indique, uglify va rendre le javascript moche, peu lisible mais très compact.
  • concat : concatène de fichiers entre eux, donc évite de devoir assembler soit même les fichiers.
  • watch : module très important, il permet de surveiller les modifications sur des fichiers et de faire des actions à ce moment là.
  • imagemin : optimisation des images, jpg, gif, png etc..
  • csslint : un peu comme jshint, l’extension va vérifier que le css est bien écrit et performant.
  • cssmin : minifie tout simplement les fichiers CSS.
  • csslint : un peu comme le jshint, mais pour le CSS.

L’intérêt d’avoir plusieurs modules différents c’est que l’on peut faire des tâches différentes suivant les cas, une tâche pour le dev et une tâche pour build le code.

A partir de là, on peut simplement lancer la commande suivante pour installer tous les modules nécessaires au bon fonctionnement de grunt :

npm install

Et là nodejs va aller chercher les packages nécessaires et les mettre dans le dossier node_modules. Dans la console ça devrait donner quelque chose du genre :grunt-npm-install

Il faut attendre la fin de la procédure.

Créer le fichier Gruntfile.js

Pour que grunt puisse s’y retrouver, il faut lui donner un fichier de configuration qui s’appelle Gruntfile.js.

Ce fichier va contenir les différentes tâches à faire en fonction de ce que l’on a entré dans la console. La base à écrire est :

// Ici c'est du javascript
module.exports = function(grunt) {
  grunt.initConfig({
// On lit le fichier de package
    pkg: grunt.file.readJSON('package.json')
  });
};

Mais là il ne se passe rien du tout, on ne lui a pas spécifié de tâches ou autre. Partons du principe que nous avons l’arborescence suivante :

-assets
--js
--script.js
--script2.js
--script3.js
---libs
---lib1.js
---lib2.js
---lib3.js
--css
--mon-style.css
---libs
---lib1.css
---lib2.css
--images
---src
----sprite.png
----image1.png
----image2.png

Nous avons donc deux cas :

  1. Développement : je veux avoir des tests sur mes fichiers, voir s’ils sont bien indentés etc.
  2. Construction : je veux créer un fichier final, minifié, sans les commentaires.

Il faut donc créer deux tâches qui vont exécuter deux actions différentes.

La tâche de développement

Je veux donc voir si mon code correspond à des normes et qu’il soit de bonne qualité. Nous allons donc utiliser le jshint et le csslint, mais nous pourrions utiliser des librairies de test unitaires pour le js aussi.

Nous allons donc écrire notre première tâche grunt :


// Ici c'est du javascript
module.exports = function(grunt) {
  grunt.initConfig({
    // On lit le fichier de package
    pkg: grunt.file.readJSON('package.json'),
    // Execution du csslint
    csslint : {
      // Sous élément dev
      dev : {
        src:['assets/css/**/*.css'] 
      }
    },
    // Execution du jshint
    jshint : {
      // Sous élément jshint pour le dev
      dev : {
        // Tous les fichiers sauf les librairies
        src: [ 'Gruntfile.js', 'assets/*.js' ],
        options: {
          // options here to override JSHint defaults
          globals: {
            jQuery: true,
            console: true,
            document: true
          }
        }
      }
    }
  });

  // On charge les plugins
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks("grunt-contrib-imagemin");
  grunt.loadNpmTasks("grunt-contrib-csslint");
  grunt.loadNpmTasks("grunt-contrib-cssmin");

  // Par défault on est en dev, donc on va charger les tâches de dev
  grunt.registerTask('default', ['csslint:dev', 'jshint:dev']);
};

En allant dans la console et en lançant :


grunt

Grunt va lancer la tâche default et hop les fichiers seront csslint et jshint.
Seulement, il faudrait lancer cette commande à chaque fois que on enregistre son fichier… C’est un peu embêtant, non ? C’est là que grunt-contrib-watch entre en jeu, son rôle ? Regarder ce qu’il se passe sur des fichiers et lancer des tâches en conséquence :


// Ici c'est du javascript
module.exports = function(grunt) {
  grunt.initConfig({
    // On lit le fichier de package
    pkg: grunt.file.readJSON('package.json'),
    watch: {
      scripts : {
       files: ['assets/js/*.js'],
       tasks: ['jshint:dev']
      },
      styles : {
        files: ['assets/css/**/*.css'],
        tasks: ['csslint:dev']
      }
    },
    // Execution du csslint
    csslint : {
      // Sous élément dev
      dev : {
        src:['assets/css/**/*.css'] 
      }
    },
    // Execution du jshint
    jshint : {
      // Sous élément jshint pour le dev
      dev : {
        // Tous les fichiers sauf les librairies
        src: [ 'Gruntfile.js', 'assets/*.js' ],
        options: {
          // options here to override JSHint defaults
          globals: {
            jQuery: true,
            console: true,
            document: true
          }
        }
      }
    }
  });

  // On charge les plugins
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks("grunt-contrib-imagemin");
  grunt.loadNpmTasks("grunt-contrib-csslint");
  grunt.loadNpmTasks("grunt-contrib-cssmin");

  // Par défault on est en dev, donc on va charger les tâches de dev
  grunt.registerTask('default', ['watch:scripts', 'watch:styles'] );
  // Là on charge les tâches watch:script et watch:styles en dev
};

Ce qui nous donne dans la console :
grunt-watch-result

Donc là au moment où j’ai enregistré mon fichier css, la tâche associée s’est lancée.

Juste en dessous la tâche watch n’est pas terminée, elle attend qu’un autre fichier soit modifié donc pas besoin de relancer la tâche à chaque fois.

La construction des fichiers pour la « production »

Imaginons que notre développement est terminé et que l’on doit livrer le plugin terminé. Il faut faire en sorte que les fichiers prennent moins de place et surtout qu’ils soient rassemblés.

On va donc créer une nouvelle tâche pour la ‘compilation’ de notre application :

Js


uglify : {
      dist : {
        files: {
          // Application minifiée
          'assets/js/app.min.js': [
            // Là je liste les fichiers
            // On commence par les libraries
            'assets/js/libs/lib1.js',
            'assets/js/libs/lib2.js',
            'assets/js/libs/lib3.js',

            // Puis mes fichiers personnels
            'assets/js/script.js',
            'assets/js/script2.js',
            'assets/js/script3.js'
          ],
        }
      }
    }

Dans notre cas on veut avoir les librairies dans notre fichier minifié mais on pourrait vouloir compiler dans deux fichiers différents ce qui donnerait ça :


uglify : {
      dist : {
        files: {
          // Application minifiée
          'assets/js/app.min.js': [
            // Mes fichiers personnels
            'assets/js/script.js',
            'assets/js/script2.js',
            'assets/js/script3.js'

          ],
          // Les librairies
          'assets/js/vendor.min.js' : [
            'assets/js/libs/lib1.js',
            'assets/js/libs/lib2.js',
            'assets/js/libs/lib3.js',

          ]
        }
      }
    }

Vouez avez compris le principe, on peut alors ajouter autant d’éléments que l’on veut. Il y a plusieurs options disponibles dans grunt uglify, vous pouvez aller voir la doc pour tout savoir.

CSS

Le CSS se passera comme pour le JS sauf que l’on va utiliser cssmin au lieu de uglify, le plugin a aussi ses propres options.
On a donc ça au final :


cssmin : {
      dist : {
        files: {
          // Application minifiée
          'assets/css/app.min.css': [
            // Mes fichiers personnels
            'assets/css/mon-style.css'

          ],
          // Les librairies
          'assets/css/vendor.min.js' : [
            'assets/css/libs/lib1.css',
            'assets/css/libs/lib2.css'
          ]
        }
      }
    }

Ce qui va donc créer deux fichiers. Sachez que des opérateurs du type ‘assets/css/libs/*.css’ vont aussi faire le boulot, sachant que les fichiers seront pris dans l’ordre alphabétique du dossier pour être compilés, cela peut être utile si vous avez beaucoup de fichiers et vous ne voulez pas gérer le fait de devoir ajouter les fichier dans la liste.

Images

Oui, on veut aussi optimiser un petit peu nos images. C’est aussi simple que pour le reste des modules :


dist : {
        options: {
          // On spécifie un niveau d'optimsations importat
          optimizationLevel: 7
        },
        files: {
          'assets/images/sprite.png' : 'assets/images/src/sprite.png', // 'destination': 'source'
          'assets/images/image1.png' : 'assets/images/src/image1.png',
          'assets/images/image2.png' : 'assets/images/src/image2.png'
        }
      }

N’oubliez pas d’aller voir dans la doc pour plus d’options ;).

La compilation

Il faut juste ajouter la tâche à la fin du fichier Gruntifle.js :


    grunt.registerTask('dist', ['uglify:dist', 'cssmin:dist', 'imagemin:dist'] );

 

Maintenant on va dans sa console et on tape :

grunt dist

Comme vous pouvez le voir, j’ai spécifié la tâche à executer. Et là on peut avoir un résultat équivalent à ça :

grunt-compilation-result

Voilà en plus grunt nous donne un rapport complet de la compilation, sachez qu’en ajoutant -v dans la ligne de commande on va pouvoir avoir un mode verbeux et donc beaucoup plus d’informations, plus de commandes sur le site de grunt.

Conclusion

Bon vous avez un peu la vision de la base de la base de ce que l’on peut faire avec grunt, sachez que vous pouvez lancer des tâches lors d’actions git par exemple. Vous arrivez sur votre serveur de production, vous faites un « git pull » et là automatiquement grunt va recréer, reminifier les scripts et css automatiquement, pratique non ?

Il y a beaucoup d’autres applications disponibles et de manières de faire, regardez ce qu’on fait les créateurs de WordPress, c’est tout autre chose. Bref allez voir la doc ça ne vous fera pas de mal :).

Si je devais résumer l’article en quelques mots :

Automatisez, automatisez automatisez

WCEU : Perfect your images using WordPress

wceu-pyiuw

Cet article est la suite de ma retranscription des conférences du WordCamp Europe 2013. Elle s’intitule Perfect your images using WordPress  et elle a été présentée par Mike Schroder et Marko Heijen. Ces deux orateurs sont contributeurs core sur les dernières versions de WordPress.

La conférence est disponible sur Speakerdeck.

Manipuler les images avant la 3.5

Avant que l’on passe à la 3.5, manipuler des images dans WordPress était assez compliqué et surtout difficile. On utilisait la Librairie GD qui permet de faire tout type de modifications sur les images.

Cependant le problème de cette méthode est que l’on utilise directement GD, il n’était pas possible d’utiliser d’autres librairies de façon facile et rapide. WordPress 3.5 introduit une couche d’abstraction qui permet alors d’utiliser le système en place sur le serveur pour manipuler les images. GD n’étant pas le plus performant et le plus complet des systèmes, il se pouvait que l’on voulait utiliser Imagick. On a alors créé une couche d’abstraction qui va permettre de ne plus se préoccuper de ce qui est installé sur le serveur.

WP_Image_Editor

Grâce à cette classe, on va pouvoir faire toute sorte de manipulations :  

  •  Lire une image
  • Manipuler l’image
  • La sauvegarder
  • La streamer si besoin

On peut demander à ce que l’image soit enregistrée dans plusieurs tailles et dans plusieurs formats de façon facile et en temps réel, on peut même demander que l’image soit enregistrée dans le format PDF.

Comment a été créée la classe

Le chantier de transformation du code de WordPress était énorme, tout était à remettre en ordre. Cette classe est le fruit de la coopération internationale des deux auteurs. WordPress utilise beaucoup les images donc les modifications ont été en profondeur pour le core.

L’avantage de cette classe c’est qu’elle est magique, elle donne au développeur la puissance contenue dans le core de WordPress. Pas besoin d’instancier, de tester soit même tout se fait par magie et en fonction des capacités de notre serveur.

Le support

La nouvelle classe supporte Imagick et GD avec :

  • 88% des serveur ont GD
  • 65% des serveur ont Imagick

Il faut savoir que Imagick est plus performant mais surtout plus stable. Il supporte les profils de couleurs, sans Imagick il y a automatiquement une couche de vert sur les photos ce qui les dénature. Les photographes ont alors des problèmes pour mettre des photos sur un WordPress car leurs profils de couleur sont ruinés.

Beaucoup de filtres ont disparu du core WordPress qui est du au fait que l’on utilise plus les méthodes la librairie GD directement. Donc mettez à jour vos plugins qui manipulent les images pour la version 3.5+.wceu-pyiuw-filtres

Les limites

Le problème actuellement est que pour manipuler des images dans WordPress, par exemple lors de l’upload, il faut faire pas mal de manipulations. Des queries dans la base de données etc…

La solution serait peut être d’utiliser une classe WP_Image, le projet est sur github donc à tester et à contribuer, ils attendent un maximum de retour sur cette pour qu’un jour peut être elle puisse être ajoutée dans core WordPress.

Les possibilités de la classe

A partir d’une ressource de wp_image_editor, on peut faire beaucoup de choses comme redimensionner mais aussi à partir d’une image créer plusieurs tailles d’image, croper, tourner, retourner, enregistrer dans un fichier ou l’afficher en stream aussi ! En bref toutes les transformations sont imaginables, on peut ajouter des fonctionnalités sur nos classe d’éditeur. On peut imaginer créer un simili-instagram pour créer toutes sortes d’effets à nos photos et donner la main aux utilisateurs sur ceux-ci.

Si on regarde l’exemple de code de la présentation, on transforme juste l’image dan un autre format, mais on peut créer des formats multiples, l’enregistrer en pdf, jpg, bmp etc. les possibilités sont infinies.

Exemple concret, les images au format TIFF sont des images mais les navigateurs n’affichent pas du tout ces images donc il est nécessaire de les transformer en quelque chose de lisible.

Le mot de la fin :

I don't always resize, but when I do, I use WP_Image_Editor

Le mot de la fin des auteurs

En conclusion, utiliser WP_Image_Editor, vous pouvez faire tout ce que vous souhaitez, l’outil est là à votre disposition et surtout il est simple d’utilisation donc ne vous privez pas !

WCEU : Between glorified computer interface and ultimate narcissist : finding what the client needs

glorified1

Cet article est la suite de ma retranscription des conférences du WordCamp Europe 2013. Cette fois encore elle fait partie des conférences LEARN, elle s’intitule Between glorified computer interface and ultimate narcissist : finding what the client needs et elle a été présentée par Monica Guerra Leiria ou @jesterstear.

L’oratrice est une ancienne designer, elle est passée par différentes agences et société, son pose a évolué au fur et à mesure du temps.

Magazine

Elle a travaillé tout dabord dans le print, là tout est figé, rien ne bouge par exemple le magazine sur lequel un de ses collègues travaillait ne voulait aucune modifications. Le designer proposait des choses nouvelles mais il ne pouvait rien. Le client ne voulait rien changer, il ne peut pas être force de proposition. Le client a toujours raison, il prévaux sur le designer. Ce qui donne ça:

Les demandes des clients sont parfois farfelues et sont souvent comme ça

 

Quand on laisse le client tout choisir, sans l’accompagner ça donne le schéma ci-dessus. La création devient un arbre de Noël, l’astuce est de bien forcer le trait sur ses demandes comme ça il va venir vers le designer pour qu’il l’aide à faire des choix.

Agence de communication

Là c’était le boss qui était au dessus de la chaine, cependant il avait l’aval sur le client ET le designer. Impossible de faire passer son opinion, les demandes folles du client deviennent celles du boss et impossible de réussir à faire passer ses idées. Le schéma ci-dessus se déplace tout simplement vers le boss.

Freelance

Là, l’oratrice pensait que tout serait super, pas de bruit entre le client et elle même. Elle sera la reine, elle aura les rennes du processus de création !

Cependant on devient comme le client et le boss plus tôt, on ne prend pas en compte l’avis et les envies du client, on est le chef, on a raison et il n’a pas son mot à dire.

C’est là qu’il faut prendre en compte l’avis du client mais surtout sa personnalité, ses envies. On finit par ne plus se battre avec son client, on ne perd pas de temps à imposer son avis. Car imposer son avis demande beaucoup d’énergie et le client ne comprend pas forcément notre avis.

Il faut poser des questions à son client, beaucoup de questions. Le client aura toujours un avis sur telle ou telle chose :

  • Changer une police
  • Changer la position du logo
  • Qui êtes-vous ?
  • Quel est le message à faire passer

Finalement nous ne sommes pas frustrés, le client non plus car chacun a pu donner son avis.

Ce que je veux imposer au client n’est pas ce dont j’ai besoin, le client est dans cette même position. On est alors force de proposition et pas d’imposition, ce qui est proposé est adapté au besoin du client. Nous ne sommes qu’une partie du process de la création du site, nous ne sommes pas le site. Pour que tout ça fonctionne on va prendre beaucoup de temps à écouter le client avec des échanges email ou coups de téléphone.

Les erreurs

C’est en faisant des erreurs que l’on va pouvoir atteindre la balance avec les clients, au final le designer et le client sont au même niveau, il n’y a pas de rôle prédominant. Il faut faire ces erreurs car on va pouvoir les corriger et avancer, ne pas les répéter. Dans cet état d’esprit on a envie d’avancer, de se donner pour pouvoir satisfaire au mieux le client et se faire plaisir dans les créations.

Et WordPress ?

L’oratrice nous dit que WordPress est simplement la cerise sur le gateau, le fait que le client peut modifier des choses, avoir la main sur son contenu rend le client plus facile à gérer et surtout il fait partie du process de création du site.

L'oratrice dans sa dernière slide

L’oratrice dans sa dernière slide

WCEU : The life of a theme

wceu-lifeofatheme

Cet article est la suite de ma retranscription des conférences du WordCamp Europe 2013. Cette fois encore elle fait partie des conférences LEARN, elle s’intitule The Life of a Theme et elle a été présentée par Tammie Lister ou @karmatosed.

Voici le lien vers sa conférence : https://speakerdeck.com/tammielis/the-life-of-a-theme

L’oratrice est, en fait, la designer de plusieurs WordCamp dont le WordCamp Europe !

La vie d’un thème

Un thème c’est un peu comme une personne, il passe par plusieurs stades, fait des erreurs, a des problèmes bref tout varie ! On fait donc évoluer le process au fur et à mesure que le thème avance.

Le début

C’est un peu la petite étincelles qui va mettre en marche le projet, pour l’oratrice ça demande beaucoup d’énergie car il faut arriver à se mettre en idées des choses alors que l’on a rien à ce moment là! Même si cette idée est fragile elle permet de lancer le process de création

Le planning

Le planning est essentiel, il peut être aussi petit qu’énorme. Dans tous les cas il en faut un pour pouvoir prendre du recul sur ce que l’on fait. Le planning permet de prendre en compte les tests utilisateurs. Prévoir aussi la mise en place du thème etc.

Les moodboard

Les moodboard est un peu un méli-mélo des envies, idées ou vues. En gros il sert à se donner une idée de la direction que veut prendre le designer. C’est le mashup de ce que l’on voudrait comme idée générale. Pour l’oratrice c’est la partie excitante et fun car elle laisse l’imagination vagabonder et n’a pas de limites, par d’internet explorer, pas de bug etc. Tout est beau et la motivation est là !

L’oratrice nous donne des outils de moodboard :

 Styleguide

C’est un peu une charte graphique, elle va donner les différentes idées du style du site :

  • Couleurs
  • Menus
  • Formulaires
  • Textes
  • Typos
  • Styles dans le contenu

L’oratrice donne encore quelques outils :

Sketch

C’est en fait le mockup souvent fait à la main, c’est en fait le zoning du site sans information et il est créé très rapidement. On y inclus aucune couleur, aucune image juste les idées, juste un placement des choses pour avoir une vue d’ensemble et voir si ça fonctionne comme ça.

Quelques outils encore :

  • Penultimate
  • Evernote
  • Bamboo stylus
  • Ipad Mini

Wireframes

C’est un peu comme les sketch décris plus haut mais en fait ils sont plus complets et propres. Les couleurs et les emplacement des éléments dans la page sont bien définis, on peut cliquer sur les différents éléments dans la page et on peut un peu naviguer dans le site. C’est une partie un peu fun car on voit son travail « s’animer ».

Comme outil elle recommande balsamiq.com.

Build

C’est là que le fun s’arrête, on va commencer à construire et développer. L’oratrice utilise un starterkit de thème nommé _underscore. Il permet d’aller vite pour créer une base de thème propre et bien faite. Il y a aussi Skeleton qui peut servir de base. Même une base personnelle peut faire l’affaire, ne vous limitez pas mais tentez de partir toujours sur la même base pour que l’architecture soit pérenne et que lorsque l’on revient sur le projet on retrouve nos petits. Ne partez plus de kubrik !

Filter

Pour que tout soit développé au mieux, utilisez les coding standards de WordPress, il y a aussi le Theme Development Checklist qui permet de ne pas se perdre en cours de route de développement et proposer un thème qui va fonctionner dans presque tous les cas. Ils nous servent aussi à savoir où l’on en est dans le développement. Vous pouvez aussi utiliser WP fill me , il va donner plus ou moins tous les éléments qu’un utilisateur va pouvoir entrer dans l’éditeur de WordPress et donc prévoir tous les styles côté front-end.

Testing

C’est là où tout se corse, c’est un monde qui fait peur car des personnes extérieures au projet vont tester. Il va y avoir une seconde opinion sur le travail et vont donner leur avis. Cet avis extérieur va aussi permettre d’éviter des problèmes lors du passage sur wordpress.org. On va pouvoir tester sur des sites comme browserstacks.org (mobiles) mais il y aussi et surtout les machines virtuelles qui permettent de tester dans les conditions les plus proches des utilisateurs.

Launch

Le lancement peut être douloureux mais si on respecte toutes les étapes précédentes alors c’est beaucoup plus facile.

Refine

Le fait le lancer le projet ne veut pas dire qu’il est maintenant figé, ce n’est pas la fin. Il y a des bugs, des améliorations etc. Il faut prendre en compte les retours utilisateur, ils vont faire changer les choses, une fonctionnalité pensée lors d’une des étapes précédentes peut se retrouver totalement inutile au final.

Conclusion

L’oratrice nous a donné quelques trucs et quelques outils pour mener à bien la création de son thème, sa conférence a plutôt mis l’accent sur la création de thèmes pour le repository officiel mais ses conseils valent aussi bien pour un projet non open source. Ne pensez pas qu’un projet est fini dès lors qu’il est mis en production. Les clients ont toujours des envies et besoins différents. Si les étapes précédentes ont été respectées alors faire des évolutions ne posera pas plus de problèmes que ça car tout est bien organisé et réfléchis.

Faites des thèmes mais faites les biens et la qualité globale de WordPress augmentera de la même manière.

WCEU : Better Site Stacks with Composer

wceu-composer2

Cet article est la suite de ma retranscription des conférences du WordCamp Europe 2013. Cette fois encore elle fait partie des conférences LEARN, elle s’intitule Better Site Stacks with Composer et elle a été présentée par Andrey Savchenko ou @Rarst.

Vous pouvez retrouver sa conférence sur WordPress TV.

Que nous dit notre orateur ?

Tout d’abord il nous explique ce qu’est un dependency manager ( ou gestionnaire de dépendances ). En gros c’est un moyen de déclarer que notre code dépend d’une libraire ou d’un autre code. Les développeurs créent du code, beaucoup de code mais ils ne savent pas, réellement, si au moment de déployer leur code il va fonctionner, justement a cause de ces dépendances.

Si chaque plugin commence par inclure sa propre librairie, dans sa propre version on va avoir des conflits. Une librairie incluse plusieurs fois dans PHP va déclencher une erreur fatale et le site sera planté.

Pour répondre a ce genre de problématiques il y a le PHP5.3 avec le namespacing qui permet d’avoir moins de problèmes de collision de nom de classe.

Le standard PSR-0 permet de généraliser le autoloading de classes,. Si jamais on appelle une classe qui n’existe pas, en dernier recours on peut mettre en place une fonction qui va tenter de charger la classe correspondante avant que le code ne plante complètement. Ce standard permet d’uniformiser l’arborescence des fichiers, mais je vous invite à consulter le site.

Une solution ?

Pour l’orateur ces solutions ne sont pas complètes, ce n’est pas automatisé, il faut gérer les dépendances soit même, on en sait pas vraiment si les libraires ou plugins sont présents, s’ils sont à la bonne version etc.

La solution serait donc d’utiliser Composer. Composer va se nourrir de différentes sources pour télécharger ses dépendances :

  • Téléchargement direct
  • SVN : un gestionnaire de versions
  • GIT : un gestionnaire de version aussi
  • Mercurial : encoreu n gestionnaire de versions
  • Pear (packages) etc.

Pour déclarer là où l’on peut trouver les éléments à télécharger, on déclare un fichier packages.json. Pour pouvoir trouver les sources, on peut aller sur https://packagist.org/ qui va nous donner des

Le fichier composer.json lui va déclarer ce que le projet à besoin, c’est à dire ses dépendances, la version de la dépendance etc. Ce qui est intéressant c’est que l’on peut dire que notre projet dépend d’une version d’un package mais surtout la possibilité de dire que l’on a besoin de n’importe quelle version du package dans la version 1.*. C’est un peu comme quand dans un plugin on dit qu’il a besoin d’au moins la version 3.0 de WordPress pour fonctionner.

Donc si un plugin demande la version 1.5 alors composer va prendre la version 1.5 comme on a spécifié que l’on a besoin de n’importe quelle version de la 1.x.

Et WordPress ?

Dans WordPress ce n’est pas actuellement en place cependant les challenges sont :

  • Amener ça au niveau du core WordPress
  • Avoir un accès au repository de WordPress et ainsi faciliter la mise en place des sites
  • Gérer les assets de façon facile

N’oublions pas que composer n’est pas dédié à PHP, on peut l’appliquer aussi au CSS ou au javascript. C’est un peu comme ce que l’on peut rencontrer avec d’autres gestionnaires comme dans nodejs et npm (node package manager ) ou Bower. On déclare les dépendances et tout se télécharge dans des dossiers spécifiés.

Conclusion

Cette technique permet de solidifier nos sites, gérer automatiquement ce genre de choses rend les mises à jour ou les installations plus simples et moins stressants. Est-ce que nous n’allons pas oublier un fichier ? La dépendance est-elle en place ? Le module ne manque-t-il pas ?

Il ne faut pas seulement appeler ses site des webapps mais il faut faire en sorte que se soit vraiment une webapp.

L’image de la fin :

wceu-composer

WCEU : Unit testing like a pirate

Comme vous le savez peut être le WordCamp Europe s’est déroulé à Leiden du 5 au 7 octobre 2013. Durant ces 2 jours les conférences étaient rassemblées par thème. Celle-ci fait partie des conférences LEARN et le sujet est le test unitaire et elle est présentée par Ptah Dunbar.

Tout d’abord vous pouvez retrouver la conférence ici :


 

Mais que nous dit notre orateur ?

WordPress devient de plus en plus une plateforme pour créer des applications. La simplicité de l’administration permet de manier ses données de façon simple et surtout la pléthore des plugins d’étendre ses possibilités. Par exemple la plateforme live ninja qui utilise WP avec BuddyPress mais aussi nodejs. Doonc il est possible d’utiliser WordPress comme App.

Les plugins

Les plugins sont le coeur de WordPress, leur multiplicité permet de répondre aux différents besoin. La question est : Votre plugin peut-il être utilisé dans une grosse structure de Webapp ? On trouve beaucoup de plugins mais la qualité du code du repository de WordPress n’est pas bonne, alors qu’il faut se concentrer sur cette qualité. Déployer du nouveau code peut avoir des effets indésirables sur d’autres fonctionnalités, c’est ce que l’on appelle des effets de bord et il n’est pas facile de les détecter.

Actuellement :

  • Tests fonctionnalités par fonctionnalités, une fonctionnalité finie, on valide puis on passe à la seconde
  • C’est lent, il faut aller les faire soit même, cliquer, mettre les données, valider etc.
  • On va surtout manquer des choses, on ne peut pas gérer tous les effets de bord

On a besoin de tester nos plugins, d’être sûr que tout fonctionne parfaitement, que nos clients soient contents.Il faut que se soit rapide et que la réponse soit claire, que tout soit réutilisable, donc que tout soit fiable.

Cependant PHP comparé aux autres langages n’est pas mature par rapport a ces demandes. On voit bien que Ruby, Python et autres sont bien adaptés pour gérer ce genre de choses.

La solution :

Le Unit testing bien sûr ! ( ou les tests unitaires ). On va donc écrire des test unitaires, ils   vont donner une réponse fiable sur ce qu’il s’est passé. Un test va tester une fonctionnalité et une seule fonctionnalité ! Ces test permettent de séparer le design du code, bien sûr ça ne teste pas le code javascript mais on est sûrs que le processus PHP s’est bien passé.

Les tests unitaires dans PHP :

Le framework de tests unitaires présenté est PHPunit et il y a le petit framework français atoum qui utilise les fonctionnalités de PHP 5.3 pour créer les tests.

Définition :

Un test unitaire : c’est un bout de code qui s’execute des certaines conditions, il y a ne valeur attendue et une valeur reçue, on vérifie donc que ce que l’on attend et ce que l’on reçoit est exactement pareil. Même si le résultat attendu est une erreur. Pour savoir si en passant un certain argument on retourne bien une WP_Error, on peut et on doit le tester.

Une suite de tests : Un ensemble de tests unitaire qui s’exécutent. Nous pouvons donc créer un ensemble de tests qui vont vérifier un ensemble de fonctionnalités comme par exemple un panier de site ecommerce etc.

Assertion : ce que l’on attend, on attend donc une valeur et la teste dans l’environnement réel pour savoir si tout s’est bien passé. Si on attend 56 mais que la fonction renvoie 10 alors le test échoue !

Un ensemble de fonctionnalités inhérentes au framework sont disponibles comme tester si on retourne bien true ou false que ce n’est pas NULL ou que le résultat contient une certaine valeur etc. (Voir la page 31 de la présentation )

La création d’un test unitaire :

Pour créer un test unitaire c’est simple, il ne faut que 3 choses : Une assertion ( ce que je veux ), une action ( ce que le code fait ) et un contexte d’exécution.

Exemple :

On veut tester une fonction d’addition, on va donc créer deux variables que l’on veut additionner par exemple 3 et 4 (contexte), on va exécuter notre fonction d’addition sur notre contexte (action) et vérifier que l’on va bien obtenir notre résultat, 7 (assertion). Si le test se passe bien alors il va signaler que tout s’est déroulé comme prévu.

Par contre il est plus difficile d’appliquer ça à WordPress car les plugins sont souvent mis dans des contextes ( hooks ). C’est donc dans la dernière partie(assertion) que la difficulté se trouve, il faut pouvoir prévoir ce que WordPress va nous retourner. Le plus simple est de découper son code de façon à ce qu’il soit testable de façon facile.

On peut donc tester son cache, vérifier des requêtes SQL etc. La meilleure façon d’écrire ses tests est de faire la liste des données requises et des conditions requises pour chaque fonctionnalité pour bien créer le bon contexte et créer l’interface utilisateur d’abord puis d’ajouter le code par dessus par la suite.

Je vous conseille de parcourir sa conférence pour avoir plus d’exemples.

L’auteur a créé un squelette de plugin qui va prendre en compte les tests unitaires :

https://github.com/ptahdunbar/wp-skeleton-plugin/

Conclusion :

Ce que nous pouvons retenir de cette conférence est qu’il est nécessaire et même indispensable de créer des tests unitaires, nous passons beaucoup de temps pour les écrire mais c’est la garantie d’éviter le maximum d’erreurs de syntaxe, de variable mal écrite etc.

Donc les tests unitaire bouffez-en et surtout habituez vous à en faire, qui sait ? Peut être un jour un de vos plugin deviendra payant et demandera d’avoir une qualité professionnelle et avoir un gros bug d’une version vous fera perdre des clients.

Ajouter un bouton dans l’éditeur WordPress

tinymce

Introduction

Il peut arriver que l’on doive ajouter un bouton dans l’éditeur de WordPress. Cela peut être pour des raisons pratiques comme par exemple quand on a un short un petit peu compliqué à mettre en oeuvre. Par exemple si notre shortcode va avoir des paramètres multiples et compliqués comme un id de post, de catégorie etc… Partons du constat que nous voulons mettre en place un shortcode qui va afficher les derniers articles d’une catégorie et d’un type de contenu en particulier. Nous n’allons pas demander à notre utilisateur de connaître ses id de taxonomie ou de termes et aussi les slugs des types de contenu.

Donc un petit bouton dans l’éditeur peut être utile.

 Le code pour le bouton

TinyMce permet à travers une API de faire toute sortes de choses, comme des styles en plus et dans notre cas ajouter un bouton avec un comportement particulier.

Cet ajout se passe du côté du javascript et le traitement peut se passer du côté PHP, pour ma part j’aime passer par la thickbox de WodPress et une page en ajax, avec une interface et un vrai formulaire pour que se soit le plus simple pour l’utilisateur et surtout ne pas charger des librairies en plus pour l’interface utilisateur.

Pour le code PHP, c’est assez simple à mettre en place mais il faut bien sûr différencier l’administration de la partie client. Pour se faire nous aurons besoin d’un fichier javascript, d’une image pour le bouton mais aussi d’un fichier qui va se charger de la partie admin et de la partie client. Pour se faire je ferais un petit zip avec tout ça à la fin de l’article !

PHP

La base du plugin est la suivante, elle est comme celle de l’article parlant de la mise en place d’une extension :


<?php /*
Plugin Name: My tinyMce Button
Plugin URI: http://nicolas-juen.fr
Description: Add tinymce button
Version: 1.0
Author: Rahe
Author URI: http://blog.nicolas-juen.fr
*/

define('MTMCE_URL', plugins_url('/', __FILE__));
define('MTMCE_DIR', dirname(__FILE__));
define('MTMCE_VERSION', '1.0');

require_once (MTMCE_DIR . DIRECTORY_SEPARATOR . 'inc' . DIRECTORY_SEPARATOR . 'class.client.php');
function MyTinyMceButton_Init() {
global $myTinyMce;

// Load translations
load_plugin_textdomain('mytmceb', false, basename(rtrim(dirname(__FILE__), '/')) . '/languages');

// Load client
$myTinyMce['client'] = new myTinyMceButton_Client();

// Admin
if (is_admin()) {
require_once (MTMCE_DIR . DIRECTORY_SEPARATOR . 'inc' . DIRECTORY_SEPARATOR . 'class.admin.php');
$myTinyMce['admin'] = new myTinyMceButton_Admin();

}
}

add_action('plugins_loaded', 'MyTinyMceButton_Init');
?>

Classe Admin :


<?php class myTinyMceButton_Admin{

function __construct() {
// init process for button control
add_action( 'admin_init', array (&$this, 'addButtons' ) );
add_action( 'wp_ajax_mybutton_shortcodePrinter', array( &$this, 'wp_ajax_fct' ) );
}

/*
* The content of the javascript popin for the insertion
*
*/
function wp_ajax_fct(){
?>
<h2></h2>
<!--?php _e("Category: ", 'mytmceb');?-->
<!--?php wp_dropdown_categories(array('name' =--> 'mcb_category', 'id' => 'mcb_category'));?>

<!--?php _e("Number of posts: ", 'mytmceb');?-->
<input id="mcb_number" type="number" min="-1" name="mcb_number" value="-1" />
<p class="description"></p>
<input class="button-primary" id="mcb_button" type="submit" name="mcb_button" value="<?php _e(" />">
<!--?php die();<br ?--> }

/*
* Add buttons to the tiymce bar
*/
function addButtons() {
// Don't bother doing this stuff if the current user lacks permissions
if ( ! current_user_can('edit_posts') && ! current_user_can('edit_pages') )
return false;

if ( get_user_option('rich_editing') == 'true') {
add_filter('mce_external_plugins', array (&$this,'addScriptTinymce' ) );
add_filter('mce_buttons', array (&$this,'registerTheButton' ) );
}
}

/*
* Add buttons to the tiymce bar
*
*/
function registerTheButton($buttons) {
array_push($buttons, "|", "mybutton");
return $buttons;
}

/*
* Load the custom js for the tinymce button
*

*/
function addScriptTinymce($plugin_array) {
$plugin_array['mybutton'] = MTMCE_URL. '/inc/ressources/tinymce.js';
return $plugin_array;
}

}
?>

Donc en décrivant ce qu'il se passe, nous avons deux actions :

  1. L'ajout du bouton dans l'éditeur
  2. L'ajout de l'action ajax ( si vous voulez savoir comment ça marche, vous pouvez vous reporter sur l'article qui explique l'ajax dans WordPress )

Simplement, l'action dans 'admin_init' permet de vérifier si l'utilisateur a les droits suffisants et surtout ajouter deux filtres pour mettre en place le fichier js et aussi ajouter notre bouton à la liste des boutons des tinyMce. Il faut savoir que chaque bouton doit avoir un slug unique! Ici nous utilisons le slug 'mybutton'. Donc notre fichier javascript qui gère le comportement du bouton est inclus seulement si le bouton apparaît dans la liste des boutons.

La méthode wp_ajax_fct permet juste d'afficher notre formulaire pour choisir la catégorie que l'on veut utiliser pour afficher nos articles mais aussi le nombre d'articles à afficher.

Javascript

Pour le javascript, il suffit d'avoir un seul fichier pour que ça marche :


(function() {
var called = false;
tinymce.create('tinymce.plugins.mybutton', {
init : function(ed, url) {
ed.addButton('mybutton', {
title : 'My button',
image : url + '/images/mybutton.png',
cmd : 'mceMyButtonInsert',
});

ed.addCommand('mceMyButtonInsert', function(ui, v) {
tb_show('', ajaxurl + '?action=mybutton_shortcodePrinter');
if(called == false) {
called = true;
jQuery('#mcb_button').live("click", function(e) {
e.preventDefault();

tinyMCE.activeEditor.execCommand('mceInsertContent', 0, mybutton_create_shortcode());

tb_remove();
});
}
});
},
createControl : function(n, cm) {
return null;
},
});
tinymce.PluginManager.add('mybutton', tinymce.plugins.mybutton);
})();

function mybutton_create_shortcode() {
return '[my-listing category="' + jQuery('#mcb_category').val() + '" posts_per_page="' + jQuery('#mcb_number').val() + '"]';
}

Rapide tour de  ce qu'il se passe, on ajoute donc une action spéciale sur notre bouton avec le tinymce.PluginManager.add('mybutton', tinymce.plugins.mybutton); et nous déclarons la fonction associée avec tinymce.create('tinymce.plugins.mybutton', ,il ajoute aussi le bouton dans la barre. Comme vous pouvez le voir, on peut mettre une image ( très recommandé ) à notre bouton pour qu'il soit facilement repérable dans l'éditeur. Nous ajoutons aussi l'effet que le click au bouton va déclencher avec cmd : 'mceMyButtonInsert', et avec ed.addCommand('mceMyButtonInsert', nous attrapons l'appel pour pouvoir déclencher la fonction qui nous intéresse à ce moment là.

Dans notre cas nous appelons thickbox avec notre action ajax et après nous ajoutons l'action live sur le bouton de validation de notre petit formulaire dans la thickbox. Au click on lance tout simplement une insertion de contenu en appelant notre fonction mybutton_create_shortcode qui va retourner à tinyMce la chaîne à insérer.

Dans notre cas on insère le shortcode avec les arguments sélectionnés.

 La partie client

Pour la partie client, on va juste ajouter le shortcode et l'interpréter :


<?php class myTinyMceButton_Client {
function __construct() {
add_shortcode( 'my-listing' , array( &$this, 'shortcode' ) );
}

function shortcode( $atts ) {
extract( shortcode_atts( array(
'category' => 0,
'posts_per_page' =>5,
), $atts ) );

if ( empty( $category ) )
return false;

ob_start();

$q_posts = new WP_Query( array( 'post_type' => 'post', 'category__in' => $category, 'posts_per_page' => (int)$posts_per_page ) );

if( $q_posts->have_posts() ) {
?>
<ul>
<ul><?php while( $q_posts->have_posts() ) {</ul>
</ul>
 
<ul>
<ul>$q_posts->the_post();</ul>
</ul>
?>

<!--?php </p-->

}
?>

<?php wp_reset_post_data();
}

$content = ob_get_contents();
ob_clean();
return $content;
}
}
?>

Donc pour le shortcode, on ajoute juste le shortcode, on vérifie que la catégorie a été fournie et on affiche le nombre d'articles demandés dans un ul/li.

Conclusion

Vos utilisateurs ont besoin d'interfaces et ceci est une des possibilités de donner les clés à vos utilisateurs pour ajouter du contenu "dynamique" dans leur article ou autre. En plus avec les shortcodes, l'affichage peut être altéré par la suite ou adapté.

C'est aussi l'assurance d'avoir plus ou moins la main sur l'effet et la présentation des données.

Ajouter un bouton ne demande pas beaucoup de code alors facilitez la vie à vos utilisateurs :)

Pour le fichier zip contenant tout le petit plugin c'est par ici.

JQuery et WordPress

20090715101242!Jquery-logo

Introduction

Souvent dans les plugins et thèmes, le javascript ( jQuery notamment ) à une place assez importante dans les différentes fonctionnalités. Ajax, validation de formulaire, lightbox, sliders etc. toutes ces fonctionnalités utilisent le javascript et donnent à l’utilisateur une impression de plus grande interactivité.

WordPress lui même utilise beaucoup le javascript dans ses fonctionnalités ! Essayer d’aller dans la page de gestion des widgets sans javascript ou en activant le mode accessibilité dans les options de l’écran des widgets… c’est tout de suite moins fun !

WordPress inclus dans ses fichiers jquery, mais aussi jquery ui qui est maintenant en librairie complète depuis la 3.3 !

Inclure des fichiers javascript

Il faut savoir que WordPress propose une API particulière pour pouvoir inclure ses fichiers javascript de façon élégante et surtout en gérant les priorités et les dépendances.

Cette fonction s’appelle « wp_enqueue_script« , elle accepte les arguments suivants:

  1. Un identifiant de script UNIQUE ( string )
  2. Le chemin vers le fichier à inclure ( url, string )
  3. Les dépendances ( array )
  4. La version du script (string)
  5. Inclure ce fichier dans le footer ? ( boolean )

Par exemple, si je veux inclure mon fichier pour le slider de la home qui a besoin de jquery pour fonctionner je peux faire de la façon suivante:


<?php
wp_enqueue_script( 'mon-slider', get_bloginfo('stylesheet_directory').'/js/monscript.js', array( 'jquery' ), '1.0', true );

Donc nous allons charger la librairie depuis notre thème en demandant d’avoir jquery de chargé avant de charger mon script et surtout de la mettre dans le footer.

Mais comment WordPress le met-il dans le footer ou dans kle header ? Tout simplement grâce aux fonctions wp_head() et wp_footer() incluses dans nos thèmes, il est donc primordial de les avoir incluses, surtout si vous utilisez des plugins, ils vont utiliser cette fonction ( s’ils sont bien codés ) pour ajouter leurs scripts.

Particularité de WordPress 3.3

Il faut savoir qu’avant WordPress 3.3, il fallait absolument appeler cette fonction avant le hook ‘wp_enqueue_script’, car une fois celui-ci passé toutes les tentatives d’ajout de script ne fonctionneront pas !

Par exemple si vous aviez un shortcode qui a besoin d’un script pour fonctionner mais que vous ne vouliez l’inclure que s’il était présent, ce n’était pas possible ! A moins de tester si c’est un article ou une page, mais vous perdiez toute chance de le voir fonctionner s’il était appelé avec do_shortcode.

Alors qu’avec la 3.3, on peut faire un wp_enqueue_script n’importe quand ( un temps soit peu qu’il soit avant le wp_footer ). Donc dans le code qui génère votre shortcode, vous pouvez faire un wp_enqueue_script et donc avoir votre script exclusivement dans les pages qui en ont besoin. Il sera présent dans le footer et ses dépendances fonctionneront parfaitement.

jQuery et jQuery UI

jQuery et jQuery UI sont deux librairies largement répandues et surtout utilisées dans WordPress, elles sont donc incluses directement dans les fichiers de WordPress. Il suffit de faire un :

<?php

wp_enqueue_script( 'jquery');

wp_enqueue_script( 'jquery-ui-core' );

Par exemple pour charger jQuery et le coeur de jQuery ui pour les retrouver dans son header et pouvoir les utiliser. Les fichiers de jQuery UI ont leur propres dépendances donc en appelant jquery-ui-autocomplete par exemple, il va automatiquement charger les autres morceaux de la librairie nécessaires à son bon fonctionnement.

Dans votre thème il se peut que vous ayez besoin de jQuery et jQuery UI, cependant pour des raisons de performance je vous conseille fortement de ne pas charger ceux de WordPress et d’utiliser les CDN de google à la place :


<?php
wp_deregister_script( 'jquery-ui-core' );
wp_deregister_script( 'jquery-ui-tab' );
wp_deregister_script( 'jquery-ui-autocomplete' );
wp_deregister_script( 'jquery-ui-accordion' );
wp_deregister_script( 'jquery-ui-autocomplete' );
wp_deregister_script( 'jquery-ui-button' );
wp_deregister_script( 'jquery-ui-datepicker');
wp_deregister_script( 'jquery-ui-dialog' );
wp_deregister_script( 'jquery-ui-draggable' );
wp_deregister_script( 'jquery-ui-droppable' );
wp_deregister_script( 'jquery-ui-mouse' );
wp_deregister_script( 'jquery-ui-position' );
wp_deregister_script( 'jquery-ui-progressbar');
wp_deregister_script( 'jquery-ui-resizable' );
wp_deregister_script( 'jquery-ui-selectable');
wp_deregister_script( 'jquery-ui-slider' );
wp_deregister_script( 'jquery-ui-sortable' );
wp_deregister_script( 'jquery-ui-tabs' );
wp_deregister_script( 'jquery-ui-widget' );

wp_enqueue_script( 'jquery-ui-core', 'https://ajax.googleapis.com/ajax/libs/jqueryui/1.8/jquery-ui.min.js', array( 'jquery' ), '1.8', true);

Donc là on a retiré tous les scripts de jquery-ui de WordPress et à la place nous avons chargé toute la librairie depuis les CDN de Google. Mais alors on peut se demander si le chargement de tout jQuery UI au lieu de juste ce que nous avons besoin est vraiment nécessaire ? Il faut savoir que les CDN de Google sont utilisés sur beaucoup de sites donc si une personne est déjà allé dans un site qui utilise le CDN alors ce fichier sera en cache et la personne ne devra ps le retélécharger. De plus vu qu’il n’est pas stocké sur le même domaine que nos site, il sera téléchargé en même temps qu’une autre ressource, donc un gain de performances au niveau du chargement de notre page.

Pareil pour jQuery :


<?php
wp_deregister_script( 'jquery' );
wp_enqueue_script( 'jquery', 'http://ajax.googleapis.com/ajax/libs/jquery/1.7/jquery.min.js', array(), '1.7' );

Particularité de jQuery dans l’administration

WordPres n’est pas limité à jQuery, il propose aussi d’autres libraires comme Mootools ou script.aculo.us et ces librairies utilisent aussi le « $ » pour faire leurs selecteurs, donc jQuery est inclus dans WordPress pour ne pas entrer en conflit avec ces libraires, c’est le mode noConflict. Deux solutions s’offrent à nous

  1. Faire une fonction wrapper qui permet d’utiliser tout de même le $
  2. Ne Plus utilise le « $ » mais utiliser ‘jQuery’ à la place

Exemple :

Le wrapper :


// De cette manière, ont peut utiliser nos anciennes fonctions sans changer le $

jQuery(function($) {

// Mettez vos fonctions avec des $ ici

});

La réécriture :


// La ligne :

$('.monselecteur').hide();

// Devient

jQuery('.monselecteur').hide();

Ces deux solutions se valent, si vous ne voulez pas taper à chaque fois jQuery, préférez la première solution ;).

Les performances

Utiliser toutes ces méthodes n’ont pas seulement un impact sur la beauté du code ou sa maintenabilité, elles permettent surtout de gagner en performances. Grâce à un plugin tel que wp-minify, on peut facilement faire en sorte que nos fichier soient rassemblés en un seul. Avec le wp_enqueue_script le plugin sait où il doit aller afficher les script, lequel avant lequel etc…

Il devient alors très facile pour quelqu’un de modifier les différents appels et dépendances de nos fichiers. De même pour une personne qui utilise votre plugin, s’il n’a pas besoin de vos fichiers javascript dans son thème, il suffit de deregister vos scripts et il est tranquille, pas besoin d’aller dans votre plugin pour supprimer les lignes concernées.

Conclusion

Si vous suivez mes conseils, la maj de votre code ou de votre thème avec jQuery sera facilité et surtout vous donnerez les clefs à vos utilisateurs de désactiver des fonctionnalités non voulues. De plus vous suiverez les évolutions de WordPress, en effet vu que les fonctionnalités sont, au pire, dépréciées votre wp_enqueue_script fonctionnera dans tous les cas.

Les tables personnalisées dans WordPress

wordpress-database-tables

Introduction

Même si WordPress propose une structure de tables assez flexible et des API pour en profiter intéressantes, il est parfois nécessaire pour le développeur de créer ses propres tables. Parfois pour les performances, parfois par méconnaissance des API, nous allons voir comment créer une table simple dans WordPress et surtout de manière propre et rapide.

La classe $wpdb

WordPres propose une classe globale qui permet de faire des requêtes SQL très facilement et surtout de façon sécurisée si on s’en donne la peine. Elle permet surtout d’êtrte le plus flexible avec une installation WordPress qui aurait, par exemple, modifié le prefixe de ses tables. Si le développeur n’utilise pas la classe wpdb, toutes ses requêtes ne fonctionneront pas !

Dans classe $wpdb on retrouve tous les noms des tables qui sont natives à WordPress comme la table des métas  ou celle des posts. Elle stocke le nom des tables déjà préfixées, par exemple :


global $wpdb;
echo $wpdb->postmeta;

Si vous utilisez ce bout de code, faites le uniquement en développement ;).

Donc ce bout de code affiche le nom de la table postmeta de votre base et avec les préfixes que l’utilisateur aurait pu utiliser.

Cela permet de ne pas se soucier des préfixes de votre utilisateur et surtout que si un jour WordPress décide de changer le nom de la table en base que votre code continue à fonctionner sans problèmes et est maintenu entre les versions.

Et la sécurité ?

Faire des requêtes dans la base est assez problématique si vous le faites à partir d’informations entrées par votre utilisateur puisque certains sont mal intentionnés, et tentent de pirater votre site par cet intermédiaire. Si il tente de passer par le SQL cela s’appelle une attaque par injection SQL, il casse votre requête de base et en fait ce qu’il veut comme, par exemple, supprimer tous les utilisateurs ou toutes votre base etc…

Si votre plugin ou développement utilise des requêtes SQL personnalisées et que vous n’utilisez pas du tout la classe $wpdb, je vous encourage à le faire.

Prenons cet (horrible) exemple:

global $wpdb;
$wpdb->query( « SELECT * FROM wp_posts WHERE ID=’$_GET['post_id']‘ » );

Nous sommes dans le cas où il est possible de se faire pirater son site, votre variable qui est dans $_GET peut être tout et n’importe quoi, ça peut être tout autant un ID de post mais aussi des caractères qui voudraient casser la requête actuelle pour aller faire autre chose dans votre base. Deuxième problème on marque directement le nom de la table dans la requête : ‘wp_posts’ ce qui peut ne pas fonctionner.

Voici la manière de le faire le plus proprement possible :


global $wpdb;
$wpdb->get_results( $wpdb->prepare( « SELECT * FROM $wpdb->posts WHERE ID = ‘%d' », $_GET['post_id'] ) );

Dans cette requête j’utilise l’une des méthodes les plus importantes de la classe : prepare(). Elle permet de spécifier le type de données attendues dans les variables de notre requête. Par exemple ici j’ai mis ‘%d’ cela veut dire que j’attend un chiffre de la variable $_GET['post_id']. Si vous avez plusieurs variables à faire passer dans votre requête vous avez deux choix :

  1. Mettre l’un après l’autre les variables que vous souhaitez tester
  2. Donner un tableau à prepare là ou se trouve $_GET ['post_id'], et e mettant les données dans l’ordre de leur apparition.
Chose importante : Il n’y a pas que %d poiur caractériser ses données, vous pouvez utiliser celles de sprintf. WordPress les comprendra et les interprétera, si les variables ne correspondent pas aux attentes, prepare ne les utilisera pas dans sa query.

Et les autres fonctions de wpdb ?

La classe wpdb permet de faire d’autres choses que get_results, par exemple si vous voulez récupérer une ligne entière, utilisez get_row. Si vous voulez récupérer une valeur unique utilisez get_var.

Dans tous les cas je vous invite à consulter la documentation de la classe wpdb du codex, bien d’autres choses vous y attendent.

Créer sa table

Etant donné que nous voulons créer une petite table personnalisée, il faut le faire le plus proprement possible et surtout en s’insérant le plus proprement dans l’installation de notre client. Comme dit plus tôt si votre client a utilisé une prefixe différent de celui que l’on trouve dans WordPress, il faut que vous puissiez utiliser cette donnée aussi !

Pour que tout se passe à merveille, la meilleure solution est de s’insérer dans WordPress et d’utiliser la classe $wpdb à votre avantage.

Déclarons dans la classe une nouvelle table ( attention cela ne la crée en aucun cas ) pour qu’elle puisse être utilisée dans nos requêtes.


global $wpdb;
$wpdb->ma_table_perso = $wpdb->prefix.’nom_de_ma_table_en_base';

Maintenant dès que vous aurez à faire une requête dans votre base, il vous suffira de faire $wpdb->ma_table_perso ! Comme ça vous ne vous souciez plus du tout du prefix ou autre.

Par contre il faut faire attention aux nom que vous donnez à votre propriété dans $wpdb, il ne faudrait pas écraser un nom existant, donc préfixez votre nom.

Cet exemple doit s’insérer dans le fichier principal d’un plugin, pour qu’il soit bien pris en compte par la suite.

 

Dans le cas d’un plugin, on veut créer une table perso lors de l’activation de celui-ci et ne plus la recréer si l’utilisateur le désactive puis le réactive. Voici la manière de procéder que j’utilise :


register_activation_hook  ( __FILE__, ‘my_plugin_activate’ );
function my_plugin_activate() {
		global $wpdb;</p>
<p>		if ( ! empty($wpdb->charset) )
			$charset_collate = « DEFAULT CHARACTER SET $wpdb->charset »;
		if ( ! empty($wpdb->collate) )
			$charset_collate .=  » COLLATE $wpdb->collate »;</p>
<p>		// Add one library admin function for next function
		require_once( ABSPATH . ‘wp-admin/includes/upgrade.php’ );</p>
<p>		// Try to create the meta table
		return maybe_create_table( $wpdb->ma_table_perso, « CREATE TABLE $wpdb->ma_table_perso(
				`id` int(20) NOT NULL auto_increment,
				`object_id` INT( 20 ) NOT NULL,
				`user_id` INT( 20 ) NOT NULL,
				PRIMARY KEY (`id`),
				UNIQUE KEY `object_ids` (`object_id`,`user_id`)
			) $charset_collate; » );
}

Dans ce cas, nous utilisons la classe $wpdb au mieux, nous vérifions bien le charset et le collate si besoin, nous utilisons notre variable de classe pour l’utiliser dans notre requête.

Avec la fonction maybe_create_table, nous ne créons la table que si elle n’existe pas encore, cela nous permet de ne pas générer d’erreurs lors de l’activation de notre plugin.

Avec ça, la table est créée proprement et ne posera pas de problèmes, vous pourrez ainsi utiliser autant de fois que vous le voudrez la classe avec cette variable

Les tables multi-site

Il s’avère que dans le cas d’un multisite avec la méthode citée ci-dessus la table n’est créée que pour le site principal, donc quand les requêtes seront effectuées, elle le seront sur la table du site actuel mais elles n’existeront pas et donc rien n’en resortira.

Cela peut être utile si vous avez des données qui doivent être lues depuis les sous-sites sur le site principal et pas depuis sa table personnelle.

Si vous voulez que la table soit créée pour le site principal ainsi que sur les sous-sites, vous devez procéder de la manière suivante:


global $wpdb;
$wpdb->ma_table_perso = $wpdb->prefix.’nom_de_ma_table_en_base';
$wpdb->tables[] = ‘ma_table_perso';

De cette manière, vous créerez aussi cette table lors de l’activation de votre plugin sur le sous-site.

Il ne faut pas perdre de vue que créer des tables dans WordPress reste quand même assez rare et je ne vous conseille pas de le faire, utilisez au maximum les possibilités des API de WordPress et de sa structure de base de données qui est assez flexible.

Si vous utilisez des tables personnalisées, faites le avec le plus grand soin et surtout pensez à la sécurité et à limiter les actions de vos utilisateurs. La plupart du temps ce sont les plugins et non WordPress lui même qui a des failles de sécurité. ;)

Utiliser l’API Endpoint pour créer une règle de réécriture d’url simple

url

Le Endpoint

Il n’est pas rare de vouloir créer une règle de réécriture simple et efficace sans avoir à la créer soit même, à tout penser etc…

C’est pour cela que WordPress propose l’endpoint qui fait partie de l’API de rewriting.

Comment l’utiliser ?

C’est vraiment une API très simple à utiliser, prenons l’exemple suivant :

« Je veux ajouter à la fin des liens de mes articles un paramètre qui va afficher la vidéo de l’article associée dans un champ méta ».

Alors comme ça, ça parait compliqué, mais en fait non ! Quelques lignes de code suffiront à le faire. Elles peuvent être ajoutées dans le fichier function.php du thème mais aussi dans un plugin.

Ajouter le Endpoint

Pour ajouter un endpoint, c’est tout simple, il suffit d’appeler la fonction add_rewrite_endpoint avec en premier paramètre le nom du endpoint et en deuxième paramètre les cas où WordPress va réécrire et ajouter le endpoint.
Le deuxième paramètre utilise des variables définies au sein de WordPress, vous avez accès à :

  • EP_PERMALINK
  • EP_ATTACHMENT
  • EP_DATE
  • EP_YEAR
  • EP_MONTH
  • EP_DAY
  • EP_ROOT
  • EP_COMMENTS
  • EP_SEARCH
  • EP_CATEGORIES
  • EP_TAGS
  • EP_AUTHORS
  • EP_PAGES
  • EP_ALL
Comme on peut le voir, on peut choisir où s’ajoute notre endpoint, soit dans un cas bien précis (EP_DAY s’applique aux urls des jours) ou bien partout avec EP_ALL.
Dans notre cas ce sera à la fin du lien de notre article.

add_action( 'init', 'add_video_endpoint' );
function add_video_endpoint() {
// J'ajoute un endpoint nommé vidéo à la fin des liens de mes articles
add_rewrite_endpoint( 'video', EP_PERMALINK );
}

C’est donc en créant des liens du type monsite.fr/chemin_vers_larticle/video/small que WordPress va réécrire et interpréter notre endpoint.

Utiliser le endpoint

Disons que nous voulons afficher la vidéo seule, et dans un template dédié.

Il faut commencer par détecter que le endpoint est actif et puis l’utiliser à son avantage.



add_action( 'parse_query', 'video_endpoint_parse_query' );

function video_endpoint_parse_query( $query ){
// Si je détecte dans nos query vars la vidéo et que la vlauer dans la query vars est small,medium ou marge
if( isset( $query->query_vars['video'] ) && in_array( $query->query_vars['video'], array( 'small', 'medium', 'large' ) ) ) {
// J'ajoute mon action au moment du template redirect
add_action( 'template_redirect', 'video_endpoint_template_loader' );
}
}

function video_endpoint_template_loader() {
global $wp_query;
// Récupérons le slug de la vidéo ( déjà vérifié plus haut )
$slug = $wp_query->query_vars['video'];
// Créons le nom du template à utiliser
$templates = array(
'single-video-'.$slug.'.php',
'single-video.php',
'single.php'
);
// Localisons le template
locate_template( $templates, true );
// Terminons tout ça :)
exit();
}

Donc là nous avons tout simplement détecté la présence de notre endpoint et vérifié qu’il soit renseigné comme nous l’attendions ( ici small, medium ou large ).

Puis nous avons ajouté une action lors du template_redirect et demandé le template correspondant au slug détecté plus haut. Donc les templates chargés peuvent être :

  • single-video-small.php
  • single-video-medium.php
  • single-video-larger.php
  • single-video.php si ceux-ci n’existent pas !
  • Finalement single.php si aucun de ces templates ne sont trouvés

Et là on peut faire ce que l’on veut dans notre template, avoir une présentation spéciale, demander d’être connecté avant de continuer etc..

Conclusion

L’API des endpoint peut être très facilement utilisée et surtout dans des petits cas pratiques comme celui-ci. Afficher une mise en page pour l’impression, afficher l’article avec une présentation spéciale etc…
Elle est très rapide à mettre en place et il ne faut pas perdre de vue qu’elle reste très limitée, il va falloir ajouter les règles de réécriture à la main dans WordPress pour des cas plus compliqués, mais ce sera sûrement l’objet d’un autre article ;).