Artisteer : Générateur de templates Joomla / WordPress / Drupal

Pour gérer l’apparence graphique de son site Joomla, il y a plusieurs options possibles :

  • créer un nouveau template « from scratch » et gérer entièrement l’intégration XHTML/CSS
  • acheter un template sur une boutique en ligne de templates Joomla tel que Joomlart, et le personnaliser légèrement
  • utiliser un générateur de templates.

sshot2Pour cette dernière option, le plus connu est sans conteste, Artisteer. C’est assez bluffant. Il est possible de créer soit même son template Joomla sans aucune connaissance technique en XHTML/CSS.

L’utilisateur a la possibilité  de modifier la structure, la typographie, les textures, les images etc…. aussi facilement que s’il utilisait un logiciel de bureautique traditionnel. Ce logiciel n’est pour le moment disponible que sous Windows.

Pour la création de templates Joomla, il faut compter 129€95, par poste client. C’est donc à peine plus cher qu’un template traditionnel, et cela peut servir à gérer l’apparence d’un nombre non limité de sites Joomla.

Joomla : le CMS libre le plus populaire au niveau mondial ?

Avez-vous déjà essayé de comparer la popularité des différents CMS libres  en utilisant Google Insights ?

Voici une petit comparatif au niveau national du volume de recherche de différents CMS libres connus : Joomla, eZPublish, Typo3, Drupal, Spip.

joomla_insights_france
au niveau national

Si avant 2006 SPIP était plus populaire, il s’est très vite fait distancé par Joomla qui, au passage est loin devant tous les CMS concurrents (au niveau popularité). Pour rappel, Joomla est né en août 2005 !

joomla_insights_world
au niveau mondial

Au niveau mondial, c’est encore plus frappant ! SPIP semble n’avoir jamais existé. Très honnêtement, je ne trouve pas normal qu’il est pris autant d’avance au niveau de la popularité face à ses concurrents. Drupal, par exemple, est loin d’être un mauvais CMS !

Ce genre de tests n’est pas complêtement innocent. Il est important lorsque l’on choisit une solution libre, que cette solution soit populaire. Car si la solution n’est pas populaire, il y aura une communauté autour du projet très faible, et la pérénité du projet ne sera pas sûre.

Templates Joomla gratuits et payants

Joomlart

65 templates Joomla y sont disponibles, dont certains sont destinés à être utilisés sur des boutiques VirtueMart. Des thèmes Magento commencent aussi à apparaître au rythme d’un template par mois. Différentes offres sont proposées.

Pour 59€, il est possible de télécharger librement les templates Joomla pendant 3 mois, et de les installer sur un site. Il existe également des offres destinées aux professionnels. Pour 499€, il est permis de télécharger librement les templates pendant un an, d’enlever le « copyright », et de les installer sur un nombre illimité de sites.

Des templates Joomla gratuits sont également disponibles. C’est d’ailleurs JoomlArt qui est l’auteur de JA Purity, le template qui est maintenant distribué avec Joomla 1.5. Ils sont également les auteurs du template JA Larix qui est fourni avec VirtueMart. Peut-être sans le savoir, vous utilisez donc probablement déjà des templates Joomlart.

JoomlaBamboo

bamboo

JoomlaBamboo proposent 42 templates Joomla relativement épurés. Quelques (rares) templates VirtueMart sont proposés. Pour 40$, il est il possible de télécharger librement les templates Joomla pendant 3 mois, et de les installer sur un site (les templates sont donc un peu moins cher que sur Joomlart).

Pour les professionnels, il est possible moyennant 125$ d’avoir un accès libre à l’ensemble des templates pendant 6 mois, et pouvoir les installer sur un nombre illimité de domaine, en enlevant le copyright.

Rocket Theme


Rocket Theme propose plus de 80 templates Joomla.

Pour les boutiques Virtuemart orientées technologies, le template Joomla 1.5 VirtueMart « Mynxx » impressionne de par ses nombreux effets DHTMLs (cf vidéo) ! Très pro !

Acheter un template Joomla pour son site Internet revient à 50$.

Pour les professionnels, il est possible moyennant 300$ de télécharger librement les templates pendant un an, et de les installer sur un nombre illimité de sites.

Surcharger les composants sous Joomla 1.0.X

L’une des nouveautés de Joomla 1.5, est la possibilité de surcharger l’affichage par défaut des composants.

Sous Joomla 1.0, dès que l’on souhaitait modifier légèrement l’affichage d’un composant, on était contraint de modifier le code source de ce dernier. Cela avait pour conséquence de compliquer la maintenance des sites sous Joomla. En effet, il n’était plus possible de suivre bêtement la procédure de mise à jour de Joomla pour appliquer un patch corrigeant une faille de sécurité par exemple.

En réalité, redéfinir l’affichage des composant est possible également sous Joomla 1.0. La technique consiste à créer un mambot système qui va modifier l’objet global $mainframe. Il est possible de modifier le comportement de $mainframe, mais également de l’étendre, de l’enrichir… Cette technique peut également être utilisé à d’autres fins : tels que la modification du comportement de l’objet global $database….

Voici un premier exemple qui va modifier, de façon transparente pour Joomla, l’objet $mainframe, afin de lui ajouter de nouvelles fonctionnalités, ou afin de modifier son comportement.

defined( '_VALID_MOS' )
or die( 'Direct Access to this location is not allowed.' );

$_MAMBOTS->registerFunction(
  'onAfterStart',
  'extendMosMainframe' );

function extendMosMainframe {
  global $mainframe;
  $mainframe = new mosExtendMainframe($mainframe);
}

/*
 * Cette extension n'a aucun intérêt si de nouvelles
 * méthodes, de nouvelles ne sont pas ajoutées dans
 * la classe mosExtendMainframe, ou si des méthodes
 * de mosMainframe ne sont pas surchargées
 */

class mosExtendMainframe extends mosMainframe{
  // Récupération de l’ensemble des propriétés
  //de l’objet $mainframe initial
  function __construct($mosmainframe){
    $vars = get_class_vars("mosMainframe");
    foreach($vars AS $key=>$value) {
      $this->$key = $mosmainframe->$key;
    }
  }
}

L’objet $mainframe est capital au sein de Joomla. En le modifiant certaines de ses propriétés, vous serez à même de redéfinir le nom des fichiers appartenant à un composant. Voici un exemple très succint, à placer au sein d’un mambot système :

if ($option=='com_content' && $task='view'){
  $mainframe->_path->front=
      $mos_config_absolute_path.
      "/components/com_content/content.redefined.php";
  $mainframe->_path->front_html=
      $mos_config_absolute_path.
      "/components/com_content/content.redefined.html.php";
  $mainframe->_path->class=
      $mos_config_absolute_path.
      "/components/com_content/content.redefined.class.php";
  $mainframe->_template =
      "redefined";
}

Joomla et AJAX : créer une page minimaliste

Dans le cadre de développement AJAX, (voire AJAJ, ou AJAH puisque dans la pratique, je pense que le HTML et le JSON sont plus utilisés que le XML), il est nécessaire de pouvoir afficher une page Joomla minimaliste, c’est à dire une page Joomla qui ne contiendra exclusivement le texte écrit par le composant. En outre, le template du site ne devra pas être affiché.

Pour cela, il existe trois techniques principales :

Template vide

On crée un gabarit qui ne contient rien d’autre que les données affichées par le composant Joomla.

Version Joomla 1.0

<?php
defined( '_VALID_MOS' )
or die( 'Direct Access to this location is not allowed.' );
mosMainBody();
?>

Version Joomla 1.5

<?php
defined( '_JEXEC' )
or die( 'Restricted access' );
<jdoc:include type="component" />
?>

On crée ensuite une entrée de menu dans un menu qui n’est pas affiché. On récupère l’identifiant numérique de cette entrée de menu (Itemid). On suppose que l’Itemid vaut 32.

A cette entrée de menu, on affecte le template vite récemment crée.

Maintenant, pour avoir un affichage minimal, il suffit de spécifier l’Itemid nouvellement créé dans la querystring (la querystring sera donc semblable à : index.php?option=com_virtuemart&page=shop.XXXXX&Itemid=32).

Index2 avec no_html

Sur le front-office, il suffit d’appeler index2.php à la place d’index.php et de rajouter no_html=1 dans la querystring (exemple : index2.php?option=com_virtuemart&page=shop.XXXXX&no_html=1).

Sur le back-office, c’est la page index3.php qui doit être appelée à la place de la page index2.php.

Page de chargement de joomla minimaliste

Cette méthode consiste à recréer un fichier PHP, qui ne soit pas chargé par Joomla, afin de gagner en performance. Pour cela, il faut faire de l’ingénieurie inverse, et s’y prendre en plusieurs fois pour déterminer quels sont les fichiers à inclure et dans quel ordre, quel groupe de mambots/plugins doit être chargé, quelles sont les variables globales qui doivent être déclarées et comment.. En bref, cela devient à mes yeux vite chronophage, et n’est pas toujours justifié. Je ne vais donc pas détailler davantage cette technique dans ce billet.

Voir les différentes positions d’un template Joomla

Position modules Joomla

Sous Joomla, chaque template dispose d’un certain nombre de positions dans lesquelles sont placés les différents modules.

Pour visualiser la position de ces modules, il faut ajouter « tp=1 » dans la querystring.

Voici par exemple, une capture d’écran de http://www.joomla.org/?tp=1

Avec cette technique, il est plus facile d’identifier les modules présents sur un site Joomla.


Modifier la page d’accueil de Joomla

Cette astuce fonctionne sur toutes les versions de Joomla.

Joomla affiche en « page d’accueil », la premier lien publié du menu appelé « main_menu ».

Par défaut, il s’agit d’une vue particulière du composant « com_content » qui va afficher une liste d’articles, à la manière d’un blog.

Pour mettre en page d’accueil, votre boutique VirtueMart, il vous suffit donc de placer en première position du menu main_menu, une entrée pointant vers une page du composant « virtuemart ».

Il n’est pas nécessaire qu’un module affichant le « mainmenu » ne soit publié. Ainsi, cette modification ne sera pas nécessairement visible dans les menus de navigation.

Améliorer les performances de VirtueMart : Proposition d’une nouvelle table

Voici une proposition permettant d’améliorer le parcours de l’arborescence catégorie de VirtueMart, au détriment de la vitesse d’écriture. Ce billet fait directement suite à mon article « Améliorer les performances de VirtueMart« .

Cette méthode nécessite de créer une nouvelle table que nous appellerons #__{vm}_category_tree, dont voici le schéma :

  • category_id : identifiant de la catégorie
  • category_path : fil d’ariane de la catégorie sous forme d’un liste dénormalisée d’identifiant de catégorie séparée par « , »
  • level : niveau de profondeur de la catégorie étudiée

Par exemple, une catégorie ayant un « fil d’ariane » ayant pour valeur « ,1,6,184, » serait de niveau 4 (étant donné qu’il existe trois niveaux de catégories parentes). Sa catégorie parente serait la catégorie « 184 » qui aurait elle même comme parent « 6 » qui aurait elle même comme parent « 1 » qui n’aurait pas de catégorie parente.

Le choix du séparateur « , » permettra d’utiliser au besoin la colonne presque directement dans une requête SQL via le mot clé « in » si besoin.

Voici le SQL permettant de créer cette table :

CREATE TABLE IF NOT EXISTS `#__{vm}_category_tree` (
`category_id` INT(11) NOT NULL,
`category_path` VARCHAR(255) NOT NULL,
`level` INT(11) NOT NULL,
KEY `category_id` (`category_id`),
KEY `category_path` (`category_path`),
KEY `level` (`level`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

Pour alimenter cette table, il faut d’abord executer une fois la requete suivante :

INSERT INTO
`#__{vm}_category_tree`
(category_id,category_path,level)
SELECT
`#__{vm}_category.category_id`,
",",
1
FROM
`#__{vm}_category`
INNER JOIN
`#__{vm}_category_xref`
ON
`#__{vm}_category_xref`.category_child_id=`#__{vm}_category`.category_id
WHERE
`#__{vm}_category`.category_publish="Y"
AND
`#__{vm}_category_xref`.category_parent_id=0;

Il faut ensuite exécuter pour chaque niveau :

INSERT INTO
`#__{vm}_category_tree`
(category_id,category_path,level)
SELECT
`#__{vm}_category`.category_id,
concat(IFNULL(parent_leaf.category_path,""),`#__{vm}_category_xref`.category_parent_id,";"),
IFNULL(parent_leaf.level+1,0)
FROM
`#__{vm}_category`
INNER JOIN
`#__{vm}_category_xref`
ON
`#__{vm}_category_xref`.category_child_id=`#__{vm}_category`.category_id
LEFT OUTER JOIN
`#__{vm}_category_tree` parent_leaf
ON
parent_leaf.category_id=`#__{vm}_category_xref`.category_parent_id
WHERE
`#__{vm}_category`.category_publish="Y"
AND
`#__{vm}_category_xref`.category_parent_id IN (SELECT
category_id FROM `#__{vm}_category_tree` WHERE level=?)

Le remplissage « au fil de l’eau » de cette table, fera l’objet d’autres billets.

Maintenant pour connaître tous les enfants directs et indirects d’une catégorie (« 5 » par exemple), il suffit d’éxécuter la requête suivante:

SELECT category_id, level

FROM `#__{vm}_category_tree`

WHERE category_path LIKE ',5,%';

Une sacré économie de requetes SQL. Le résultat peut-être placée en cache si cela est possible. Il est également possible de complexifier cette requête en y rajoutant par exemple une jointure avec la table #__{vm}_category.

Si vous êtes intéressé par cette modification, merci d’appuyer ma demande sur le forum.

Améliorer les performance de Virtuemart : Constat

Dans le cadre professionnel, il m’est arrivé à moi et à mes collèges de créer des boutiques en ligne, basées sur Joomla / VirtueMart, proposant plus de 15000 produits.

Après avoir réalisé des modifications nous permettant de tenir un tel catalogue, nous avons voulu les proposer à la communauté via le forum officiel de VirtueMart. Malheureusement, étonnement, notre demande a été ignorée pendant plusieurs mois.

L’un des problèmes majeurs, était le nombre de requêtes SQL nécessaires aux parcours de l’arborescence VirtueMart.

L’arborescence produit est stocké dans la table #__vm_category_xref dont voici le schéma simplifié :

  • category_parent_id : identifiant de la catégorie parent
  • category_child_id : identifiant de la catégorie enfant

Imaginons que votre site soit découpé en catégories de la manière suivante :

  1. CMS
    1. Joomla
      1. Joomla 1.0
      2. Joomla 1.5
      3. Joomla 1.6
    2. Drupal
    3. EZ Publish
    4. Typo 3
  2. E-Commerce
    1. VirtueMart
    2. Magento
    3. OS Commerce

Ce découpage est bien en dessous de l’arborescence que nous avons à gérer pour nos sites e-commerce.

Pour récupérer, l’arborescence et l’afficher il nous faut d’abord récupérer les catégories sans enfants (« CMS » et « E-Commerce »). Pour chacune de ces catégories, il faut voir si ces dernières ont des enfants et les afficher. Cet algorithme continue de manière itérative…

On voit bien que le nombre de requêtes SQL nécessaire est exponentiel. Certes, il y a le cache, mais ce dernier n’est pas toujours utilisable (ie : en back office).

Pire, imaginons que la page affichant la catégorie « CMS » doivent afficher l’ensemble des produits contenus dans la catégorie « CMS » et dans ces enfants directs et indirects, le tout trié par prix.

Ce problème explique en partie la lourdeur de l’arborescence du back-office par défaut de VirtueMart , lorsque le catalogue produit est volumineux.

J’expliquerais en détail la méthode que nous souhaitons soumettre à la communauté dans un prochain billet.

Comment rendre VirtueMart plus souple ….

Lorsque je suis amené à travailler sur VirtueMart, solution libre de e-commerce basé sur le CMS Joomla, je suis contraint de modifier directement le code original afin de l’adapter à mes besoins.

Le code perd alors toute compatibilité avec la version communautaire.

En dehors de cela, en raison de cette absence de modularité, il est difficile d’échanger des modifications de Virtuemart à la communauté, sans passer par l’approbation de la communauté VirtueMart. La communauté perd ainsi en « dynamisme ».

En conséquence, j’ai émis une suggestion sur le forum officiel de VirtueMart.

Techniquement, le support de plugin sous VirtueMart ne me semble pas très difficile, la notion de plugin étant déjà présente sous Joomla.

Il faut tout d’abord commencer par créer un nouveau dossier de « plugin ». Pour cela, il suffit de rajouter un dossier « virtuemart » dans le répertoire « plugins » de Joomla.

Par la suite, il faut définir un ensemble d’événements durant lesquels les extensions pourront être déclenchées.

Je propose dans un premier temps (car j’aurai personnellement besoin de ces événements) :

  • insertion de produits (onProductInsert),
  • modification de produits (onProductUpdate),
  • suppression de produits (onProductDelete),
  • insertion de catégories (onCategoryInsert),
  • modification de catégories (onCategoryUpdate),
  • suppression de catégories (onCategoryDelete),
  • passage de commande (onCheckoutProcessed).

Une fois, les événements définies, il faut modifier le code source du composant Virtuemart, pour déclencher les événements des plugins aux moments opportuns.

Par exemple, pour déclencher l’événement « onCategoryInsert », lors de la création d’une catégorie, il faut rajouter le code suivant dans la méthode « add » de la classe « ps_product_category ».

<?php

$vmLogger->info(
  $VM_LANG->_('VM_PRODUCT_CATEGORY_ADDED').
  ': "'.vmGet($d,'category_name').'"'
);

/* Ca commence */
JPluginHelper::importPlugin('virtuemart');
$mainframe->triggerEvent(
  'onCategoryInsert',
  array($category_id)
);
/* Ca termine */

return true;

?>

En fait, la méthode importPlugin, a des fins d’optimisation devrait plutôt être chargée au démarrage du composant virtuemart, en front et en back office.

Ensuite, la création de plugins pour VirtueMart devient possible.

Évidemment, le plugin doit avoir pour « folder » ou « group » la valeur « virtuemart ».

Voici un exemple d’interception de l’insertion de catégories :

<?php
// no direct access
defined( '_JEXEC' ) or die( 'Restricted access' );

jimport( 'joomla.plugin.plugin' );

/**
* Generate a category tree for performance
* optimization (skeleton of a future plugin)
*
*/

class  plgVirtuemartCategorytree extends JPlugin
{
  function plgVirtuemartCategorytree(&$subject, $config) {
    parent::__construct($subject, $config);
  }

  function onCategoryInsert($category_id)   {
    echo '<h3>'.$category_id.'</h3>';
  }
}

?>

Ce plugin se content d’afficher l’identifiant de la catégorie insérée. Ce plugin, en l’état n’a bien entendu aucun intérêt. C’est juste une démonstration illustrant le fonctionnement des plugins.

Si vous êtes intéressé par cette modification, merci d’appuyer ma demande sur le forum.