Publikacja wtyczki w repozytorium WordPress

Aby przećwiczyć proces publikacji własnej wtyczki do repozytorium WordPress.org, przygotowałem prostą wtyczkę o nazwie Snake Retro Game Shortcode
Jej celem było umożliwienie osadzenia klasycznej gry w węża na dowolnej stronie lub wpisie WordPressa poprzez użycie shortcode [snake_game]

Nie będę tutaj szczegółowo omawiał tym razem samej wtyczki, ale w skrócie napiszę co się dzieje i podam kod.

Gra Snake

Score: 0

Use ← ↑ ↓ → to move, space to pause.

Główne komponenty wtyczki

Plik główny PHP (snake-retro-game-shortcode-by-eskim.php)

  • Definiuje nagłówek wymagany przez WordPressa (nazwa, opis, wersja, autor, wymagania PHP i WordPressa).
  • Zabezpiecza plik przed bezpośrednim dostępem (if ( ! defined( 'ABSPATH' ) ) exit;).
  • Rejestruje shortcode [snake_game], który wstawia na stronę kontener HTML z dynamicznie ustawianymi parametrami gry (np. szybkość, kolory, rozmiary).
  • Rejestruje i ładuje pliki JavaScript i CSS tylko wtedy, gdy faktycznie są potrzebne — np. gdy wyświetlany jest wpis lub aktywny jest widżet (is_singular() lub is_active_widget()).
/**
 * Plugin Name:       Snake Retro Game Shortcode by Eskim
 * Plugin URI:        https://eskim.pl/snake-retro-game-shortcode-by-eskim-en/
 * Description:       Klasyczna gra w węża, dostępna jako shortcode do WordPressa.
 * Version:           1.1.0
 * Requires at least: 5.0
 * Requires PHP:      7.0
 * Author:            Eskim
 * Author URI:        https://eskim.pl
 * License:           GPL v2 or later
 * License URI:       https://www.gnu.org/licenses/gpl-2.0.html
 * Text Domain:       snake-retro-game-shortcode-by-eskim
 * Domain Path:       /languages
 */

// Zabezpieczenie przed bezpośrednim dostępem
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

/**
 * Rejestruje shortcode     
Score: 0

Use ← ↑ ↓ → to move, space to pause.

, który renderuje kontener i <canvas> z grą. * * @return string HTML gry Snake. */ function eskim_snake_game_shortcode($atts) { $atts = shortcode_atts([ 'speed' => 65, 'background_color' => '#000', 'border_color' => '#333', 'snake_color' => 'lime', 'food_color' => 'red', 'width' => 300, 'height' => 300, ], $atts, 'snake_game'); ob_start(); ?> <div id="snake-game-container" data-speed="<?php echo esc_attr($atts['speed']); ?>" data-bg-color="<?php echo esc_attr($atts['background_color']); ?>" data-border-color="<?php echo esc_attr($atts['border_color']); ?>" data-snake-color="<?php echo esc_attr($atts['snake_color']); ?>" data-food-color="<?php echo esc_attr($atts['food_color']); ?>" data-width="<?php echo esc_attr($atts['width']); ?>" data-height="<?php echo esc_attr($atts['height']); ?>" > <div id="snake-score">Score: 0</div> <!-- Ustawiamy dynamiczne wymiary --> <div class="snake-canvas-wrapper" style="position: relative; display: inline-block;"> <canvas id="snake-game" width="<?php echo esc_attr($atts['width']); ?>" height="<?php echo esc_attr($atts['height']); ?>"></canvas> <button id="start-snake-game"><?php esc_html_e('Start Game', 'snake-retro-game-shortcode-by-eskim'); ?></button> </div> <p id="snake-instructions"> Use <strong>← ↑ ↓ →</strong> to move, <strong>space</strong> to pause. </p> </div> <?php return ob_get_clean(); } add_shortcode( 'snake_game', 'eskim_snake_game_shortcode' ); /** * Rejestruje i ładuje pliki JS oraz CSS potrzebne do działania gry. * Skrypty ładowane tylko, gdy shortcode lub widżet są aktywne. */ function eskim_snake_game_assets() { // Rejestracja skryptu i stylu wp_register_script( 'eskim-snake-js', plugins_url( 'assets/game.js', __FILE__ ), [], '1.0.0', true ); wp_register_style( 'eskim-snake-css', plugins_url( 'assets/style.css', __FILE__ ), [], '1.0.0' ); // Ładowanie tylko na pojedynczych stronach lub gdy aktywny widżet if ( is_singular() || is_active_widget( false, false, 'eskim_snake_widget', true ) ) { wp_enqueue_script( 'eskim-snake-js' ); wp_enqueue_style( 'eskim-snake-css' ); } } add_action( 'wp_enqueue_scripts', 'eskim_snake_game_assets' ); /** * Donate :) */ add_filter( 'plugin_row_meta', 'eskim_snake_plugin_meta_links', 10, 2 ); function eskim_snake_plugin_meta_links( $links, $file ) { if ( strpos( $file, 'snake-retro-game-shortcode-by-eskim.php' ) !== false ) { $links[] = '<a href="https://www.buymeacoffee.com/eskim" target="_blank" rel="noopener">Buy me a coffee ☕</a>'; } return $links; }

Skrypt gry (assets/game.js)

  • Inicjalizuje działanie gry po załadowaniu DOM (DOMContentLoaded).
  • Odczytuje wszystkie ustawienia gry z atrybutów HTML (data-attributes) przekazywanych przez shortcode.
  • Implementuje klasyczną mechanikę gry w węża: ruch segmentów, generowanie jedzenia, obsługę kolizji (ze ścianami i z samym sobą), naliczanie punktów.
  • Dodaje funkcjonalność pauzy (z użyciem spacji) i dynamicznie aktualizuje wynik na stronie.
  • Umożliwia restart gry poprzez przycisk „Start Game”, bez konieczności przeładowania strony.
  • Skrypt jest przemyślany pod kątem minimalizmu — brak zbędnych zależności, czysty Vanilla JS.
/**
 * Snake Game – classic Snake with start button and score counter.
 * Author: by Eskim
 * Version: 1.1
 */
 
 
document.addEventListener('DOMContentLoaded', () => {
    // === Elementy DOM ===
	const container = document.getElementById('snake-game-container');
    const canvas = document.getElementById('snake-game');
    const startButton = document.getElementById('start-snake-game');
    const scoreDisplay = document.getElementById('snake-score');

    // Pobranie prędkości, kolorów i wymiarów z atrybutów
	let speedValue = Math.min(100, Math.max(1, parseInt(container.dataset.speed) || 65));
	const speed = Math.round(mapRange(speedValue, 1, 100, 200, 10));
    const backgroundColor = container.dataset.bgColor || '#000';
	const borderColor = container.dataset.borderColor || '#333';
    const snakeColor = container.dataset.snakeColor || 'lime';
    const foodColor = container.dataset.foodColor || 'red';

    // Jeśli brakuje któregokolwiek elementu – przerywamy działanie
    if (!container || !canvas || !startButton || !scoreDisplay) return;
	canvas.style.borderColor = borderColor;

    // Kontekst rysowania
    const ctx = canvas.getContext('2d');
	
    // === Ustawienia gry ===
    const gridSize = 10; // Rozmiar kratki w pikselach
	
	// Wstępne tło canvasu — przed startem gry
	ctx.fillStyle = backgroundColor;
	ctx.fillRect(0, 0, canvas.width, canvas.height);

    // === Zmienne stanu gry ===
    let snake = [];             // Tablica segmentów węża
    let dx = 0, dy = 0;         // Kierunek ruchu węża
    let food = null;            // Pozycja jedzenia
    let gameInterval = null;    // Uchwyt do interwału gry
    let score = 0;              // Liczba zdobytych punktów
	let isPaused = false;       // stan pauzy

    // === Nasłuchiwanie zdarzeń ===
    startButton.addEventListener('click', startGame);
	document.addEventListener('keydown', (e) => {
		const key = e.key;

		// Pauzowanie/wznawianie gry (działa zawsze)
		if (key === ' ' || key === 'Spacebar' || e.code === 'Space') {
			e.preventDefault();
			togglePause();
			return;
		}

		// Inne klawisze działają tylko jeśli gra NIE jest zapauzowana
		if (!isPaused) {
			changeDirection(e);
		}
	});
	
	/**
	 * Zamienia wartość z jednego zakresu na drugi.
	 * @param {number} value - Wartość wejściowa
	 * @param {number} inMin - Minimalna wartość wejściowa
	 * @param {number} inMax - Maksymalna wartość wejściowa
	 * @param {number} outMin - Minimalna wartość wyjściowa
	 * @param {number} outMax - Maksymalna wartość wyjściowa
	 * @returns {number}
	 */
	function mapRange(value, inMin, inMax, outMin, outMax) {
		return (value - inMin) * (outMax - outMin) / (inMax - inMin) + outMin;
	}

    /**
     * Rozpoczyna nową grę lub restartuje obecną.
     */
    function startGame() {
		isPaused = false;
        startButton.style.display = 'none'; // Ukryj przycisk "Start"

        // Resetuj stan gry
        snake = [{ x: 150, y: 150 }];
        dx = gridSize;
        dy = 0;
        food = spawnFood();
        score = 0;
        updateScore();

        // Wyczyść poprzedni interwał (jeśli istniał) i uruchom grę
        clearInterval(gameInterval);
        gameInterval = setInterval(gameLoop, speed);
    }

    /**
     * Główna pętla gry – porusza węża, sprawdza kolizje i rysuje planszę.
     */
    function gameLoop() {
        // Oblicz nową pozycję głowy
        const head = {
            x: snake[0].x + dx,
            y: snake[0].y + dy
        };

        // Sprawdź kolizje
        if (checkCollision(head)) {
            endGame();
            return;
        }

        // Dodaj nową głowę na początek
        snake.unshift(head);

        // Sprawdź, czy zjedzono jedzenie
        if (head.x === food.x && head.y === food.y) {
            food = spawnFood();
            score++;
            updateScore();
        } else {
            snake.pop(); // Usuń ogon (ruch)
        }

        draw(); // Odśwież planszę
    }

    /**
     * Zatrzymuje grę i pokazuje przycisk startowy ponownie.
     */
    function endGame() {
        clearInterval(gameInterval);
        startButton.style.display = 'block';
    }
	
    /**
     * Pauzuje/wznawia grę.
     */
	function togglePause() {
		if (!snake || snake.length === 0) return;

		isPaused = !isPaused;

		if (isPaused) {
			clearInterval(gameInterval);
			gameInterval = null;
		} else {
			gameInterval = setInterval(gameLoop, speed);
		}

		draw();
	}

    /**
     * Aktualizuje widoczny wynik gry.
     */
    function updateScore() {
        scoreDisplay.textContent = `Score: ${score}`;
    }

    /**
     * Sprawdza, czy wąż uderzył w ścianę lub w siebie.
     * @param {Object} pos - Pozycja głowy węża.
     * @returns {boolean} Czy wystąpiła kolizja.
     */
    function checkCollision(pos) {
        return (
            pos.x < 0 || pos.y < 0 ||
            pos.x >= canvas.width || pos.y >= canvas.height ||
            snake.some(segment => segment.x === pos.x && segment.y === pos.y)
        );
    }

    /**
     * Losuje nową pozycję jedzenia na planszy.
     * @returns {Object} Koordynaty jedzenia.
     */
    function spawnFood() {
        return {
            x: Math.floor(Math.random() * (canvas.width / gridSize)) * gridSize,
            y: Math.floor(Math.random() * (canvas.height / gridSize)) * gridSize
        };
    }

    /**
     * Zmienia kierunek poruszania się węża na podstawie strzałek.
     * @param {KeyboardEvent} e - Zdarzenie klawiatury.
     */
	function changeDirection(e) {
		const allowedKeys = ['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'];

		if (allowedKeys.includes(e.key)) {
			e.preventDefault();
		}

		if (isPaused) return;

		switch (e.key) {
			case 'ArrowUp':
				if (dy === 0) { dx = 0; dy = -gridSize; }
				break;
			case 'ArrowDown':
				if (dy === 0) { dx = 0; dy = gridSize; }
				break;
			case 'ArrowLeft':
				if (dx === 0) { dx = -gridSize; dy = 0; }
				break;
			case 'ArrowRight':
				if (dx === 0) { dx = gridSize; dy = 0; }
				break;
		}
	}

    /**
     * Rysuje tło, węża i jedzenie na planszy.
     */
    function draw() {
        // Tło
        ctx.fillStyle = backgroundColor;
        ctx.fillRect(0, 0, canvas.width, canvas.height);

        // Wąż
        ctx.fillStyle = snakeColor;
        for (let segment of snake) {
            ctx.fillRect(segment.x, segment.y, gridSize, gridSize);
        }

        // Jedzenie
        ctx.fillStyle = foodColor;
        ctx.fillRect(food.x, food.y, gridSize, gridSize);
		
		if (isPaused) {
			ctx.fillStyle = 'rgba(255, 255, 255, 0.8)';
			ctx.font = 'bold 32px monospace';
			ctx.textAlign = 'center';
			ctx.textBaseline = 'middle';
			ctx.fillText('PAUSED', canvas.width / 2, canvas.height / 2);
		}
    }
});

Arkusz stylów (assets/style.css)

  • Definiuje styl kontenera, canvas gry, przycisku startu i instrukcji sterowania.
  • Utrzymuje minimalny, retro wygląd pasujący do gry.
  • Wprowadza prostą responsywność poprzez automatyczne wyśrodkowanie i skalowanie zawartości.
#snake-game-container {
    text-align: center;
    margin: 10px auto 30px auto;
    width: max-content;
}

#snake-game {
    display: block;
    border: 2px solid #333;
    background: #000;
}

#snake-score {
    font-family: monospace;
    font-size: 16px;
    color: #333;
    margin-bottom: 6px;
}

#snake-instructions {
	font-family: monospace;
    font-size: 13px;
    color: #333;
    margin-top: 6px;
}

.snake-canvas-wrapper {
    position: relative;
    display: inline-block;
}

#start-snake-game {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    padding: 10px 20px;
    font-size: 16px;
    background-color: #4CAF50;
    color: white;
    border: none;
    border-radius: 6px;
    cursor: pointer;
    z-index: 10;
	transition: background-color 0.2s ease-in-out;
}

#start-snake-game:hover {
    background-color: #45a049;
}

Dodatkowe pliki i przygotowanie pod WordPress.org

Readme.txt

  • Zawiera wymagane sekcje (== Description ==, == Installation ==, == Frequently Asked Questions ==, == Screenshots ==, == Changelog == itd.).
  • Kluczowe informacje: kompatybilność wtyczki z wersjami WordPressa, instrukcja użycia shortcode, zasady działania.
  • Plik w odpowiednim formacie dla parsera WordPress.org (aby prawidłowo wyświetlał się opis w repozytorium).
=== Snake Retro Game Shortcode by Eskim ===
Contributors: eskimpl
Tags: snake, game, retro, classic, arcade
Requires at least: 5.0
Tested up to: 6.8
Requires PHP: 7.0
Stable tag: 1.1.0
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Donate link: https://buymeacoffee.com/eskim

Classic retro Snake game embedded via shortcode. Built with canvas and pure JavaScript.

== Description ==

Snake Retro Game Shortcode by Eskim adds a classic Snake game to your WordPress site, fully playable directly in the browser.

The game is embedded via the     
Score: 0

Use ← ↑ ↓ → to move, space to pause.

shortcode, and is rendered with HTML5 canvas and JavaScript — no external libraries needed. Features: * Simple shortcode:
Score: 0

Use ← ↑ ↓ → to move, space to pause.

* Fully customizable: colors, size, speed * Adjustable game speed (1 = slowest, 100 = fastest) * Pause/Resume with spacebar * Score counter and "PAUSED" message on canvas * Responsive and lightweight == Installation == 1. Upload the plugin folder to /wp-content/plugins/. 2. Activate the plugin via the "Plugins" menu. 3. Add the
Score: 0

Use ← ↑ ↓ → to move, space to pause.

shortcode to any post or page. Example usage:
Score: 0

Use ← ↑ ↓ → to move, space to pause.

== Shortcode Parameters == You can customize the game using the following shortcode attributes: * background_color – canvas background color (default: #000) * snake_color – snake segment color (default: lime) * food_color – food color (default: red) * border_color – border color of the canvas (default: #333) * width – canvas width in pixels (default: 300) * height – canvas height in pixels (default: 300) * speed – snake speed from 1 (slow) to 100 (fast); internally mapped to a shorter interval in ms (default: 50) == Controls == * Use arrow keys (← ↑ ↓ →) to move the snake. * Press Spacebar to pause/resume the game. * Click "Start Game" to begin or restart. == Screenshots == 1. Snake game displayed with default settings. 2. Game with custom colors and size. 3. Score counter and PAUSED state in action. == Frequently Asked Questions == = Can I change the size and colors? = Yes! Use the shortcode attributes. = Can I use this in a widget area? = No – this version is shortcode-only. = Is it mobile-friendly? = It works on mobile, but is best played with a keyboard. == Changelog == = 1.1.0 = * Removed widget support * Added mapRange logic for better speed control * "PAUSED" label rendered on canvas * Optimized shortcode-only version = 1.0.0 = * Initial release with shortcode and widget support == License == GPL v2 or later == Upgrade Notice == = 1.1.0 = Removed widget support and improved speed control. == Support the Developer == If you enjoy this plugin and want to support its development.

Ikony wtyczki

  • icon-256x256.png – ikona w wyższej rozdzielczości (np. dla wyświetlania na ekranach Retina)
  • icon-128x128.png – podstawowa ikona wyświetlana w listingu wtyczek oraz w panelu WordPressa.

Banery promocyjne

  • banner-772x250.jpg – baner o standardowym rozmiarze do wyświetlania na stronie wtyczki w repozytorium WordPressa (desktop).
  • banner-1544x500.jpg – baner w wyższej rozdzielczości, automatycznie używany przez WordPress na większych ekranach (np. 4K, Retina Displays).

Screenshoty (assets/screenshot-1.png, assets/screenshot-2.png)

  • Zrzuty ekranu przedstawiającr wygląd gry na stronie internetowej WordPress.
  • Obowiązkowy, aby wtyczka w repozytorium wyglądała profesjonalnie i nie odstraszała użytkowników pustym thumbnail’em.

Wersjonowanie

  • Numer wersji (Version: 1.1.0) spójny w nagłówku PHP i plikach assets (ładowanie wersji plików w wp_register_script() oraz wp_register_style()).
  • Umożliwia poprawne zarządzanie aktualizacjami i unikanie problemów z cache’owaniem plików w przeglądarkach użytkowników.

Struktura katalogów

W przypadku publikacji wtyczki w repozytorium WordPress.org, Twoja struktura musi spełniać pewne zasady.
WordPress.org nie używa GitHuba — korzysta z SVN — i oddziela pliki kodu od plików marketingowych (grafik, bannerów).

/
|-- assets/
|    |-- banner-772x250.jpg
|    |-- banner-1544x500.jpg
|    |-- icon-128x128.png
|    |-- icon-256x256.png
|    |-- screenshot-1.png
|
|-- trunk/
|    |-- twoja-wtyczka.php
|    |-- readme.txt
|    |-- assets/
|    |    |-- game.js
|    |    |-- style.css
|    |-- languages/ (opcjonalnie, jeśli masz tłumaczenia)
|    |-- inne_katalogi_i_pliki
|
|-- tags/
|    |-- 1.1.0/
|         |-- (kopiujesz tu wszystko z trunk/ w momencie publikacji wersji)

Pliki marketingowe – katalog /assets/

Tutaj wrzucasz wyłącznie pliki marketingowe:

  • Banery (banner-772x250.jpg, banner-1544x500.jpg)
  • Ikony (icon-128x128.png, icon-256x256.png)
  • Zrzuty ekranu (screenshot-1.png, screenshot-2.png, itd.)

Te pliki nie są pobierane przez użytkownika, tylko używane na stronie WordPress.org do prezentacji Twojej wtyczki.

Nie wrzucaj plików JS, CSS, ani kodu PHP do /assets/!

Aktualna wersja wtyczki – katalog /trunk/

To jest główna wersja rozwojowa Twojej wtyczki. Tutaj wrzucasz cały kod źródłowy:

  • Plik główny PHP (your-plugin-name.php).
  • readme.txt.
  • Własne foldery na assety (assets/ z grą JS i stylem CSS).
  • languages/, jeśli dodajesz tłumaczenia (.pot, .po, .mo).

Użytkownicy, instalując Twoją wtyczkę, ściągają właśnie pliki z trunk.

Wydania – katalog /tags/

To katalog, w którym robisz snapshoty Twoich wydań.

Gdy np. wypuszczasz wersję 1.1.0, robisz kopię całej zawartości /trunk/ do /tags/1.1.0/. Dzięki temu WordPress.org wie, jakie pliki były w konkretnej wersji. Każda kolejna wersja (1.2.0, 1.3.0 itd.) dostaje swój osobny katalog.

SVN działa na zasadzie commitów i tagowania – nie nadpisuj katalogu /tags/1.1.0 po jego wypuszczeniu. Jeśli chcesz poprawić błąd – wypuszczasz nową wersję (1.1.1).

Opis wtyczki, czyli szerzej o pliku readme.txt

Jeżeli chcesz opublikować swoją wtyczkę w oficjalnym repozytorium WordPress.org, jednym z wymaganych plików jest readme.txt.
To nie jest zwykły opis – to instrukcja, która decyduje o tym, jak Twoja wtyczka będzie wyglądać w repozytorium i czy użytkownicy będą mogli łatwo ją znaleźć i zrozumieć.

WordPress.org ma swoje własne zasady formatowania readme.txt. Plik ten musi zawierać określone sekcje.

Nagłówek wtyczki (=== Nazwa wtyczki ===)

Na samej górze pliku musi się znaleźć kilka podstawowych informacji.

=== Nazwa wtyczki ===
Contributors: eskimpl
Donate link: https://buymeacoffee.com/eskim
Tags: snake, game, shortcode, retro
Requires at least: 5.0
Tested up to: 6.5.2
Requires PHP: 7.0
Stable tag: 1.1.0
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Co oznaczają poszczególne linie:

  • Contributors – Twoja nazwa użytkownika WordPress.org (nie e-mail!).
  • Donate link – link do darowizn (opcjonalne, ale przydatne).
  • Tags – maksymalnie 12 tagów opisujących wtyczkę, pomagają w wyszukiwarce.
  • Requires at least – minimalna wersja WordPressa.
  • Tested up to – najwyższa przetestowana wersja WordPressa.
  • Requires PHP – minimalna wersja PHP.
  • Stable tag – wersja wtyczki, którą WordPress traktuje jako „stabilną”.
  • License / License URI – wtyczki MUSZĄ być na GPL lub zgodnej licencji.

Opis (== Description ==)

To pierwszy dłuższy tekst, który użytkownik zobaczy. Powinieneś tu jasno i zwięźle opisać, co robi wtyczka i dlaczego warto jej użyć.

== Description ==
Classic Snake Game – a fully playable retro snake game you can embed anywhere on your WordPress site using a simple shortcode.
Customize speed, colors, and canvas size directly via shortcode parameters.

Pierwsze 150 znaków jest używane jako snippet np. w wynikach wyszukiwania WordPress.org – dobrze, żeby były konkretne.

Instalacja (== Installation ==)

Instrukcja krok po kroku, jak zainstalować i skonfigurować wtyczkę.

== Installation ==
1. Upload the plugin files to the `/wp-content/plugins/your-plugin-name` directory, or install the plugin through the WordPress plugins screen directly.
2. Activate the plugin through the 'Plugins' screen in WordPress.
3. Use the shortcode     
Score: 0

Use ← ↑ ↓ → to move, space to pause.

in a post or page to display the game.

Nawet jeśli instalacja jest banalna, napisz ją – WordPress tego wymaga.

FAQ (== Frequently Asked Questions ==)

Odpowiedzi na najczęstsze pytania użytkowników. Nawet jedna-dwie odpowiedzi robią różnicę.

== Frequently Asked Questions ==
= How do I start the game? =
Click the "Start Game" button displayed over the canvas.

= Can I customize the speed and colors? =
Yes, use shortcode attributes like     
Score: 0

Use ← ↑ ↓ → to move, space to pause.

.

Zrzuty ekranu (== Screenshots ==)

Opis obrazków, które wrzuciłeś do /assets/

== Screenshots ==
1. Snake Game running on a post.
2. Start screen and instructions for the game.

Zrzuty muszą się nazywać screenshot-1.png, screenshot-2.png, itd. w katalogu /assets/ Twojego repozytorium SVN.

Changelog (== Changelog ==)

Historia zmian – nawet przy pierwszej wersji musisz mieć jakąś sekcję changeloga.

== Changelog ==
= 1.1.0 =
* Initial public release.
* Added start button, pause feature, and responsive canvas.

Każda wersja musi mieć oddzielny wpis. Późniejsze aktualizacje powinny trafiać właśnie tutaj.

Upgrade Notice (== Upgrade Notice ==)

Krótki komunikat dla użytkowników WordPressa, dlaczego powinni zaktualizować do nowej wersji.

== Upgrade Notice ==
= 1.1.1 =
Recommended update – fixes compatibility with WordPress 6.5.

Nieobowiązkowe, ale przy większych zmianach przydatne.

Sprawdzenie kodu wtyczki

Przed wysłaniem musisz upewnić się, że:

  • wtyczka jest zabezpieczona (if ( ! defined( 'ABSPATH' ) ) exit; na początku pliku PHP)
  • wszystkie funkcje mają prefiks (np. eskim_) – nie może być „gołych” funkcji globalnych
  • żadnych błędów PHP
  • wszystkie dane wyjściowe są poprawnie escapowane (esc_html_e, esc_attr, itp.)
  • shortcode’y i hooki są rejestrowane poprawnie (add_shortcode(), add_action())
  • assety (JS, CSS) są ładowane tylko tam, gdzie są potrzebne (is_singular(), itp.)

Plugin Checkoficjalna wtyczka WordPress.org do sprawdzania:

  • bezpieczeństwa kodu,
  • zgodności ze standardami publikacji,
  • typowych błędów, które odrzuciłyby Twój plugin na review.

Co sprawdza Plugin Check:

  • Czy masz odpowiednią licencję GPL,
  • Czy zabezpieczyłeś wtyczkę przed bezpośrednim dostępem (ABSPATH check),
  • Czy funkcje są prefiksowane (np. nie ma globalnych kolizji),
  • Czy readme.txt jest obecny i poprawny,
  • Czy nie ma niedozwolonych funkcji (eval(), base64_decode(), itp.),
  • Czy assety są poprawnie ładowane (wp_enqueue_script zamiast „na pałę” w <script>).

Plugin Check nie sprawdza poprawności działania skryptu, logiki JavaScript itd. — to narzędzie czysto pod standardy WordPress.org.

Można ją zainstalować jak każdą inną wtyczkę, albo użyć udostępnionego środowiska na którym zainstalujemy i sprawdzimy wtyczkę tym pluginem – przycisk podczas dodawania wtyczki do repozytorium.

Jeśli po sprawdzeniu masz 0 błędów i ewentualnie kilka nieistotnych ostrzeżeń — jesteś gotowy na zgłoszenie.

Sprawdzenie pliku readme.txt

Musisz upewnić się, że:

  • plik ma wszystkie wymagane sekcje (== Description ==, == Installation ==, == Changelog ==, itd.),
  • wersje są spójne: numer wersji w pliku PHP (Version:)
  • plik nie zawiera błędów formatowania.

Readme validator – dedykowane narzędzie

Proste narzędzie w którym wklejasz zawartość pliku readme.txt, klikasz validate i sprawdzasz czy wszystko jest co ma być.

Ostrzeżeniami nie musisz się przejmować, ale lepiej dodać wymagane sekcje. Ostrzeniami – nie błędami – te trzeba poprawić.

Zgłoszenie wtyczki do WordPress.org

Jeżeli już przygotowałeś wszystko – przetestowałeś wtyczkę i masz właściwą strukturę katalogów to pakujesz wtyczkę do .zip i wysyłasz do sprawdzenia (wcześniej trzeba się zalogować / założyć konto)

Pamiętaj, że w pliku readme.txt musisz podać w Contributors taką samą nazwę użytkownika jak ta do konta.

Nie wrzucasz całego katalogu SVN, tylko samą paczkę .zip zawierającą pliki /trunk/! Tak, aby można było zainstalować wtyczkę.

Formularz zgłoszenia

  • Plugin Name – pełna nazwa wtyczki (taka jak w pliku PHP i readme.txt).
  • Plugin Slug – sugerowany identyfikator URL (np. snake-retro-game-shortcode-by-eskim).
  • Plugin URL – Twój Plugin URI (opcjonalnie).
  • Short Description – jednozdaniowe streszczenie funkcji wtyczki.
  • Full Plugin Zip File – ZAŁĄCZ plik .zip Twojej wtyczki (tylko kod, nie /assets/).

Co się dzieje po zgłoszeniu?

  • Zgłoszenie trafia do kolejki review
  • Review może trwać od 1 do 7 dni roboczych (czasem szybciej, czasem wolniej).
  • Recenzent sprawdza Twoją wtyczkę pod kątem bezpieczeństwa, zgodności z zasadami WordPress.org, poprawności readme.txt

Jeśli coś jest nie tak:

  • dostajesz e-maila z uwagami,
  • poprawiasz i odpisujesz na wiadomość

Jeśli wszystko OK

  • otrzymujesz e-mail z przyznaniem dostępu do repozytorium SVN.

Wrzucenie do repozytorium SVN

Jeśli dostałeś zielone światło, w mailu otrzymasz dostęp do repozytorium SVN.

Ja skorzystałem z TortoiseSVN. W środowisku Windows wystarczy zainstalować. Programu nie uruchamiasz. Zamiast tego tworzysz pusty katalog w którym będziesz trzymał swoją wtyczkę, wchodzisz do niego i klikasz prawym przyciskiem checkout. W górnym okienku podajesz link do repozytorium, który dostałeś na maila. Może być konieczność zalogowania się – login i hasło takie jak ustawiłeś do wordpress.org.

Po tej operacji pobierze repozytorium na dysk. Wypełniasz katalogi odpowiednimi plikami, czyli do

  • trunk wrzucasz aktualną wtyczkę, razem z plikiem readme.txt itd.
  • assets wrzucasz banery, ikony i screenshoty
  • do tags wrzucasz aktualną wersję wtyczki i wszystkie jej modyfikacje (w osobnym katalogu, którego nazwą jest wersja wtyczki) na teraz możesz skopiować zawartość trunk np. do katalogu tags/1.0/ (skopiować! nie przenieść!)

Po prawidłowym wrzuceniu plików klikamy ponownie prawym przyciskiem myszy w katalogu z wtyczką i wybieramy commit. To spowoduje wrzucenie zmodyfikowanej wtyczki na serwer (zmodyfikowana, bo dodaliśmy pliki). Przy każdym „commicie” musimy wpisać co się zmieniło – za pierwszym razem może to być po prostu Initial release, albo coś w ten deseń.. ale coś trzeba wpisać. Musimy jeszcze zaznaczyć pliki, które chcemy dodać (lista na dole).

Linki