Aller au contenu
smallPict
Essai Gratuit

Engineering21 min read

CI/CD d’une extension WordPress : WPCS, PHPStan et PHP 7.4 à 8.5

CI/CD d’une extension WordPress sous GitHub Actions : WPCS, PHPStan et tests sur PHP 7.4 à 8.5, puis un contrôle bloquant avant WordPress.org.

smallPict Engineering

Engineering

L’extension WordPress de smallPict convertit les images envoyées en WebP et AVIF et les sert aux visiteurs. Quand nous taguons une version, GitHub Actions la commite dans le dépôt SVN de WordPress.org, d’où elle atteint chaque site sur lequel l’extension est installée. Les sites dont les mises à jour automatiques sont activées l’installent sans que personne ne relise la modification. L’extension déclare Requires PHP: 7.4 et Requires at least: 5.9 : un même build doit donc tourner aussi bien sur un hébergement mutualisé encore en PHP 7.4 que dans un conteneur en PHP 8.5.

Une erreur fatale dans une extension peut rendre wp-admin inaccessible. Une valeur non échappée sur une page de réglages est une faille XSS sur tous les sites à la fois. Une vérification de nonce manquante fait d’une action d’administration une cible CSRF. Aucun de ces problèmes ne se corrige discrètement : le correctif exige une nouvelle version, et certains sites gardent la version défectueuse jusqu’à son arrivée.

Cet article décrit notre pipeline CI/CD pour l’extension WordPress : les WordPress Coding Standards (WPCS), PHPStan et les tests automatisés exécutés sur sept versions de PHP, ainsi que le contrôle bloquant placé avant WordPress.org. Tout ce qui suit provient du dépôt smallpict-wp à la version 1.2.9.

Points clés

  • Chaque pull request vers master exécute WPCS, PHPStan et 9 scripts de tests automatisés sur PHP 7.4, 8.0, 8.1, 8.2, 8.3, 8.4 et 8.5, en parallèle dans GitHub Actions.
  • WPCS impose des entrées assainies, des sorties échappées, des nonces et des requêtes préparées. PHPStan au niveau 5 détecte les erreurs de type et les branches mortes à partir des stubs WordPress, sans exécuter WordPress.
  • Un tag de version relance WPCS sur les sept versions de PHP, et le job qui commite dans le SVN de WordPress.org ne démarre qu’une fois les sept réussis.

Vue d’ensemble du pipeline CI/CD de l’extension WordPress

Deux workflows GitHub Actions protègent l’extension.

WorkflowDéclencheurJobsContrôles
phpcs.yml (PHP Code Quality & Standards)push sur master ou develop, pull requests vers masterun job par version de PHP : 7.4, 8.0, 8.1, 8.2, 8.3, 8.4, 8.5WPCS, PHPStan, tests automatisés
deploy-all.yml (Deploy to WordPress.org)push d’un tag v*WPCS sur chacune des 7 versions de PHP, puis deployWPCS, puis build et commit SVN

Note sur la couverture des versions de PHP : Les captures d’écran de cet article montrent nos exécutions CI antérieures, qui couvraient PHP 7.4 à 8.3. Aujourd’hui, notre matrice de tests GitHub Actions s’est élargie et couvre PHP 7.4 à PHP 8.5, ce qui garantit une compatibilité continue avec les environnements d’exécution PHP récents, sans aucune régression sur les environnements plus anciens.

Tout l’outillage est déclaré en dépendance de développement Composer, donc rien n’est livré aux utilisateurs :

JSON
"require-dev": {    "wp-coding-standards/wpcs": "^3.4.1",    "phpcsstandards/php_codesniffer": "^3.0",    "phpstan/phpstan": "^2.1",    "szepeviktor/phpstan-wordpress": "^2.0 || ^1.3.5",    "phpstan/extension-installer": "^1.4"}

Tests sur une matrice de versions PHP dans GitHub Actions

Ce qui change entre PHP 7.4 et PHP 8.5

PHP 7.4 et PHP 8.5 n’exécutent pas le même code source de la même façon. Voici quelques changements qui touchent le code d’une extension WordPress :

  • Depuis PHP 8.0, de nombreuses fonctions internes lèvent une TypeError quand un argument n’a pas le bon type, là où 7.4 renvoyait null avec un avertissement. Un code qui passait un tableau à strlen() continuait de tourner en 7.4 et s’arrête en 8.0.
  • PHP 8.0 a modifié la comparaison entre un nombre et une chaîne non numérique. 0 == "abc" vaut true en 7.4 et false en 8.0, ce qui inverse sans bruit certaines comparaisons lâches sur des valeurs d’options.
  • PHP 8.0 a ajouté str_starts_with() et les fonctions apparentées. Notre processeur d’images appelle str_starts_with(). En PHP 7.4, cela ne fonctionne que parce que WordPress 5.9 et les versions ultérieures fournissent un polyfill, ce que garantit notre Requires at least: 5.9.
  • PHP 8.1 a rendu obsolète le passage de null aux paramètres non nullables des fonctions internes. strtolower( wp_parse_url( $url, PHP_URL_HOST ) ) ne pose aucun problème en 7.4 et journalise une dépréciation en 8.1 lorsque $url est relative et que l’hôte vaut null. Certains hébergeurs affichent les dépréciations dans la page.
  • PHP 8.2 a rendu obsolètes les propriétés dynamiques. Affecter une propriété non déclarée sur l’une de vos propres classes journalise une dépréciation à chaque requête.

Chacun de ces changements n’apparaît que lorsque le code est analysé ou exécuté sur la version de PHP qui se comporte différemment. C’est pourquoi le pipeline exécute chaque pull request vers master sur les sept versions en même temps.

La matrice GitHub Actions

Exécution CI d’une extension WordPress dans GitHub Actions : tests sur une matrice PHP avec cinq jobs WPCS et PHPStan en parallèle sur PHP 7.4, 8.0, 8.1, 8.2 et 8.3, tous réussis

Figure 1 : Le workflow PHP Code Quality & Standards pour le merge du travail de la 1.2.0 dans master. Chaque version de PHP est un job distinct, et le job PHP 8.3 montre les étapes que chaque job exécute : PHPCS, PHPStan, puis les tests automatisés.

Note sur la couverture des versions de PHP : Les captures d’écran ci-dessus montrent nos exécutions CI antérieures, qui couvraient PHP 7.4 à 8.3. Aujourd’hui, notre matrice de tests GitHub Actions s’est élargie et couvre PHP 7.4 à PHP 8.5, ce qui garantit une compatibilité continue avec les environnements d’exécution PHP récents, sans aucune régression sur les environnements plus anciens.

YAML
jobs:  code-quality:    name: WPCS & PHPStan (PHP ${{ matrix.php-version }})    runs-on: ubuntu-26.04    strategy:      matrix:        php-version: ['7.4', '8.0', '8.1', '8.2', '8.3', '8.4', '8.5']    steps:      - uses: actions/checkout@v7      - uses: shivammathur/setup-php@v2        with:          php-version: ${{ matrix.php-version }}          tools: composer:v2, cs2pr          ini-values: memory_limit=2G          coverage: none      - run: composer install --prefer-dist --no-progress --no-interaction      - name: Run PHPCS (WordPress Coding Standards)        run: vendor/bin/phpcs -q --standard=phpcs.xml.dist --report=checkstyle | cs2pr      - name: Run PHPStan (WordPress Static Analysis)        run: vendor/bin/phpstan analyse --memory-limit=2G      - name: Run the standalone tests        run: |          for t in tests/test_*.php; do            echo "== $t"            php "$t" || exit 1          done

fail-fast conserve sa valeur par défaut, true : quand une version échoue, GitHub annule les jobs encore en cours. Une pull request défectueuse coûte peu, au prix de ne pas voir le résultat de chaque version dans la même exécution.

Ce que la matrice prouve, et ce qu’elle ne prouve pas

Les trois contrôles ne tirent pas le même bénéfice de la matrice. PHPStan analyse le code pour la version de PHP sur laquelle il tourne, et les tests exécutent le code sur cette version : les deux peuvent donc donner une réponse différente selon le job. PHPCS travaille sur des tokens et, en pratique, donne la même réponse sur les sept ; dans la matrice, il prouve surtout que la chaîne d’outils s’installe et s’exécute sur chaque version. Vérifier en une seule passe la syntaxe et les fonctions sur une plage de versions de PHP est le rôle de PHPCompatibility, que notre ruleset n’inclut pas encore.

Automatiser les WordPress Coding Standards (WPCS)

Les sniffs de sécurité qui comptent pour une extension

WPCS est un ensemble de sniffs PHP_CodeSniffer écrits pour WordPress. Les règles les plus importantes pour la sécurité d’une extension se trouvent dans le ruleset WordPress lui-même :

  • WordPress.Security.ValidatedSanitizedInput signale toute lecture de $_POST, $_GET, $_REQUEST ou $_COOKIE dont les slashes ne sont pas retirés et dont la valeur n’est pas assainie.
  • WordPress.Security.EscapeOutput signale tout echo ou print d’une valeur qui n’est pas passée par une fonction d’échappement comme esc_html(), esc_attr() ou esc_url().
  • WordPress.Security.NonceVerification signale un handler qui lit des données de requête sans vérifier de nonce.
  • WordPress.DB.PreparedSQL et PreparedSQLPlaceholders signalent une requête construite par concaténation de chaînes au lieu de $wpdb->prepare(), ainsi que les placeholders qui ne correspondent pas à leurs arguments.

Notre ruleset WPCS

phpcs.xml.dist ajoute WordPress-Extra et WordPress-Docs, fixe le text domain des sniffs de traduction et exige que chaque fonction, classe et constante globale porte notre préfixe, afin que l’extension ne puisse pas entrer en collision avec les noms d’une autre extension sur le même site :

XML
<rule ref="WordPress">    <exclude name="Universal.Arrays.DisallowShortArraySyntax"/></rule><rule ref="WordPress-Extra"/><rule ref="WordPress-Docs"/>
<rule ref="WordPress.WP.I18n">    <properties>        <property name="text_domain" type="array">            <element value="smallpict"/>        </property>    </properties></rule>
<rule ref="WordPress.NamingConventions.PrefixAllGlobals">    <properties>        <property name="prefixes" type="array">            <element value="smallpict"/>            <element value="SmallPict"/>            <element value="SMALLPICT"/>        </property>    </properties></rule>

Un handler AJAX qui passe WPCS

Ce handler de l’extension restaure par lots les médias déportés vers le stockage cloud. Chaque frontière d’entrée est traitée dès ses premières lignes :

PHP
public function ajax_restore_offloaded() {    if ( ! check_ajax_referer( 'smallpict_restore_offloaded', 'nonce', false ) || ! current_user_can( 'manage_options' ) ) {        wp_send_json_error( array( 'message' => 'forbidden' ), 403 );    }    global $wpdb;    $after = isset( $_POST['after'] ) ? absint( wp_unslash( $_POST['after'] ) ) : 0;    // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- admin action, the rows change on every call.    $ids = $wpdb->get_col(        $wpdb->prepare(            "SELECT DISTINCT post_id FROM {$wpdb->postmeta} WHERE meta_key = %s AND meta_value = %s AND post_id > %d ORDER BY post_id ASC LIMIT %d",            '_smallpict_offloaded',            '1',            $after,            self::RESTORE_BATCH        )    );    // ...}

Le nonce et la capability sont vérifiés ensemble, car un nonce valide prouve que la requête vient de notre page d’administration, pas que l’utilisateur a le droit d’effectuer l’action. $_POST['after'] est débarrassé de ses slashes et converti avec absint() avant d’atteindre la requête, et la requête passe quand même par $wpdb->prepare() alors que la valeur est déjà un entier.

Toute suppression d’alerte exige un nom de sniff et une raison

La ligne phpcs:ignore ci-dessus est délibérée. WPCS met en garde contre les requêtes directes en base sans cache d’objets : c’est un bon conseil pour les lectures côté front-end, et un mauvais pour une action d’administration dont les lignes changent à chaque appel. Notre règle : chaque ignore nomme le sniff exact et donne la raison après --. Un // phpcs:ignore nu ne passe pas la revue.

En CI, PHPCS écrit un rapport checkstyle et cs2pr le transforme en annotations sur le diff de la pull request : le relecteur voit chaque violation sur la ligne qui l’a causée plutôt que dans un log.

Détecter les erreurs de logique avec l’analyse statique PHPStan

WPCS lit le code ligne par ligne. Il sait qu’il manque un appel d’échappement à un echo, mais pas quel type contient une variable ni si une branche peut un jour s’exécuter. PHPStan construit un modèle des types qui circulent dans chaque fonction et signale le code qui le contredit : l’appel d’une méthode qui n’existe pas, un string|false passé là où un string est attendu, la comparaison de valeurs qui ne peuvent jamais être égales, des conditions toujours vraies ou toujours fausses.

Utiliser PHPStan avec WordPress sans exécuter WordPress

szepeviktor/phpstan-wordpress fournit à PHPStan les signatures des fonctions et classes du cœur de WordPress via des fichiers de stubs, ainsi que quelques extensions de types propres à WordPress. phpstan/extension-installer l’enregistre automatiquement. PHPStan lit ces déclarations et ne charge jamais WordPress ni une base de données.

Notre configuration PHPStan

YAML
parameters:    level: 5    paths:        - smallpict.php        - includes/        - admin/    treatPhpDocTypesAsCertain: false    bootstrapFiles:        - phpstan-bootstrap.php

Le niveau 5 vérifie le type de chaque argument passé à une fonction ou à une méthode, en plus des contrôles des niveaux inférieurs sur les classes, méthodes et propriétés inconnues, les types de retour et le code mort. treatPhpDocTypesAsCertain: false indique à PHPStan de ne pas considérer nos propres docblocks @param comme une preuve. WordPress transmet ce que renvoie un filtre, si bien qu’un paramètre documenté comme int peut tout de même arriver sous forme de chaîne depuis une autre extension, et nous voulons que PHPStan conserve les contrôles défensifs qui gèrent ce cas. Le fichier bootstrap définit les constantes de l’extension (SMALLPICT_PATH, SMALLPICT_URL et d’autres), normalement définies à l’exécution.

Log d’analyse statique PHPStan pour WordPress dans GitHub Actions : étape WPCS sans erreur, PHPStan a analysé 11 fichiers sur 11 de l’extension avec « [OK] No errors »

Figure 2 : Les étapes PHPCS et PHPStan du job PHP 8.3. PHPCS n’affiche rien quand il n’a rien à signaler. PHPStan analyse les 11 fichiers de l’extension (le fichier principal et les 10 classes de includes/) et ne signale aucune erreur.

Une vraie détection PHPStan : la ligne 626 du processeur d’images

Le 2 octobre 2026, le pipeline a échoué sur PHPStan avec une seule erreur :

PHPStan détecte un bug dans une extension WordPress : « Right side of && is always true » dans includes/class-smallpict-image-processor.php, ligne 626, règle booleanAnd.rightAlwaysTrue, job en échec sur PHP 8.2

Figure 3 : Le job PHP 8.2 s’est arrêté à l’étape PHPStan avec booleanAnd.rightAlwaysTrue à la ligne 626 de includes/class-smallpict-image-processor.php. À ce moment-là, l’extension comptait 9 fichiers dans les chemins analysés.

Ce code est la dernière étape d’une conversion. Lorsque le réglage Format de sortie de l’extension vaut WebP ou AVIF, le fichier converti devient la pièce jointe et le fichier envoyé d’origine est supprimé pour économiser de l’espace disque. Les autres choix, « AVIF, avec WebP en secours » et « Conserver le format d’origine », gardent les fichiers JPEG et PNG d’origine. Voici la branche de suppression :

PHP
// C. Pure 1-to-1 Mode: Delete raw uncompressed source file to free 100% hosting space.if ( ( $is_single_webp || $is_single_avif ) && $canonical_path !== $main_file_path && file_exists( $main_file_path ) ) {    wp_delete_file( $main_file_path );}

Selon PHPStan, file_exists( $main_file_path ) est toujours vrai à cet endroit. La raison se trouve 150 lignes plus haut, au début de la même méthode :

PHP
$main_file_path = get_attached_file( $attachment_id );if ( ! $main_file_path || ! file_exists( $main_file_path ) ) {    return new WP_Error( 'file_missing', 'File not found on disk.' );}

La méthode ne continue que si le fichier existe, et PHPStan propage ce fait jusqu’à la ligne 626.

Nous n’avons pas pris ce signalement pour argent comptant. file_exists() interroge le système de fichiers, et la réponse peut changer entre deux appels. Par défaut, PHPStan mémorise le résultat d’un tel appel (l’option rememberPossiblyImpureFunctionValues), en supposant que rien entre-temps n’a modifié le disque. Avant de supprimer le test, nous avons vérifié deux points en lisant le code :

  1. Rien entre la garde et la ligne 626 ne supprime ni ne déplace le fichier source. La conversion écrit chaque sortie dans un fichier temporaire puis la déplace vers un nouveau chemin, et les seuls appels à wp_delete_file() sur ce chemin suppriment des fichiers temporaires. L’étape de déport, qui supprime bien des fichiers locaux, s’exécute après la ligne 626.
  2. wp_delete_file() tolère de toute façon un fichier absent. La fonction fait passer le chemin par le filtre wp_delete_file et appelle @unlink(), ce qui ne cause aucun dégât si le fichier a déjà disparu.

Une fois ces deux points confirmés, la condition était du code mort, et du code mort dans une branche de suppression laisse croire au lecteur suivant que le fichier peut disparaître en cours de méthode. Le correctif l’a retirée :

DIFF
-if ( ( $is_single_webp || $is_single_avif ) && $canonical_path !== $main_file_path && file_exists( $main_file_path ) ) {+if ( ( $is_single_webp || $is_single_avif ) && $canonical_path !== $main_file_path ) {     wp_delete_file( $main_file_path ); }

Ce signalement ne correspondait pas à un crash. Sa valeur tenait à ce qu’il révélait sur la méthode : les hypothèses du code s’étaient éloignées de sa structure, dans la seule branche qui supprime des fichiers d’utilisateurs. La leçon que nous en tirons est plus étroite que « faites confiance à l’analyseur ». Un signalement « toujours vrai » ou « toujours faux » sur une fonction liée au système de fichiers, au réseau ou au temps mérite une vérification manuelle de ce qui se passe entre les deux appels avant de retirer la condition.

Tests automatisés d’une extension WordPress sans PHPUnit

La dernière étape de chaque job de la matrice exécute les fichiers de tests/. Ce ne sont pas des tests PHPUnit. Chaque fichier est un simple script PHP qui définit des stubs minimaux pour les fonctions WordPress dont il a besoin (get_option(), update_option(), sanitize_key(), etc.), charge la classe de l’extension à tester, l’exerce et se termine avec un code de sortie non nul au premier échec :

Shell
for t in tests/test_.php do  echo "== $t"  php "$t"  exit 1done

Il existe aujourd’hui 9 scripts de ce type. Ils couvrent les chemins où une erreur coûte des données ou de l’argent à un client : le pipeline de conversion WebP et AVIF et ses replis, la diffusion des images, le déport et la suppression de fichiers dans le stockage cloud, la restauration par lots des fichiers déportés, le comportement lorsqu’un compte cesse de payer, le quota de stockage et la désinstallation. Le test de désinstallation exécute les vraies requêtes de désinstallation sur une base SQLite en mémoire et vérifie ce qui reste :

PHP
check(    array( '_smallpict_cdn_base', '_smallpict_cdn_key', '_smallpict_offloaded', '_smallpictx', '_wp_attached_file' ) === $meta,    'offload markers and foreign meta remain (got ' . implode( ',', $meta ) . ')');

Cette assertion protège une décision facile à défaire par accident. Désinstaller l’extension supprime ses réglages mais conserve les post meta qui indiquent quels fichiers n’existent que dans le stockage cloud, pour qu’un site qui réinstalle l’extension retrouve ses images. Un DELETE ... LIKE '_smallpict%' écrit sans précaution supprimerait ces marqueurs, et le test échoue dans ce cas.

Nous avons préféré des scripts simples à la suite de tests PHPUnit de WordPress pour la vitesse et le coût de mise en place : ils ne demandent ni serveur de base de données ni checkout de WordPress, et les 9 s’exécutent en moins d’une seconde, si bien que les lancer sur sept versions de PHP n’ajoute presque rien à une pull request. La contrepartie : les stubs ne modélisent que ce que nous y avons écrit. Le comportement qui dépend du vrai cœur de WordPress, comme la gestion des métadonnées propre à la médiathèque, n’est pas couvert par ces tests.

Le contrôle bloquant avant le déploiement sur WordPress.org

Les versions sont publiées par un workflow distinct. Le push d’un tag comme v1.2.9 le déclenche, et le job qui commite dans le SVN de WordPress.org déclare une dépendance à la matrice de lint :

YAML
jobs:  lint:    name: WPCS Check (PHP ${{ matrix.php-version }})    runs-on: ubuntu-26.04    strategy:      matrix:        php-version: ['7.4', '8.0', '8.1', '8.2', '8.3', '8.4', '8.5']    steps:      - uses: actions/checkout@v7      - uses: shivammathur/setup-php@v2        with:          php-version: ${{ matrix.php-version }}      - run: composer install --prefer-dist --no-progress --no-interaction      - name: PHP CodeSniffer Check        run: vendor/bin/phpcs --standard=phpcs.xml.dist
  deploy:    name: Deploy    needs: lint    runs-on: ubuntu-26.04    permissions:      contents: read    steps:      - uses: actions/checkout@v7      - uses: shivammathur/setup-php@v2        with:          php-version: '7.4'      - name: Build WP.org Version        run: |          chmod +x build-wporg.sh          ./build-wporg.sh      - name: Deploy to WordPress.org        uses: 10up/action-wordpress-plugin-deploy@stable        with:          generate-zip: false        env:          SVN_USERNAME: ${{ secrets.SVN_USERNAME }}          SVN_PASSWORD: ${{ secrets.SVN_PASSWORD }}          SLUG: smallpict          BUILD_DIR: build-wporg/smallpict          ASSETS_DIR: .wordpress-org

needs: lint signifie que le job deploy ne démarre que lorsque les sept jobs lint ont réussi. Si WPCS échoue sur une seule version, GitHub saute deploy et aucun commit SVN n’a lieu. L’étape de build tourne sur PHP 7.4, la plus ancienne version que nous prenons en charge. Le jeton du job n’a qu’un accès en lecture au dépôt ; sa seule écriture va vers le SVN de WordPress.org, avec des identifiants stockés comme secrets du dépôt.

Contrôle bloquant avant déploiement dans le workflow GitHub Actions Deploy to WordPress.org : WPCS Check réussi sur PHP 7.4, 8.0, 8.1, 8.2 et 8.3 avant l’exécution du job Deploy

Figure 4 : Le workflow Deploy to WordPress.org. Les cinq jobs WPCS Check s’exécutent d’abord ; le job Deploy situé en dessous ne s’exécute qu’une fois les cinq réussis.

Ce contrôle relance WPCS sur le commit tagué au lieu de se fier à l’exécution antérieure sur la pull request. Un tag peut pointer vers n’importe quel commit, y compris un commit poussé directement ou un commit dont les contrôles ne se sont jamais terminés, et le workflow de publication n’a pas d’autre moyen de savoir ce qu’il livre.

Exécuter les contrôles CI en local

Les scripts Composer encapsulent les mêmes commandes que la CI, ce qui permet de reproduire un échec avant le push :

Shell
composer installcomposer lint        # vendor/bin/phpcs --standard=phpcs.xml.distcomposer lint-fix    # vendor/bin/phpcbf: fixes spacing and formatting sniffscomposer phpstan     # vendor/bin/phpstan analysefor t in tests/test_.php do php "$t"  break done

Pour reproduire l’échec d’un job précis de la matrice, exécutez les mêmes commandes sous la version de PHP concernée, par exemple avec l’image officielle après composer install :

Shell
docker run --rm -v "$PWD":/app -w /app php:7.4-cli \  sh -c 'vendor/bin/phpstan analyse --memory-limit=2G && for t in tests/test_*.php; do php "$t" || exit 1; done'

phpcbf ne corrige que ce qu’un sniff peut corriger mécaniquement. Pour les signalements sur l’échappement, l’assainissement et les nonces, une personne doit choisir la fonction adaptée au contexte, et nous ne les corrigeons pas automatiquement.

Ce que le pipeline ne couvre pas encore

Trois lacunes figurent sur notre liste :

  1. Le contrôle avant déploiement n’exécute que WPCS. PHPStan et les tests automatisés tournent sur les push vers master et develop et sur les pull requests, pas sur le tag de version. Ajouter ces deux étapes au job lint du workflow de déploiement comble cette lacune.
  2. Notre ruleset n’inclut pas PHPCompatibility. Ajouter phpcompatibility/phpcompatibility-wp avec une testVersion de 7.4- signalerait en une seule exécution la syntaxe et les fonctions qui n’existent pas en 7.4.
  3. Les tests utilisent des stubs plutôt qu’une vraie installation de WordPress. Un job d’intégration sur WordPress 5.9 (notre minimum) et sur la dernière version couvrirait le comportement du cœur que les stubs ne peuvent pas reproduire.

FAQ

Pourquoi tester sur une matrice de PHP 7.4 à 8.5 est-il essentiel pour les extensions WordPress ?

WordPress.org distribue la même version à chaque site, et l’en-tête de l’extension (Requires PHP: 7.4) est le seul filtre sur les versions de PHP qui l’installent. Entre 7.4 et 8.5, PHP a changé la façon dont les fonctions internes traitent les arguments de mauvais type, la comparaison entre nombres et chaînes, et les constructions qui déclenchent des dépréciations : un code correct sur une version peut provoquer une erreur fatale ou journaliser des avertissements sur une autre. Une exécution CI sur une seule version de PHP prouve seulement que l’extension fonctionne sur cette version. Exécuter PHPStan et les tests sur chaque version prise en charge détecte ces différences avant que la version n’atteigne les utilisateurs.

WPCS remplace-t-il les audits de sécurité classiques ?

Non. WPCS vérifie des motifs à la ligne où ils apparaissent : une variable de requête lue sans assainissement, un echo sans échappement, un handler sans vérification de nonce, une requête sans $wpdb->prepare(). Il ne peut pas dire si un handler vérifie la bonne capability, si la fonction d’échappement convient au contexte de sortie, si une requête côté serveur part vers une URL contrôlée par un utilisateur, ou si un utilisateur peut accéder aux données d’un autre. Un commentaire phpcs:ignore peut aussi faire taire un sniff. Nous considérons WPCS comme le socle minimal qui écarte les erreurs connues, et nous relisons à la main les changements qui touchent à la sécurité.

Comment PHPStan gère-t-il les fonctions du cœur de WordPress sans exécuter de code ?

PHPStan n’exécute jamais le code qu’il analyse. Il lit les déclarations et les docblocks pour construire un modèle des types. Pour WordPress, szepeviktor/phpstan-wordpress fournit des fichiers de stubs : les signatures, les types de paramètres et les types de retour des fonctions et classes du cœur de WordPress, sans leur corps. PHPStan lit ces stubs comme s’ils étaient WordPress, et peut ainsi vérifier qu’un appel à wp_delete_file() ou get_attached_file() passe et reçoit les bons types. Les constantes que WordPress ou l’extension définissent à l’exécution vont dans un fichier bootstrap, que PHPStan charge avant l’analyse.

L’extension est disponible sur WordPress.org sous le nom smallPict. L’installation et les réglages Format de sortie sont décrits dans le guide d’installation et dans la référence des réglages d’image.

Écrit par smallPict Engineering

Engineering

Nous développons la conversion d'images et la diffusion CDN pour les sites web et les applications.

Essayez-le sur vos propres images.

20 Mo par mois gratuits. Environ deux minutes d’installation sur WordPress.

Plus d'articles sur la performance des images, les Core Web Vitals et le stockage cloud.

Tous les articles

Cloud & CDN3 min read

SmallPict API/SDK : BYOK ou CDN géré, lequel choisir ?

Ignite n'inclut pas de CDN (les résultats reviennent directement à votre application) ; Velocity et Momentum vous laissent choisir entre le stockage et le CDN SmallPict (par défaut) ou votre propre stockage et votre propre CDN. Voici comment déterminer le modèle adapté à votre projet.