İçeriğe geç
smallPict
Ücretsiz Başla

Engineering16 min read

WordPress Eklentisi için CI/CD: WPCS, PHPStan ve PHP 7.4'ten 8.5'e

GitHub Actions'ta WordPress eklentisi CI/CD: PHP 7.4'ten 8.5'e WPCS, PHPStan, otomatik testler ve WordPress.org'a dağıtım öncesi kapı.

smallPict Engineering

Engineering

smallPict'in WordPress eklentisi yüklenen görselleri WebP ve AVIF'e dönüştürür ve ziyaretçilere sunar. Bir sürümü etiketlediğimizde GitHub Actions onu WordPress.org SVN deposuna commit eder ve sürüm oradan eklentinin kurulu olduğu her siteye ulaşır. Otomatik güncellemeleri açık olan siteler, değişikliği kimse incelemeden sürümü kurar. Eklenti Requires PHP: 7.4 ve Requires at least: 5.9 bildirir; bu yüzden tek bir derleme hem hâlâ PHP 7.4 kullanan paylaşımlı bir hostingde hem de PHP 8.5 çalıştıran bir konteynerde çalışmak zorundadır.

Bir eklentideki fatal error wp-admin'i çökertebilir. Ayarlar sayfasında escape edilmemiş bir değer, aynı anda her sitede bir XSS açığı demektir. Eksik bir nonce kontrolü, bir yönetici işlemini CSRF hedefine çevirir. Bunların hiçbiri sessizce yamalanamaz: düzeltme yeni bir sürüm gerektirir ve bazı siteler o sürüm gelene kadar bozuk sürümde kalır.

Bu yazı, WordPress eklentimizin CI/CD pipeline'ını anlatıyor: yedi PHP sürümünde çalışan WordPress Coding Standards (WPCS), PHPStan ve otomatik testler ile WordPress.org'un önündeki dağıtım öncesi kapı. Aşağıdaki her şey smallpict-wp deposunun 1.2.9 sürümünden alınmıştır.

Öne çıkanlar

  • master dalına açılan her pull request, GitHub Actions'ta PHP 7.4, 8.0, 8.1, 8.2, 8.3, 8.4 ve 8.5 üzerinde paralel olarak WPCS, PHPStan ve 9 otomatik test betiğini çalıştırır.
  • WPCS; sanitize edilmiş girdi, escape edilmiş çıktı, nonce ve hazırlanmış sorgular (prepared queries) zorunlu kılar. Seviye 5'teki PHPStan, WordPress'i çalıştırmadan WordPress stub'larından tür hatalarını ve ölü dalları bulur.
  • Bir sürüm etiketi WPCS'yi yedi PHP sürümünün hepsinde yeniden çalıştırır ve WordPress.org SVN'ine commit eden job ancak yedisi de geçtikten sonra başlar.

Bir bakışta WordPress eklentisi CI/CD pipeline'ı

Eklentiyi iki GitHub Actions workflow'u korur.

WorkflowTetikleyiciJob'larKontroller
phpcs.yml (PHP Code Quality & Standards)master veya develop dalına push, master dalına pull requestPHP sürümü başına bir job: 7.4, 8.0, 8.1, 8.2, 8.3, 8.4, 8.5WPCS, PHPStan, otomatik testler
deploy-all.yml (Deploy to WordPress.org)v* etiketinin push edilmesi7 PHP sürümünün her birinde WPCS, ardından deployWPCS, ardından derleme ve SVN commit'i

PHP sürüm kapsamı hakkında not: Bu yazıdaki ekran görüntüleri, PHP 7.4'ten 8.3'e kadar olan önceki CI çalıştırmalarımızı gösteriyor. Bugün GitHub Actions test matrisimiz PHP 7.4'ten PHP 8.5'e kadar genişledi; böylece eski ortamlarda hiçbir gerileme olmadan modern PHP çalışma ortamlarıyla sürekli ileriye dönük uyumluluk sağlanıyor.

Tüm araçlar Composer geliştirme bağımlılığıdır (dev dependency), bu yüzden hiçbiri kullanıcılara ulaşmaz:

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

GitHub Actions'ta çoklu sürüm PHP matris testi

PHP 7.4 ile PHP 8.5 arasında neler değişiyor

PHP 7.4 ve PHP 8.5 aynı eklenti kaynak kodunu farklı çalıştırır. WordPress eklenti kodunu etkileyen değişikliklerden bazıları:

  • PHP 8.0 ile birçok dahili fonksiyon yanlış türde bir argüman için TypeError fırlatmaya başladı; 7.4 ise bu durumda bir uyarıyla birlikte null döndürüyordu. strlen() fonksiyonuna dizi geçen kod 7.4'te çalışmaya devam ediyordu, 8.0'da duruyor.
  • PHP 8.0, bir sayının sayısal olmayan bir string ile karşılaştırılma biçimini değiştirdi. 0 == "abc" ifadesi 7.4'te true, 8.0'da false sonucunu verir; bu da seçenek değerleri üzerindeki bazı gevşek karşılaştırmaların sonucunu sessizce tersine çevirir.
  • PHP 8.0, str_starts_with() ve ilgili fonksiyonları ekledi. Görsel işlemcimiz str_starts_with() çağırır. Bu, PHP 7.4'te yalnızca WordPress 5.9 ve sonrası bir polyfill içerdiği için çalışır; bunu da Requires at least: 5.9 başlığımız garanti eder.
  • PHP 8.1, dahili fonksiyonların null kabul etmeyen parametrelerine null geçmeyi kullanımdan kaldırılmış (deprecated) olarak işaretledi. strtolower( wp_parse_url( $url, PHP_URL_HOST ) ) 7.4'te sorunsuzdur; 8.1'de ise $url göreli olduğunda ve host null olduğunda log'a bir deprecation yazar. Bazı hostingler deprecation mesajlarını sayfaya basar.
  • PHP 8.2, dinamik özellikleri (dynamic properties) kullanımdan kaldırdı. Kendi sınıflarınızdan birinde bildirilmemiş bir özelliğe değer atamak, her istekte log'a bir deprecation yazar.

Bunların her biri ancak kod, farklı davranan PHP sürümünde analiz edildiğinde veya çalıştırıldığında ortaya çıkar. Pipeline'ın master dalına açılan her pull request'i aynı anda yedi sürümün hepsinde çalıştırmasının nedeni budur.

GitHub Actions matrisi

GitHub Actions'ta WordPress eklentisi CI çalıştırması: PHP 7.4, 8.0, 8.1, 8.2 ve 8.3 üzerinde beş paralel WPCS ve PHPStan job'u ile PHP matris testi, hepsi başarılı

Şekil 1: 1.2.0 çalışmasının master dalına birleştirilmesi için PHP Code Quality & Standards workflow'u. Her PHP sürümü ayrı bir job'dur ve PHP 8.3 job'u her job'un çalıştırdığı adımları gösterir: PHPCS, PHPStan, ardından otomatik testler.

PHP sürüm kapsamı hakkında not: Yukarıdaki ekran görüntüleri, PHP 7.4'ten 8.3'e kadar olan önceki CI çalıştırmalarımızı gösteriyor. Bugün GitHub Actions test matrisimiz PHP 7.4'ten PHP 8.5'e kadar genişledi; böylece eski ortamlarda hiçbir gerileme olmadan modern PHP çalışma ortamlarıyla sürekli ileriye dönük uyumluluk sağlanıyor.

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 varsayılan değeri olan true olarak kalır; bu yüzden bir sürüm başarısız olduğunda GitHub hâlâ çalışan job'ları iptal eder. Bozuk bir pull request'in maliyeti düşük olur, karşılığında aynı çalıştırmada her sürümün sonucunu göremezsiniz.

Matrisin kanıtladıkları ve kanıtlamadıkları

Üç kontrol matristen aynı faydayı görmez. PHPStan kodu üzerinde çalıştığı PHP sürümüne göre analiz eder, testler de kodu o sürümde çalıştırır; bu yüzden ikisi de her job'da farklı sonuç verebilir. PHPCS token'lar üzerinde çalışır ve pratikte yedi sürümün hepsinde aynı sonucu verir; matriste esas olarak araç zincirinin her sürümde kurulup çalıştığını kanıtlar. Söz dizimini ve fonksiyonları tek geçişte bir PHP sürüm aralığına göre kontrol etmek PHPCompatibility'nin işidir ve kural setimiz bunu henüz içermiyor.

WordPress Coding Standards (WPCS) otomasyonu

Bir eklenti için önemli güvenlik sniff'leri

WPCS, WordPress için yazılmış bir PHP_CodeSniffer sniff setidir. Eklenti güvenliği için en önemli kurallar WordPress kural setinin kendisindedir:

  • WordPress.Security.ValidatedSanitizedInput, unslash ve sanitize işleminden geçmemiş her $_POST, $_GET, $_REQUEST veya $_COOKIE okumasını işaretler.
  • WordPress.Security.EscapeOutput, esc_html(), esc_attr() veya esc_url() gibi bir escape fonksiyonundan geçmemiş bir değeri yazdıran her echo veya print kullanımını işaretler.
  • WordPress.Security.NonceVerification, nonce doğrulamadan istek verisini okuyan bir handler'ı işaretler.
  • WordPress.DB.PreparedSQL ve PreparedSQLPlaceholders, $wpdb->prepare() yerine string birleştirmeyle oluşturulmuş bir sorguyu ve argümanlarıyla eşleşmeyen placeholder'ları işaretler.

WPCS kural setimiz

phpcs.xml.dist, WordPress-Extra ve WordPress-Docs setlerini ekler, çeviri sniff'leri için text domain'i sabitler ve her global fonksiyon, sınıf ve sabitin önekimizi taşımasını zorunlu kılar; böylece eklenti aynı sitedeki başka bir eklentinin adlarıyla çakışamaz:

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>

WPCS'den geçen bir AJAX handler'ı

Eklentideki bu handler, offload edilmiş medyayı gruplar halinde geri yükler. Her girdi sınırı ilk satırlarda ele alınır:

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

Nonce ve yetki (capability) birlikte kontrol edilir, çünkü geçerli bir nonce isteğin yönetici sayfamızdan geldiğini kanıtlar, kullanıcının bu işlemi yapmaya yetkili olduğunu değil. $_POST['after'] sorguya ulaşmadan önce unslash edilir ve absint() ile dönüştürülür; değer zaten bir tamsayı olsa da sorgu yine $wpdb->prepare() üzerinden geçer.

Susturmalar bir sniff adı ve gerekçe ister

Yukarıdaki phpcs:ignore satırı bilinçli. WPCS, nesne önbelleği olmadan yapılan doğrudan veritabanı sorguları için uyarır. Bu, ön yüz okumaları için iyi bir tavsiyedir, satırları her çağrıda değişen bir yönetici işlemi için ise yanlıştır. Kuralımız şu: her ignore tam sniff adını belirtir ve gerekçeyi -- sonrasında yazar. Yalın bir // phpcs:ignore code review'dan geçmez.

CI'da PHPCS bir checkstyle raporu yazar ve cs2pr bunu pull request diff'inde açıklamalara (annotation) dönüştürür; böylece inceleyen kişi her ihlali bir log içinde değil, ona neden olan satırda görür.

PHPStan statik analiziyle mantık hatalarını yakalamak

WPCS kodu satır satır okur. Bir echo ifadesinde escape çağrısı olmadığını bilir, ama bir değişkenin hangi türü tuttuğunu ya da bir dalın hiç çalışıp çalışamayacağını bilmez. PHPStan her fonksiyondan geçen türlerin bir modelini kurar ve bu modelle çelişen kodu raporlar: var olmayan bir metodu çağırmak, string gereken yere string|false geçmek, asla eşit olamayacak değerleri karşılaştırmak, her zaman doğru ya da her zaman yanlış olan koşullar.

WordPress'i çalıştırmadan PHPStan'i WordPress ile kullanmak

szepeviktor/phpstan-wordpress, WordPress çekirdek fonksiyonlarının ve sınıflarının imzalarını stub dosyaları aracılığıyla PHPStan'e verir; bunlara WordPress'e özgü birkaç tür eklentisi de eşlik eder. phpstan/extension-installer onu otomatik olarak kaydeder. PHPStan bu bildirimleri okur ve WordPress'i ya da bir veritabanını asla yüklemez.

PHPStan yapılandırmamız

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

Seviye 5, alt seviyelerin bilinmeyen sınıf, metot ve özellik, dönüş türü ve ölü kod kontrollerine ek olarak bir fonksiyona veya metoda geçen her argümanın türünü kontrol eder. treatPhpDocTypesAsCertain: false, PHPStan'e kendi @param docblock'larımızı kanıt olarak kabul etmemesini söyler. WordPress bir filtrenin döndürdüğü her şeyi aktarır; bu yüzden int olarak belgelenen bir parametre başka bir eklentiden string olarak gelebilir ve PHPStan'in bu durumu ele alan savunma kontrollerini korumasını istiyoruz. Bootstrap dosyası, normalde çalışma zamanında tanımlanan eklenti sabitlerini (SMALLPICT_PATH, SMALLPICT_URL ve diğerleri) tanımlar.

GitHub Actions'ta WordPress için PHPStan statik analiz logu: WPCS adımı temiz, PHPStan 11 eklenti dosyasının 11'ini analiz etti, sonuç "[OK] No errors"

Şekil 2: PHP 8.3 job'unun PHPCS ve PHPStan adımları. Raporlanacak bir şey olmadığında PHPCS hiçbir şey yazdırmaz. PHPStan 11 eklenti dosyasını (ana eklenti dosyası ve includes/ içindeki 10 sınıf) analiz eder ve hata bildirmez.

Gerçek bir PHPStan bulgusu: görsel işlemcinin 626. satırı

2 Ekim 2026'da pipeline PHPStan adımında tek bir hatayla başarısız oldu:

PHPStan bir WordPress eklentisinde hata yakalıyor: includes/class-smallpict-image-processor.php dosyasının 626. satırında "Right side of && is always true", kural booleanAnd.rightAlwaysTrue, job PHP 8.2'de başarısız

Şekil 3: PHP 8.2 job'u, includes/class-smallpict-image-processor.php dosyasının 626. satırında booleanAnd.rightAlwaysTrue ile PHPStan adımında durdu. O sırada eklentinin analiz edilen yollarda 9 dosyası vardı.

Bu kod bir dönüşümün son adımıdır. Eklentinin Çıktı biçimi ayarı WebP veya AVIF olduğunda dönüştürülen dosya ek (attachment) olur ve disk alanından tasarruf etmek için özgün yükleme silinir. Diğer seçenekler, "AVIF, yedek olarak WebP" ve "Özgün biçimi koru", özgün JPEG ve PNG dosyalarını korur. Silme dalı şuydu:

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

PHPStan'in iddiası, file_exists( $main_file_path ) ifadesinin o noktada her zaman doğru olduğuydu. Nedeni 150 satır yukarıda, aynı metodun başında:

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

Metot yalnızca dosya varsa devam eder ve PHPStan bu bilgiyi 626. satıra kadar taşır.

Bulguyu olduğu gibi kabul etmedik. file_exists() dosya sistemine sorar ve cevap iki çağrı arasında değişebilir. PHPStan böyle bir çağrının sonucunu varsayılan olarak hatırlar (rememberPossiblyImpureFunctionValues seçeneği) ve arada diskte hiçbir şeyin değişmediğini varsayar. Kontrolü silmeden önce kodu okuyarak iki şeyi doğruladık:

  1. Koruma koşulu ile 626. satır arasında hiçbir şey kaynak dosyayı silmiyor veya taşımıyor. Dönüşüm her çıktıyı geçici bir dosyaya yazar ve yeni bir yola taşır; o yol üzerindeki tek wp_delete_file() çağrıları geçici dosyaları siler. Yerel dosyaları gerçekten silen offload adımı 626. satırdan sonra çalışır.
  2. wp_delete_file() zaten eksik bir dosyayı sorun etmez. Yolu wp_delete_file filtresinden geçirir ve @unlink() çağırır; dosya zaten yoksa bu çağrı zararlı bir şey yapmaz.

İkisi de doğrulanınca koşulun ölü kod olduğu netleşti. Bir silme dalındaki ölü kod, sonraki okuyucuyu dosyanın metot ortasında kaybolabileceğini düşünmeye yöneltir. Düzeltme onu kaldırdı:

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

Bulgu bir çökme değildi. Değeri, metot hakkında söylediğindeydi: kodun varsayımları, kullanıcı dosyalarını silen tek dalda, yapısından kopmuştu. Çıkardığımız ders "analizöre güven"den daha dar. Dosya sistemi, ağ veya zaman fonksiyonu için gelen bir "her zaman doğru" ya da "her zaman yanlış" raporunda, koşulu kaldırmadan önce iki çağrı arasında ne olduğunu elle kontrol etmek gerekir.

PHPUnit olmadan WordPress eklentisi için otomatik test

Her matris job'unun son adımı tests/ içindeki dosyaları çalıştırır. Bunlar PHPUnit testleri değildir. Her dosya düz bir PHP betiğidir: ihtiyaç duyduğu WordPress fonksiyonları (get_option(), update_option(), sanitize_key() vb.) için minimal stub'lar tanımlar, test edilen eklenti sınıfını yükler, onu çalıştırır ve ilk hatada sıfırdan farklı bir kodla çıkar:

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

Bugün bu türden 9 betik var. Bir hatanın müşteriye veri ya da para kaybettireceği yolları kapsıyorlar: WebP ve AVIF dönüşüm pipeline'ı ve yedek yolları, görsel sunumu, bulut depolamaya dosya offload etme ve oradan silme, offload edilmiş dosyaları gruplar halinde geri yükleme, bir hesap ödemeyi bıraktığında yaşanan davranış, depolama kotası ve kaldırma. Kaldırma testi gerçek kaldırma sorgularını bellek içi bir SQLite veritabanında çalıştırır ve geriye ne kaldığını kontrol eder:

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

Bu doğrulama, yanlışlıkla geri alınması kolay bir kararı korur. Eklentiyi kaldırmak ayarlarını siler ama hangi dosyaların yalnızca bulut depolamada bulunduğunu kaydeden post meta'yı korur; böylece eklentiyi yeniden kuran bir site görsellerini yine bulabilir. Dikkatsiz bir DELETE ... LIKE '_smallpict%' bu işaretleri silerdi ve silerse test başarısız olur.

WordPress PHPUnit test paketi yerine düz betikleri hız ve kurulum maliyeti nedeniyle seçtik: veritabanı sunucusuna ve bir WordPress kopyasına ihtiyaç duymazlar, 9'unun tamamı bir saniyeden kısa sürede çalışır, bu yüzden onları yedi PHP sürümünde çalıştırmak bir pull request'e neredeyse hiç süre eklemez. Bedeli şu: stub'lar yalnızca onlara yazdığımız davranışı modeller. Medya kitaplığının kendi meta veri işleme mantığı gibi gerçek WordPress çekirdeğine bağlı davranışlar bu testlerin kapsamında değildir.

WordPress.org'a dağıtım öncesi kapı

Sürümler ayrı bir workflow ile yayınlanır. v1.2.9 gibi bir etiketin push edilmesi onu başlatır ve WordPress.org SVN'ine commit eden job, lint matrisine bağımlılık bildirir:

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, deploy job'unun yalnızca yedi lint job'unun tümü başarılı olduğunda başlayacağı anlamına gelir. WPCS herhangi bir sürümde başarısız olursa GitHub deploy job'unu atlar ve SVN commit'i yapılmaz. Derleme adımı, desteklediğimiz en eski sürüm olan PHP 7.4 üzerinde çalışır. Job'un token'ı depoya yalnızca okuma erişimine sahiptir; tek yazma işlemi WordPress.org SVN'ine yapılır ve kimlik bilgileri depo secret'larında saklanır.

Deploy to WordPress.org GitHub Actions workflow'unda dağıtım öncesi kapı: Deploy job'u çalışmadan önce WPCS Check PHP 7.4, 8.0, 8.1, 8.2 ve 8.3'te başarılı oldu

Şekil 4: Deploy to WordPress.org workflow'u. Önce beş WPCS Check job'u çalışır; altlarındaki Deploy job'u yalnızca beşi de geçtikten sonra çalışır.

Kapı, önceki pull request çalıştırmasına güvenmek yerine etiketlenen commit üzerinde WPCS'yi yeniden çalıştırır. Bir etiket herhangi bir commit'i gösterebilir; doğrudan push edilmiş ya da kontrolleri hiç bitmemiş bir commit de olabilir ve sürüm workflow'unun neyi yayınladığını bilmesinin başka bir yolu yoktur.

CI kontrollerini yerelde çalıştırmak

Composer betikleri CI'ın çalıştırdığı komutların aynısını sarar; böylece bir hata push etmeden önce yeniden üretilebilir:

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

Tek bir matris job'undaki hatayı yeniden üretmek için aynı komutları o PHP sürümünde çalıştırın, örneğin composer install sonrasında resmi imajla:

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 yalnızca bir sniff'in mekanik olarak düzeltebildiği şeyleri düzeltir. Escape, sanitize ve nonce bulgularında hangi fonksiyonun bağlama uyduğuna bir insanın karar vermesi gerekir; bunları otomatik düzeltmeyiz.

Pipeline'ın henüz kapsamadıkları

Listemizde üç eksik var:

  1. Dağıtım öncesi kapı yalnızca WPCS çalıştırır. PHPStan ve otomatik testler master ve develop dallarına yapılan push'larda ve pull request'lerde çalışır, sürüm etiketinde çalışmaz. İki adımı da dağıtım workflow'unun lint job'una eklemek bu açığı kapatır.
  2. Kural setimiz PHPCompatibility içermiyor. testVersion değeri 7.4- olan phpcompatibility/phpcompatibility-wp eklemek, 7.4'te olmayan söz dizimini ve fonksiyonları tek çalıştırmada işaretler.
  3. Testler gerçek bir WordPress kurulumu yerine stub kullanır. WordPress 5.9'a (minimumumuz) ve en son sürüme karşı çalışan bir entegrasyon job'u, stub'ların kapsayamadığı çekirdek davranışını kapsar.

SSS

PHP 7.4'ten 8.5'e matris testi WordPress eklentileri için neden kritik?

WordPress.org aynı sürümü her siteye dağıtır ve eklenti başlığı (Requires PHP: 7.4) hangi PHP sürümlerinin onu kuracağını belirleyen tek filtredir. 7.4 ile 8.5 arasında PHP; dahili fonksiyonların yanlış argüman türlerini nasıl ele aldığını, sayıların string'lerle nasıl karşılaştırıldığını ve hangi kalıpların deprecation ürettiğini değiştirdi. Bu yüzden bir sürümde doğru olan kod başka bir sürümde fatal error verebilir veya log'a uyarı yazabilir. Tek bir PHP sürümündeki CI çalıştırması, eklentinin yalnızca o sürümde çalıştığını kanıtlar. PHPStan'i ve testleri desteklenen her sürümde çalıştırmak, bu farkları sürüm kullanıcılara ulaşmadan yakalar.

WPCS geleneksel güvenlik denetimlerinin yerini tutar mı?

Hayır. WPCS kalıpları ortaya çıktıkları satırda kontrol eder: sanitize edilmeden okunan bir istek değişkeni, escape edilmemiş bir echo, nonce kontrolü olmayan bir handler, $wpdb->prepare() kullanmayan bir sorgu. Bir handler'ın doğru yetkiyi kontrol edip etmediğini, escape fonksiyonunun çıktı bağlamına uyup uymadığını, sunucu tarafı bir isteğin kullanıcının kontrol ettiği bir URL'ye gidip gitmediğini ya da bir kullanıcının başka bir kullanıcının verisine erişip erişemeyeceğini anlayamaz. Bir phpcs:ignore yorumu da bir sniff'i susturabilir. WPCS'yi bilinen hataları dışarıda tutan bir taban olarak görüyoruz ve güvenlikle ilgili değişiklikleri elle inceliyoruz.

PHPStan, WordPress çekirdek fonksiyonlarını kodu çalıştırmadan nasıl ele alır?

PHPStan analiz ettiği kodu asla çalıştırmaz. Bir tür modeli kurmak için bildirimleri ve docblock'ları okur. WordPress için szepeviktor/phpstan-wordpress stub dosyaları sağlar: WordPress çekirdek fonksiyonlarının ve sınıflarının gövdeleri olmadan imzaları, parametre türleri ve dönüş türleri. PHPStan bu stub'ları WordPress'in kendisiymiş gibi okur; böylece wp_delete_file() veya get_attached_file() çağrısının doğru türleri geçip aldığını kontrol edebilir. WordPress'in veya eklentinin çalışma zamanında tanımladığı sabitler, PHPStan'in analizden önce yüklediği bir bootstrap dosyasına konur.

Eklenti WordPress.org'da smallPict adıyla yer alıyor. Kurulum ve Çıktı biçimi ayarları kurulum kılavuzunda ve görsel ayarları başvuru sayfasında anlatılıyor.

Yazan: smallPict Engineering

Engineering

Web siteleri ve uygulamalar için görsel dönüştürme ve CDN dağıtımı geliştiriyoruz.

Kendi görsellerinizle deneyin.

Ayda 20 MB ücretsiz. WordPress'te kurulumu yaklaşık iki dakika.

Görsel performansı, Core Web Vitals ve bulut depolama hakkında daha fazlası.

Tüm yazılar

WordPress2 min read

CDN ile WordPress Görsel Optimizasyonu: Neler Dahil ve Adil Kullanım Nedir?

SmallPict ücretli WordPress planları yüksek hızlı yerel dağıtım (Starter) veya isteğe bağlı yönetilen küresel CDN (Pro ve Business) içerir. Tam olarak nelerin dahil olduğu, neyin adil kullanım sayıldığı ve paylaşılan kullanım havuzumuzun birden fazla sitede nasıl çalıştığı aşağıda.