12 rue de Blénod, 54700 Maidières +33 6 87 42 95 30 Cette adresse e-mail est protégée contre les robots spammeurs. Vous devez activer le JavaScript pour la visualiser. Lun-Ven: 8h/12h 14h/17h

Tutoriels inédits sur le CMS Joomla

YOOtheme Pro + FlexiContent : corriger l'erreur loadUserById() null dans l'éditeur admin

Developpeur Enerve

Vous utilisez FlexiContent et YOOtheme Pro sur Joomla 5, et l'éditeur admin refuse de s'ouvrir avec l'erreur Argument #1 ($id) must be of type int, null given dans ArticleHelper.php ? Un template bien configuré, un FlexiContent bien en place, et pourtant le Customizer plante au démarrage — voici pourquoi ça arrive et comment s'en sortir en deux étapes : correction SQL et patch de code expliqués pas à pas.

Le problème

Vous utilisez le composant FlexiContent pour gérer vos contenus Joomla, et vous avez installé le template YOOtheme Pro pour concevoir votre site. Tout fonctionne en frontend, mais dès que vous essayez d'ouvrir l'éditeur YOOtheme (le Customizer) depuis l'administration, vous obtenez cette erreur fatale :

Joomla\CMS\User\UserFactory::loadUserById(): 
Argument #1 ($id) must be of type int, null given, 
called in .../templates/yootheme/packages/builder-joomla/src/ArticleHelper.php on line 32

La page du Customizer reste blanche ou affiche un écran d'erreur, impossible de modifier votre template. En revanche, si vous passez la source de contenu en Joomla Content natif, l'éditeur s'ouvre sans problème.


Pourquoi ça se produit

Contexte : ce que fait YOOtheme à l'ouverture du Customizer

Quand vous ouvrez le Customizer YOOtheme, le builder charge en arrière-plan une prévisualisation de votre page d'accueil (ou de la page cible). Pour détecter les modifications concurrentes (deux éditeurs travaillant simultanément sur le même article), YOOtheme appelle la méthode ArticleHelper::getCollision() dans le fichier :

/templates/yootheme/packages/builder-joomla/src/ArticleHelper.php

Cette méthode, à partir de la ligne 28, fait ceci :

public static function getCollision(object $article): array
{
    $user = Factory::getContainer()
        ->get(UserFactoryInterface::class)
        ->loadUserById($article->modified_by);  // ← ligne 32 : le crash
    return [
        'contentHash' => md5($article->fulltext . $article->introtext),
        'modifiedBy' => $user->username ?: '',
    ];
}

Elle appelle loadUserById() en lui passant le champ modified_by de l'article, sans vérifier si cette valeur est NULL.

Pourquoi FlexiContent renvoie NULL

FlexiContent gère ses items dans #__content (la table d'articles standard de Joomla), mais il possède son propre système de versionning et de champs personnalisés. Contrairement à com_content qui force un modified_by valide à chaque enregistrement, FlexiContent ne remplit pas systématiquement ce champ. Les items créés par import, soumission frontend anonyme, ou script SQL peuvent donc avoir modified_by = NULL.

Pourquoi ça plante en Joomla 5 et pas avant

Depuis Joomla 5, la méthode UserFactory::loadUserById() est strictement typée :

public function loadUserById(int $id): User

Elle attend un int obligatoirement. En Joomla 4, la tolérance PHP sur le typage était plus souple. En Joomla 5 + PHP 8, passer NULL lève une TypeError fatale.

Résumé : FlexiContent ne remplit pas modified_by → YOOtheme le passe tel quel à loadUserById() → Joomla 5 rejette NULL → crash.


La solution en deux étapes

Étape 1 — Corriger les items en base de données

Connectez-vous à phpMyAdmin (ou votre client MySQL) et lancez ces requêtes.

Récupérez d'abord l'ID d'un Super User valide (remplacez le préfixe #__ par le vôtre) :

SELECT id, username FROM `#__users` WHERE block = 0 ORDER BY id;

Notez l'ID (ex. 62). Ensuite, corrigez les items FlexiContent fautifs en attribuant modified_by = created_by quand c'est possible, sinon votre ID Super User :

UPDATE `#__content` AS c
INNER JOIN `#__flexicontent_items_ext` AS fie ON fie.item_id = c.id
SET c.modified_by = IFNULL(NULLIF(c.created_by, 0), 62)
WHERE c.modified_by IS NULL OR c.modified_by = 0;

Et blindez created_by tant qu'on y est :

UPDATE `#__content` AS c
INNER JOIN `#__flexicontent_items_ext` AS fie ON fie.item_id = c.id
SET c.created_by = 62
WHERE c.created_by IS NULL OR c.created_by = 0;

Videz ensuite le cache Joomla : Système → Maintenance → Purger le cache expiré.

Étape 2 — Patcher le fichier ArticleHelper.php

La correction SQL règle le problème pour les items existants, mais tout nouvel item FlexiContent créé sans modified_by pourra déclencher à nouveau l'erreur. Il faut donc blinder le code YOOtheme lui-même.

Éditez le fichier (via FTP ou le gestionnaire de fichiers de votre hébergeur) :

/templates/yootheme/packages/builder-joomla/src/ArticleHelper.php

Remplacez tout le contenu du fichier par le code suivant :

<?php
namespace YOOtheme\Builder\Joomla;

use Joomla\CMS\Factory;
use Joomla\CMS\User\UserFactoryInterface;

class ArticleHelper
{
    public const PATTERN = '/^<!--\s?(\{.*})\s?-->/';

    public static function matchContent(?string $content): ?string
    {
        return str_contains((string) $content, '<!--') &&
            preg_match(static::PATTERN, $content, $matches)
            ? $matches[1]
            : null;
    }

    public static function getCollision(object $article): array
    {
        $modifiedBy = (int) ($article->modified_by ?? 0);
        $username = '';

        if ($modifiedBy > 0) {
            $user = Factory::getContainer()
                ->get(UserFactoryInterface::class)
                ->loadUserById($modifiedBy);
            $username = $user && $user->username ? $user->username : '';
        }

        return [
            'contentHash' => md5(($article->fulltext ?? '') . ($article->introtext ?? '')),
            'modifiedBy' => $username,
        ];
    }

    public static function isArticleView(): bool
    {
        $input = Factory::getApplication()->getInput();
        $option = $input->getCmd('option');
        $view   = $input->getCmd('view');
        $task   = $input->getCmd('task', '');

        return $option === 'com_content' && $view === 'article' && $task === '';
    }
}

Ce qui change par rapport à l'original :

  • $modifiedBy est casté en (int) et protégé par ?? 0 avant tout appel
  • loadUserById() n'est appelé que si $modifiedBy > 0
  • fulltext et introtext sont protégés par ?? '' car FlexiContent peut les laisser à null, et md5(null) est déprécié depuis PHP 8.1
  • isArticleView() est décomposé en variables pour éviter les erreurs de copier-coller (guillemets typographiques, etc.)

⚠️ Attention : Ce patch est appliqué directement dans le dossier du template YOOtheme et sera écrasé à chaque mise à jour YOOtheme Pro. Notez-le dans votre suivi de maintenance et réappliquez-le après chaque mise à jour jusqu'à correction officielle par l'équipe YOOtheme.


Vérification

Après le patch, ouvrez le Customizer YOOtheme depuis l'administration. La prévisualisation doit s'afficher normalement, que votre page d'accueil soit alimentée par FlexiContent ou com_content.


Pour aller plus loin — Prévenir les nouveaux items sans auteur

Si vous permettez les soumissions frontend via FlexiContent (formulaire de dépôt d'articles pour les membres), vérifiez dans les paramètres du menu concerné que le champ "Item author for anonymous" pointe vers un ID utilisateur valide. Cela évitera que de nouveaux items se retrouvent sans created_by ni modified_by.


Article rédigé par Serge Billon — web54.fr |
Reproduction autorisée avec mention de la source.