Vai al contenuto
smallPict
Inizia Gratis

Engineering20 min read

CI/CD per plugin WordPress: WPCS, PHPStan e PHP da 7.4 a 8.5

CI/CD per plugin WordPress con GitHub Actions: WPCS, PHPStan e test automatici su PHP da 7.4 a 8.5, più un gate pre-deploy prima di WordPress.org.

smallPict Engineering

Engineering

Il plugin WordPress di smallPict converte i caricamenti in WebP e AVIF e li serve ai visitatori. Quando creiamo il tag di una release, GitHub Actions la committa nel repository SVN di WordPress.org, e da lì arriva a ogni sito che ha il plugin installato. I siti con gli aggiornamenti automatici attivi la installano senza che nessuno esamini la modifica. Il plugin dichiara Requires PHP: 7.4 e Requires at least: 5.9, quindi la stessa build deve girare sia su un hosting condiviso ancora fermo a PHP 7.4 sia su un container con PHP 8.5.

Un fatal error in un plugin può mettere fuori uso wp-admin. Un valore senza escape in una pagina di impostazioni è un bug XSS su tutti i siti nello stesso momento. Un controllo del nonce mancante trasforma un'azione di amministrazione in un bersaglio CSRF. Nessuno di questi problemi si corregge in silenzio: la correzione richiede un'altra release, e alcuni siti restano sulla versione difettosa finché non arriva.

Questo articolo descrive la nostra pipeline CI/CD per il plugin WordPress: i WordPress Coding Standards (WPCS), PHPStan e i test automatici che girano su sette versioni di PHP, e il gate pre-deploy davanti a WordPress.org. Tutto ciò che segue proviene dal repository smallpict-wp alla release 1.2.9.

Punti chiave

  • Ogni pull request verso master esegue WPCS, PHPStan e 9 script di test automatici su PHP 7.4, 8.0, 8.1, 8.2, 8.3, 8.4 e 8.5 in parallelo in GitHub Actions.
  • WPCS impone input sanificato, output con escape, nonce e query preparate. PHPStan al livello 5 trova errori di tipo e rami morti a partire dagli stub di WordPress, senza eseguire WordPress.
  • Un tag di release esegue di nuovo WPCS su tutte e sette le versioni di PHP, e il job che fa il commit su SVN di WordPress.org parte solo dopo che tutte e sette sono passate.

La pipeline CI/CD del plugin WordPress in sintesi

Due workflow di GitHub Actions proteggono il plugin.

WorkflowSi avvia suJobControlli
phpcs.yml (PHP Code Quality & Standards)push su master o develop, pull request verso masterun job per versione di PHP: 7.4, 8.0, 8.1, 8.2, 8.3, 8.4, 8.5WPCS, PHPStan, test automatici
deploy-all.yml (Deploy to WordPress.org)push di un tag v*WPCS su ciascuna delle 7 versioni di PHP, poi deployWPCS, poi build e commit SVN

Nota sulla copertura delle versioni PHP: Gli screenshot di questo articolo mostrano le nostre esecuzioni CI precedenti, che coprivano PHP da 7.4 a 8.3. Oggi la matrice di test di GitHub Actions è stata estesa e copre PHP da 7.4 a PHP 8.5, garantendo una compatibilità continua con i runtime PHP moderni senza alcuna regressione sugli ambienti legacy.

Tutti gli strumenti sono dipendenze di sviluppo di Composer, quindi nessuno arriva agli utenti:

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"}

Test su matrice di versioni PHP in GitHub Actions

Cosa cambia tra PHP 7.4 e PHP 8.5

PHP 7.4 e PHP 8.5 eseguono lo stesso sorgente del plugin in modo diverso. Alcuni dei cambiamenti che toccano il codice dei plugin WordPress:

  • PHP 8.0 ha fatto sì che molte funzioni interne lancino un TypeError per un argomento del tipo sbagliato, dove 7.4 restituiva null con un warning. Il codice che passava un array a strlen() continuava a girare su 7.4 e si ferma su 8.0.
  • PHP 8.0 ha cambiato il modo in cui un numero viene confrontato con una stringa non numerica. 0 == "abc" è true su 7.4 e false su 8.0, e questo inverte senza alcun avviso alcuni confronti non stretti sui valori delle opzioni.
  • PHP 8.0 ha aggiunto str_starts_with() e le funzioni correlate. Il nostro image processor chiama str_starts_with(). Su PHP 7.4 funziona solo perché WordPress 5.9 e successivi includono un polyfill, garantito dal nostro Requires at least: 5.9.
  • PHP 8.1 ha deprecato il passaggio di null a parametri non nullable delle funzioni interne. strtolower( wp_parse_url( $url, PHP_URL_HOST ) ) va bene su 7.4 e registra una deprecation su 8.1 quando $url è relativo e l'host è null. Alcuni hosting stampano le deprecation nella pagina.
  • PHP 8.2 ha deprecato le proprietà dinamiche. Assegnare un valore a una proprietà non dichiarata in una delle tue classi registra una deprecation a ogni richiesta.

Ognuno di questi problemi emerge solo quando il codice viene analizzato o eseguito sulla versione di PHP che si comporta diversamente. Per questo la pipeline esegue ogni pull request verso master su tutte e sette le versioni contemporaneamente.

La matrice di GitHub Actions

Esecuzione CI di un plugin WordPress in GitHub Actions: test su matrice PHP con cinque job WPCS e PHPStan in parallelo su PHP 7.4, 8.0, 8.1, 8.2 e 8.3, tutti superati

Figura 1: Il workflow PHP Code Quality & Standards per il merge del lavoro 1.2.0 in master. Ogni versione di PHP è un job a sé, e il job PHP 8.3 mostra gli step eseguiti da ogni job: PHPCS, PHPStan, poi i test automatici.

Nota sulla copertura delle versioni PHP: Gli screenshot qui sopra mostrano le nostre esecuzioni CI precedenti, che coprivano PHP da 7.4 a 8.3. Oggi la matrice di test di GitHub Actions è stata estesa e copre PHP da 7.4 a PHP 8.5, garantendo una compatibilità continua con i runtime PHP moderni senza alcuna regressione sugli ambienti legacy.

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 mantiene il valore predefinito true, quindi quando una versione fallisce, GitHub annulla i job ancora in esecuzione. Una pull request difettosa costa poco, al prezzo di non vedere il risultato di tutte le versioni nella stessa esecuzione.

Cosa dimostra la matrice, e cosa no

I tre controlli non traggono lo stesso valore dalla matrice. PHPStan analizza il codice per la versione di PHP su cui gira, e i test eseguono il codice su quella versione, quindi entrambi possono dare una risposta diversa in ogni job. PHPCS lavora sui token e in pratica dà la stessa risposta su tutte e sette; nella matrice dimostra soprattutto che la toolchain si installa e gira su ogni versione. Verificare sintassi e funzioni rispetto a un intervallo di versioni PHP in un unico passaggio è compito di PHPCompatibility, che il nostro ruleset non include ancora.

Automatizzare i WordPress Coding Standards (WPCS)

Gli sniff di sicurezza che contano per un plugin

WPCS è un insieme di sniff di PHP_CodeSniffer scritti per WordPress. Le regole più importanti per la sicurezza di un plugin si trovano nel ruleset WordPress stesso:

  • WordPress.Security.ValidatedSanitizedInput segnala ogni lettura di $_POST, $_GET, $_REQUEST o $_COOKIE che non passa per unslash e sanificazione.
  • WordPress.Security.EscapeOutput segnala ogni echo o print di un valore che non è passato per una funzione di escape come esc_html(), esc_attr() o esc_url().
  • WordPress.Security.NonceVerification segnala un handler che legge i dati della richiesta senza verificare un nonce.
  • WordPress.DB.PreparedSQL e PreparedSQLPlaceholders segnalano una query costruita per concatenazione di stringhe invece che con $wpdb->prepare(), e i placeholder che non corrispondono ai loro argomenti.

Il nostro ruleset WPCS

phpcs.xml.dist aggiunge WordPress-Extra e WordPress-Docs, fissa il text domain per gli sniff di traduzione e richiede che ogni funzione, classe e costante globale porti il nostro prefisso, così il plugin non può entrare in conflitto con i nomi di un altro plugin sullo stesso sito:

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 che supera WPCS

Questo handler del plugin ripristina a blocchi i media trasferiti sullo storage cloud. Tutti i punti in cui entra input esterno vengono gestiti nelle prime righe:

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        )    );    // ...}

Il nonce e la capability vengono controllati insieme, perché un nonce valido dimostra che la richiesta arriva dalla nostra pagina di amministrazione, non che l'utente sia autorizzato a eseguire l'azione. $_POST['after'] passa per unslash e viene convertito con absint() prima di raggiungere la query, e la query passa comunque per $wpdb->prepare() anche se il valore è già un intero.

Le soppressioni richiedono il nome dello sniff e un motivo

La riga phpcs:ignore qui sopra è voluta. WPCS avvisa sulle query dirette al database senza object caching: un buon consiglio per le letture front-end, sbagliato per un'azione di amministrazione le cui righe cambiano a ogni chiamata. La nostra regola è che ogni ignore indichi lo sniff esatto e riporti il motivo dopo --. Un // phpcs:ignore senza altro non supera la review.

In CI, PHPCS scrive un report checkstyle e cs2pr lo trasforma in annotazioni sul diff della pull request, così chi fa la review vede ogni violazione sulla riga che l'ha causata invece che in un log.

Trovare errori di logica con l'analisi statica di PHPStan

WPCS legge il codice riga per riga. Sa che a un echo manca una chiamata di escape, ma non che tipo contiene una variabile o se un ramo potrà mai essere eseguito. PHPStan costruisce un modello dei tipi che attraversano ogni funzione e segnala il codice che lo contraddice: la chiamata a un metodo che non esiste, un string|false passato dove serve un string, il confronto tra valori che non possono mai essere uguali, condizioni sempre vere o sempre false.

Usare PHPStan con WordPress senza eseguire WordPress

szepeviktor/phpstan-wordpress fornisce a PHPStan le firme delle funzioni e delle classi del core di WordPress tramite file stub, più alcune estensioni di tipo specifiche per WordPress. phpstan/extension-installer lo registra automaticamente. PHPStan legge quelle dichiarazioni e non carica mai WordPress né un database.

La nostra configurazione di PHPStan

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

Il livello 5 controlla il tipo di ogni argomento passato a una funzione o a un metodo, oltre ai controlli dei livelli inferiori su classi, metodi e proprietà sconosciuti, tipi di ritorno e codice morto. treatPhpDocTypesAsCertain: false dice a PHPStan di non considerare i nostri docblock @param come una prova. WordPress passa qualunque cosa restituisca un filtro, quindi un parametro documentato come int può comunque arrivare come stringa da un altro plugin, e vogliamo che PHPStan mantenga i controlli difensivi che gestiscono questo caso. Il file di bootstrap definisce le costanti del plugin (SMALLPICT_PATH, SMALLPICT_URL e altre), che normalmente vengono impostate a runtime.

Log dell'analisi statica PHPStan per WordPress in GitHub Actions: step WPCS pulito, PHPStan ha analizzato 11 file su 11 del plugin con "[OK] No errors"

Figura 2: Gli step PHPCS e PHPStan del job PHP 8.3. PHPCS non stampa nulla quando non c'è niente da segnalare. PHPStan analizza gli 11 file del plugin (il file principale e le 10 classi in includes/) e non segnala errori.

Un caso reale di PHPStan: la riga 626 dell'image processor

Il 2 ottobre 2026 la pipeline è fallita su PHPStan con un errore:

PHPStan individua un bug in un plugin WordPress: "Right side of && is always true" in includes/class-smallpict-image-processor.php alla riga 626, regola booleanAnd.rightAlwaysTrue, job fallito su PHP 8.2

Figura 3: Il job PHP 8.2 si è fermato allo step PHPStan con booleanAnd.rightAlwaysTrue alla riga 626 di includes/class-smallpict-image-processor.php. All'epoca il plugin aveva 9 file nei percorsi analizzati.

Il codice è l'ultimo passaggio di una conversione. Quando l'impostazione Formato di output del plugin è WebP o AVIF, il file convertito diventa l'allegato e il caricamento originale viene eliminato per risparmiare spazio su disco. Le altre opzioni, "AVIF, con WebP di riserva" e "Mantieni il formato originale", conservano i file JPEG e PNG originali. Questo era il ramo di eliminazione:

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 );}

Secondo PHPStan, file_exists( $main_file_path ) è sempre vero in quel punto. Il motivo si trova 150 righe prima, all'inizio dello stesso metodo:

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.' );}

Il metodo prosegue solo se il file esiste, e PHPStan porta questa informazione fino alla riga 626.

Non abbiamo preso la segnalazione per buona. file_exists() interroga il filesystem, e la risposta può cambiare tra due chiamate. Per impostazione predefinita PHPStan ricorda il risultato di una chiamata del genere (l'opzione rememberPossiblyImpureFunctionValues), presupponendo che nel frattempo nulla abbia modificato il disco. Prima di eliminare il controllo, abbiamo verificato due cose leggendo il codice:

  1. Nulla tra la guardia e la riga 626 elimina o sposta il file sorgente. La conversione scrive ogni output in un file temporaneo e lo sposta in un nuovo percorso, e le uniche chiamate a wp_delete_file() su quel percorso rimuovono file temporanei. Lo step di offload, che elimina davvero i file locali, viene eseguito dopo la riga 626.
  2. wp_delete_file() tollera comunque un file mancante. Passa il percorso attraverso il filtro wp_delete_file e chiama @unlink(), che non fa danni se il file non c'è più.

Confermati entrambi i punti, la condizione era codice morto, e il codice morto in un ramo di eliminazione porta chi legge dopo a pensare che il file possa sparire a metà del metodo. La correzione l'ha rimossa:

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 ); }

La segnalazione non riguardava un crash. Il suo valore stava in ciò che diceva del metodo: le assunzioni del codice si erano allontanate dalla sua struttura, proprio nell'unico ramo che elimina file degli utenti. La lezione che ne abbiamo tratto è più circoscritta di "fidati dell'analizzatore". Una segnalazione di condizione sempre vera o sempre falsa su una funzione di filesystem, di rete o di tempo merita una verifica manuale di ciò che succede tra le due chiamate prima di togliere la condizione.

Test automatici per un plugin WordPress senza PHPUnit

L'ultimo step di ogni job della matrice esegue i file in tests/. Non sono test PHPUnit. Ogni file è un semplice script PHP che definisce stub minimi per le funzioni WordPress di cui ha bisogno (get_option(), update_option(), sanitize_key() e così via), carica la classe del plugin da testare, la esercita ed esce con un codice diverso da zero al primo fallimento:

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

Oggi gli script di questo tipo sono 9. Coprono i percorsi in cui un errore costa a un cliente dati o denaro: la pipeline di conversione WebP e AVIF con i suoi fallback, la distribuzione delle immagini, l'offload e l'eliminazione dei file nello storage cloud, il ripristino a blocchi dei file trasferiti, il comportamento quando un account smette di pagare, la quota di storage e la disinstallazione. Il test di disinstallazione esegue le vere query di disinstallazione su un database SQLite in memoria e controlla cosa rimane:

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 ) . ')');

Quell'asserzione protegge una decisione facile da annullare per sbaglio. La disinstallazione del plugin rimuove le sue impostazioni ma conserva i post meta che registrano quali file si trovano solo nello storage cloud, così un sito che reinstalla il plugin può ancora trovare le sue immagini. Un DELETE ... LIKE '_smallpict%' scritto senza attenzione rimuoverebbe quei marcatori, e in quel caso il test fallisce.

Abbiamo scelto script semplici al posto della suite di test PHPUnit di WordPress per velocità e costo di setup: non richiedono un server di database né un checkout di WordPress, e tutti e 9 girano in meno di un secondo, quindi eseguirli su sette versioni di PHP non aggiunge quasi nulla a una pull request. Il compromesso è che gli stub modellano solo ciò che vi abbiamo scritto. Il comportamento che dipende dal vero core di WordPress, come la gestione dei metadati della libreria media, non è coperto da questi test.

Il gate pre-deploy verso WordPress.org

Le release escono tramite un workflow separato. Lo avvia il push di un tag come v1.2.9, e il job che fa il commit su SVN di WordPress.org dichiara una dipendenza dalla matrice di 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 significa che il job deploy parte solo quando tutti e sette i job lint vanno a buon fine. Se WPCS fallisce su una qualsiasi versione, GitHub salta deploy e non avviene alcun commit SVN. Lo step di build gira su PHP 7.4, la versione più vecchia che supportiamo. Il token del job ha accesso in sola lettura al repository; l'unica scrittura avviene su SVN di WordPress.org, con credenziali conservate come secret del repository.

Gate pre-deploy nel workflow GitHub Actions Deploy to WordPress.org: WPCS Check superato su PHP 7.4, 8.0, 8.1, 8.2 e 8.3 prima dell'esecuzione del job Deploy

Figura 4: Il workflow Deploy to WordPress.org. I cinque job WPCS Check girano per primi; il job Deploy sotto di essi parte solo dopo che tutti e cinque sono passati.

Il gate esegue di nuovo WPCS sul commit con il tag invece di fidarsi dell'esecuzione precedente sulla pull request. Un tag può puntare a qualsiasi commit, anche a uno pushato direttamente o a uno i cui controlli non sono mai terminati, e il workflow di release non ha altro modo di sapere cosa sta pubblicando.

Eseguire i controlli CI in locale

Gli script Composer racchiudono gli stessi comandi eseguiti dalla CI, così un errore si può riprodurre prima del 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

Per riprodurre l'errore di un singolo job della matrice, esegui gli stessi comandi con quella versione di PHP, per esempio con l'immagine ufficiale dopo 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 corregge solo ciò che uno sniff può correggere in modo meccanico. Le segnalazioni su escape, sanificazione e nonce richiedono una persona che scelga la funzione adatta al contesto, e non le correggiamo automaticamente.

Cosa la pipeline non copre ancora

Abbiamo in lista tre lacune:

  1. Il gate pre-deploy esegue solo WPCS. PHPStan e i test automatici girano sui push verso master e develop e sulle pull request, non sul tag di release. Aggiungere entrambi gli step al job lint del workflow di deploy chiude questa lacuna.
  2. Il nostro ruleset non include PHPCompatibility. Aggiungere phpcompatibility/phpcompatibility-wp con un testVersion di 7.4- segnalerebbe in un'unica esecuzione la sintassi e le funzioni che non esistono su 7.4.
  3. I test usano stub invece di una vera installazione di WordPress. Un job di integrazione su WordPress 5.9 (il nostro minimo) e sull'ultima release coprirebbe il comportamento del core che gli stub non possono riprodurre.

FAQ

Perché i test su matrice da PHP 7.4 a 8.5 sono fondamentali per i plugin WordPress?

WordPress.org distribuisce la stessa release a ogni sito, e l'header del plugin (Requires PHP: 7.4) è l'unico filtro che decide su quali versioni di PHP viene installata. Tra 7.4 e 8.5, PHP ha cambiato il modo in cui le funzioni interne trattano gli argomenti del tipo sbagliato, il modo in cui i numeri si confrontano con le stringhe e quali pattern generano deprecation, quindi un codice corretto su una versione può causare un fatal error o registrare warning su un'altra. Un'esecuzione CI su una sola versione di PHP dimostra soltanto che il plugin funziona su quella versione. Eseguire PHPStan e i test su ogni versione supportata intercetta queste differenze prima che la release arrivi agli utenti.

WPCS sostituisce i tradizionali audit di sicurezza?

No. WPCS controlla i pattern sulla riga in cui compaiono: una variabile della richiesta letta senza sanificazione, un echo senza escape, un handler senza controllo del nonce, una query senza $wpdb->prepare(). Non può stabilire se un handler controlla la capability giusta, se la funzione di escape è adatta al contesto di output, se una richiesta lato server va verso un URL controllato da un utente, o se un utente può accedere ai dati di un altro. Inoltre un commento phpcs:ignore può silenziare uno sniff. Per noi WPCS è la soglia minima che tiene fuori gli errori noti, e le modifiche rilevanti per la sicurezza le rivediamo a mano.

Come gestisce PHPStan le funzioni del core di WordPress senza eseguire codice?

PHPStan non esegue mai il codice che analizza. Legge dichiarazioni e docblock per costruire un modello dei tipi. Per WordPress, szepeviktor/phpstan-wordpress fornisce file stub: le firme, i tipi dei parametri e i tipi di ritorno delle funzioni e delle classi del core di WordPress, senza il loro corpo. PHPStan legge quegli stub come se fossero WordPress, quindi può verificare che una chiamata a wp_delete_file() o get_attached_file() passi e riceva i tipi giusti. Le costanti che WordPress o il plugin definiscono a runtime vanno in un file di bootstrap, che PHPStan carica prima dell'analisi.

Il plugin è disponibile su WordPress.org come smallPict. L'installazione e le impostazioni del Formato di output sono descritte nella guida all'installazione e nel riferimento delle impostazioni delle immagini.

Scritto da smallPict Engineering

Engineering

Realizziamo la conversione delle immagini e la distribuzione via CDN per siti web e app.

Provalo sulle tue immagini.

20 MB al mese gratis. Circa due minuti per configurarlo su WordPress.

Altro su prestazioni delle immagini, Core Web Vitals e storage cloud.

Tutti gli articoli

Cloud & CDN3 min read

SmallPict API/SDK: BYOK vs CDN Gestita, quale dovresti scegliere?

Ignite non include una CDN (i risultati tornano direttamente alla tua app), mentre Velocity e Momentum ti permettono di scegliere tra storage e CDN di SmallPict (l'opzione predefinita) o storage e CDN tuoi. Ecco come decidere quale modello si adatta al tuo progetto.