Nowy blog – nowy początek.
Długo zastanawiałem się, jakiego rodzaju wpisem rozpocząć aktywność. Jestem WordPress Developerem. Będę, siłą rzeczy, pisał sporo o WordPressie, nie mniej jednak zamierzam poświęcać swą uwagę również szerszemu spektrum tematów, od drobnych tricków związanych z konkretnymi przypadkami, które przytrafiły mi się w pracy programistycznej po szeroką, filozoficzną perspektywę. Kusiło mnie, rzecz jasna, by zacząć artykułem o sztucznej inteligencji. Postanowiłem jednak, że AI chwilę zaczeka. Na początek niech będzie coś, z czym nowoczesny development oparty o PHP – czyli również WordPress – nie może się obejść.
Czym jest Composer?
Pamiętam fragment jednej z książek w ramach Trylogii ciągu Williama Gibsona, w której padło stwierdzenie, że oprogramowanie jest jak cebula. Pod warstwą zewnętrzną leży głębsza, pod tamtą kolejna i tak dalej, a każda wyższa zależy w jakiś sposób od tej niższej, dlatego też nie sposób ich od siebie oddzielić. Wizja GIbsona była cyberpunkową dystopią, rzeczywistość nie potrzebowała jednak dużo czasu, aby tę wizję doścignąć, przynajmniej w pewnych aspektach.
Dziś rzadko kiedy tworzymy już profesjonalne oprogramowanie zupełnie od nowa. Tysiące rozwiązań, pomysłów i funkcjonalności zostały już kiedyś przez kogoś zaprogramowane, bardzo często w rzetelny i godny zaufania sposób, a następnie rozwiązania te zostały sprawdzone w boju przez miliony użytkowników. Zarówno z punktu widzenia oszczędności czasu, jak i niezawodności własnego kodu, nie ma sensu po raz tysięczny tworzyć tego samego. Dlatego też w swoich projektach posługujemy się rozmaitymi zależnościami – wspomnianymi „głębszymi warstwami cebuli”, dzięki którym dopisujemy tylko tyle kodu, ile potrzeba w naszej konkretnej implementacji. Aby jednak nie pogubić się w tym chaosie, powstały rozmaite managery pakietów, jak np. npm, które pozwalają z wiersza poleceń zainstalować w projekcie potrzebne zależności.
I tu na scenę wkracza Composer, cały na biało.
Czym właściwie jest Composer? W skrócie: to manager zależności i pakietów dla języka PHP, który pozwala na wygodne zarządzanie bibliotekami stron trzecich oraz własnym kodem w projektach. Composer ułatwia nie tylko instalację i aktualizację paczek, ale i kontrolę ich wersji, a przez integrację z Packagist (centralny rejestr pakietów) umożliwia prostą publikację, użycie lub dzielenie się własnymi rozwiązaniami.
Jedną z najciekawszych funkcjonalności Composera – z punktu widzenia WordPress developera – jest możliwość publikowania własnych pluginów w formie paczek composerowych. Dzięki temu instalacja, aktualizacja i wersjonowanie stają się wygodne i proste – zarówno w swoim projekcie, jak i udostępnione publicznie innym developerom. Bo przychodzi w życiu programisty taki moment, w którym chciałby się on podzielić swoją pracą, dodać coś od siebie do ekosystemu. Composer jest tu jak znalazł.
Przejdźmy więc praktycznie przez cały proces na konkretnym przykładzie – publikacji własnej wtyczki.
Must have: środowisko lokalne, Git i Packagist
Czego będziemy potrzebowali:
- lokalne środowisko developerskie, w którym tworzysz swoje projekty. Z obsługą Composera, Gita oraz PHP z poziomu wiersza poleceń i tak dalej.
- możliwości tworzenia publicznego repozytorium, np. na Githubie.
- konta na Packagist.org
Ogólna koncepcja jest bowiem taka:
- Lokalnie tworzysz swój pakiet composerowy
- Udostępniasz go w publicznym repozytorium
- Podpinasz to repozytorium pod Packagista, który rozdystrybuuje paczkę w ekosystemie Composera i umożliwi jej instalację z wiersza poleceń w dowolnym projekcie.
Dzięki temu, że pakiet jest upubliczniony w repozytorium, możesz go łatwo udoskonalać i wersjonować.
Tworzenie pakietu Composera krok po kroku
Na potrzeby demonstracji załóżmy, że masz już przygotowaną własną wtyczkę. Jeśli nie, stwórz najprostszy plugin, który w stopce strony wypisuje aktualną datę i godzinę. Zapisz go na razie gdziekolwiek. Tak, to bzdura, ale w tym przykładzie nie chodzi nam o wtyczkę, tylko o proces.
my-fancy-plugin.php:
<?php
/**
* Plugin Name: Footer Date Time Renderer
* Description: Outputs the current date and time in the site footer.
* Version: 1.0
* Author: Your Name
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class Footer_Date_Time_Renderer {
public function __construct() {
add_action( 'wp_footer', [ $this, 'render_footer_datetime' ] );
}
/**
* Renders the current date and time in the footer.
*/
public function render_footer_datetime() {
$datetime = current_time( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ) );
echo '<div class="footer-datetime">';
echo esc_html( $datetime );
echo '</div>';
}
}
new Footer_Date_Time_Renderer();
Teraz przystępujemy do tworzenia pakietu. Na początek struktura:
- Stwórz folder o dowolnej nazwie, np.
my-composer-package. - Wewnątrz stwórz foldery
bin,srcoraztemplates. - Do folderu
templatesprzekopiuj plik(i) swojej wtyczki. W tym artykule będziemy się posługiwali jednoplikowym przykładem mini pluginu, który stworzyliśmy powyżej.
Okej, następnym krokiem jest przygotowanie pliku composer.json – serca każdej composerowej paczki. Tam definiujesz metadane pakietu, zależności, wersje oraz ścieżki do plików. Rzuć okiem na przykład:
{
"name": "your-vendor-name/super-fancy-wordpress-plugin",
"description": "Scaffold WordPress plugin example",
"type": "library",
"license": "MIT",
"authors": [
{
"name": "Your Name",
"email": "your.email@some.mail"
}
],
"require": {
"php": ">=7.4"
},
"autoload": {
"psr-4": {
"YVN\\WPPluginScaffold\\": "src/"
}
},
"bin": [
"bin/scaffold"
],
"scripts": {
"post-install-cmd": [
"@php -r \"echo '\\n✅ Package installed. Run: vendor/bin/scaffold to install the plugin\\n';\""
]
}
}
Ważną częścią zaawansowanej dystrybucji pluginów są tzw. skrypty scaffoldujące, które pozwalają automatycznie kopiować pliki z określonych ścieżek w projekcie do właściwych miejsc w strukturze katalogów (np. WordPressa). W tym celu przygotuj plik src/ScaffoldCommand.php oraz plik wykonywalny bin/scaffold. Przykładowy kod znajdziesz poniżej:
ScaffoldCommand.php:
<?php
namespace YVN\WPPluginScaffold;
class ScaffoldCommand
{
private $projectRoot;
private $templatesDir;
private $wpRoot;
private $pluginDir;
public function __construct()
{
$this->projectRoot = dirname(__DIR__, 4);
$this->templatesDir = dirname(__DIR__) . '/templates';
$this->wpRoot = $this->findWordPressRoot();
if (! $this->wpRoot) {
echo "❌ Error: WordPress installation not found.\n";
echo " Could not locate wp-load.php in parent directories.\n";
echo " Please run this command from within a WordPress installation.\n\n";
exit(1);
}
$this->pluginDir = $this->wpRoot . '/wp-content/plugins/my-fancy-plugin';
}
public function run()
{
echo "🚀 TN WordPress Simple Plugin Scaffold\n\n";
echo "📍 WordPress root detected: " . $this->wpRoot . "\n";
echo "📍 Plugin destination folder: " . $this->pluginDir . "\n\n";
if ($this->filesExist()) {
echo "⚠️ Plugin folder or file already exists. Overwrite? (y/n): ";
$handle = fopen("php://stdin", "r");
$line = fgets($handle);
if (trim($line) !== 'y') {
echo "❌ Aborted.\n";
return;
}
}
$this->createDirectory($this->pluginDir);
$this->copyFile('my-fancy-plugin.php', '/my-fancy-plugin.php');
echo "\n✅ Plugin scaffold created!\n";
echo "You can now activate the plugin in the WordPress admin.\n\n";
}
/**
* Find WordPress root by looking for wp-load.php
*/
private function findWordPressRoot()
{
$currentDir = $this->projectRoot;
$maxLevels = 10; // Safety limit
for ($i = 0; $i < $maxLevels; $i++) {
if (file_exists($currentDir . '/wp-load.php')) {
return realpath($currentDir);
}
$parentDir = dirname($currentDir);
if ($parentDir === $currentDir) {
break;
}
$currentDir = $parentDir;
}
return false;
}
private function filesExist()
{
return is_dir($this->pluginDir) ||
file_exists($this->pluginDir . '/my-fancy-plugin.php');
}
private function createDirectory($path)
{
if (!is_dir($path)) {
mkdir($path, 0755, true);
echo "📁 Created: " . basename($path) . "/\n";
}
}
private function copyFile($template, $destination)
{
$source = $this->templatesDir . '/' . $template;
$dest = $this->pluginDir . $destination;
if (copy($source, $dest)) {
echo "✅ Created: " . $destination . "\n";
} else {
echo "❌ Failed: " . $destination . "\n";
}
}
}
scaffold:
#!/usr/bin/env php
<?php
// Autoload
foreach ([__DIR__ . '/../../../autoload.php', __DIR__ . '/../vendor/autoload.php'] as $file) {
if (file_exists($file)) {
require $file;
break;
}
}
use YVN\WPPluginScaffold\ScaffoldCommand;
$command = new ScaffoldCommand();
$command->run();
Opcjonalnie, możesz też dodać pliki README.md oraz LICENSE. Moim zdaniem w dobrze utrzymanym pakiecie byłoby to mile widziane.
Publikacja pakietu
Gdy masz już gotowy kod, plik composer.json, folder templates i potrzebne skrypty, pora przejść do wersjonowania. Zainicjuj repozytorium gita (polecenie git init), dodaj wszystkie pliki (git add .), zacommituj zmiany (git commit -m "Initial commit") i zsynchronizuj repozytorium z własnym kontem, np. na Githubie (git remote add origin [adres repo]). Pamiętaj, zawczasu musisz stworzyć sobie repozytorium. Musi ono być publiczne.
Wszystko gra? Okej, zatem opublikuj swój kod: git push.
Następnym krokiem będzie nadanie wersji twojemu pakietowi. To newralgiczne, bo Packagist opiera wykrywanie zmian właśnie o numerację release’ów – najprościej zrobić to tworząc tag gitowy odpowiadający wersji, np:
git tag v1.0.0git push origin v1.0.0
Teraz logujesz się na Packagist.org i publikujesz swój pakiet, podając adres publicznego repozytorium. Synchronizacja odbywa się automatycznie – każda zmiana wymagająca aktualizacji to po prostu kolejny tag w repo. Packagist dba już o swoje, a Twój plugin, dzięki integracji z Composerem, może być użyty przez każdego na całym świecie jednym poleceniem.
Werble: Instalacja!
Jak wygląda instalacja takiej paczki po stronie projektu WordPressowego? Zakładając, że masz zainstalowanego Composera (oraz wymagane zależności, takie jak PHP >= 7.4, Git i dostęp do terminala), w katalogu głównym WordPressa odpalasz dwie komendy:
composer require --dev your-vendor-name/super-fancy-wordpress-plugin
vendor/bin/scaffold
Pierwsza zaciąga twoją paczkę do katalogu vendor i rejestruje ją w projekcie, druga wykonuje skrypt kopiujący pliki pluginu we właściwe miejsce. Od tego momentu plugin jest gotowy do użycia, a jego aktualizacja sprowadza się do prostego composer update your-vendor-name/super-fancy-wordpress-plugin i ponownego wywołania skryptu scaffoldingowego.
Komponuj z Composerem!
Co zyskujemy? Przede wszystkim pełną automatyzację procesu instalacji, aktualizacji i zarządzania własnymi paczkami. Kod wtyczki staje się niezależny od projektu – nie musisz ręcznie przenosić plików czy osobno aktualizować każdej strony klienta. Pozwalasz innym korzystać z twojej pracy jednym poleceniem, spójnie zarządzić wersjami, a przy tym zachować schludność i powtarzalność procesu deploymentu.
Na koniec: powyższy instruktaż to zaledwie szkic, od którego rozpocznie się twoja własna droga do budowania pakietów pod Composera. To temat rzeka, mam jednak nadzieję, że ten instruktaż to dobry punkt wyjścia: poznanie workflow i pierwszy krok do wyniesienia procesu instalacji/aktualizacji własnych rozwiązań WordPressowych na wyższy poziom.