LW IT Solutions logo LW IT Solutions logo LW IT Solutions
« Przegląd bloga /Wtyczki i triki WordPress / Katalog wtyczek WordPress.org: za co odrzucane są...
Ten artykuł w innych językach:

Katalog wtyczek WordPress.org: za co odrzucane są zgłoszenia

Katalog wtyczek WordPress.org: za co odrzucane są zgłoszenia

Management Summary

Katalog WordPress.org ocenia więcej niż samo działanie wtyczki, czyli rozszerzenia funkcji witryny. Znaczenie mają także licencje, rzetelne opisy, płatne oferty i przesyłanie danych na zewnątrz. Jasny wybór dotyczący statystyk oraz linku do twórcy pomaga zachować kontrolę nad stroną. Przegląd wyjaśnia, dlaczego ukryte wysyłanie danych lub płatna blokada funkcji zawartej w pakiecie może prowadzić do odrzucenia oraz dlaczego automatyczny test nie zastępuje oceny zespołu katalogu.

Spis treści
  1. Przegląd 18 zasad
  2. Licencja i czytelny kod
  3. Co pozostaje bezpłatne, a co może być płatne
  4. Jasna decyzja przed zapytaniem zewnętrznym
  5. Przykład: czas czytania, statystyki i link do twórcy
  6. Opis przesyłania w readme
  7. Nazwa i stały adres
  8. Od zgłoszenia do publikacji
  9. Czego te kontrole nie potwierdzają
  10. Pytania i odpowiedzi
  11. Źródła

Działająca wtyczka może mimo to nie przejść oceny przed przyjęciem do katalogu WordPress.org. Zespół sprawdza nie tylko kod, lecz także licencję, przesyłanie danych na zewnątrz i nazwę. Ukryte zbieranie statystyk lub płatna blokada funkcji zawartej w pakiecie mogą być równie istotne jak błąd programu.

Sprawdzono 25 października 2026 r. Detailed Plugin Guidelines zawierają 18 zasad. Poniższy przegląd wyjaśnia znaczenie tych zasad dla gotowej wtyczki. Przykład rozdziela dwie decyzje: zgodę na wysłanie statystyk i wyświetlanie linku do strony twórcy. Obie opcje są początkowo wyłączone.

Plugin Check, funkcje bezpieczeństwa oraz readme i nagłówki wtyczek mają osobne artykuły. Przykłady gotowych wtyczek to Lite Page Cache i WP Admin Captcha.

Przegląd 18 zasad

Numery odpowiadają oficjalnym wytycznym. Grupy łączą podobne tematy; kolejność nie jest rankingiem powodów odrzucenia.

TematZasadyPraktyczne znaczenie
Licencja i źródła1, 4, 13Każdy plik wymaga odpowiedniej licencji. Czytelne źródła muszą być dostępne. Bibliotek dostarczanych przez WordPress nie należy dołączać ponownie.
Płatne oferty5, 6, 8Funkcji zawartych w pakiecie nie można odblokowywać za opłatą. Udokumentowane usługi są dozwolone; zewnętrzny kod podlega ograniczeniom.
Zgoda i interfejs7, 10, 11Połączenia zewnętrzne wymagają wyjaśnienia i upoważnienia. Link do twórcy jest dobrowolny. Reklamy nie mogą przejmować panelu administracyjnego.
Publikacja i postępowanie2, 3, 9, 12, 14–18Kompletne, aktualne pakiety, uczciwe opisy, odpowiednie nazwy i numery wersji; bez spamu w opisach i niepotrzebnych zmian w SVN.

Odpowiedzialność obejmuje dołączone biblioteki i warunki usług zewnętrznych. Zespół może zmieniać zasady, dopuszczać wyjątki albo usunąć wtyczkę. Przegląd nie zastępuje więc aktualnej strony wytycznych.

Licencja i czytelny kod

Zgodność z GPL oznacza zgodność licencji z GNU General Public License. WordPress zaleca „GPLv2 or later”. Wymóg obejmuje nie tylko własny kod PHP, lecz także dołączone obrazy, dane i biblioteki. Sprzeczne deklaracje w nagłówku wtyczki i readme wymagają wyjaśnienia przed zgłoszeniem.

Pliki zminifikowane to pliki programu zmniejszone na potrzeby dystrybucji. Czytelny kod źródłowy i narzędzia budowania muszą być publicznie dostępne w pakiecie albo pod linkiem w readme. W projektach Composer plik composer.json pomaga opisać sposób budowania. WordPress dostarcza już biblioteki takie jak jQuery i PHPMailer; wtyczka powinna korzystać z tych kopii. Zbędne katalogi testowe, demonstracyjne i robocze nie należą do pakietu publikowanej wersji.

Co pozostaje bezpłatne, a co może być płatne

Wtyczka z katalogu nie może odblokowywać zawartych funkcji dopiero po zapłacie ani wyłączać tych funkcji po okresie próbnym. Tego dotyczy zakaz trialware. Płatna usługa zewnętrzna jest dozwolona, jeśli wykonuje rzeczywistą pracę i zależność została jasno opisana w readme. Samo sprawdzanie klucza licencji dla funkcji wykonywanych w całości lokalnie nie wystarcza.

Zasada 5 dopuszcza również osobną płatną wtyczkę dodatkową poza WordPress.org. Kod premium pozostaje wtedy poza bezpłatnym pakietem. Wtyczka z katalogu nie może sama pobrać i zainstalować własnej wersji premium. Dzięki temu bezpłatna funkcja, usługa zewnętrzna i dodatkowy produkt pozostają rozróżnialne.

Zasada 8 nie zakazuje każdego zewnętrznego kodu. Kod z udokumentowanych usług jest dozwolony przy spełnieniu opisanych warunków bezpieczeństwa. Bez związku z taką usługą JavaScript i CSS powinny znajdować się w lokalnym pakiecie. Ograniczenia dotyczą obcych źródeł aktualizacji, instalowania wersji premium i osadzania zewnętrznych paneli administracyjnych w iframe. Zasada dopuszcza też usługi zarządzania, które rozsyłają oprogramowanie przez własną domenę, a nie wewnątrz kokpitu WordPressa.

Komunikat o płatnym rozszerzeniu może pasować do aktualnej czynności albo znajdować się na stronie ustawień wtyczki. Komunikaty obejmujące cały panel muszą dawać się zamknąć. Wtyczka nie może udawać funkcji ani sugerować, że funkcje już zawarte w pakiecie wymagają dodatkowej zapłaty.

Jasna decyzja przed zapytaniem zewnętrznym

Opt-in oznacza aktywny wybór, na przykład zaznaczenie początkowo pustego pola. Zasada 7 wymaga wyraźnej, uprawnionej zgody na połączenia zewnętrzne oraz opisu wykorzystania danych. Wyjątek dla usług dotyczy rozpoznawalnego celu skonfigurowanej usługi: instalacja, aktywacja, rejestracja i konfiguracja mogą według zasad katalogu wyrażać potrzebną zgodę. Nie pozwala to na dowolne dodatkowe statystyki ani nie stanowi ogólnego potwierdzenia prawnej dopuszczalności każdej operacji na danych.

Link do twórcy na publicznej stronie jest osobną decyzją. Zasada 10 wymaga początkowego wyłączenia linku i zakazuje uzależniania działania wtyczki od wyświetlanego podpisu. Ukryte zdanie w warunkach korzystania nie zastępuje tego wyboru.

Przykład: czas czytania, statystyki i link do twórcy

Przykład oblicza czas czytania lokalnie, przyjmując w przybliżeniu 200 słów rozdzielonych białymi znakami na minutę. Oszacowanie nie pasuje jednakowo do każdego języka i zawsze pokazuje co najmniej minutę. Dwa niezależne ustawienia pozwalają na statystyki i link do twórcy.

Zapis ustawienia statystyk jeszcze niczego nie wysyła. Dopiero osobny przycisk „Send statistics once” uruchamia jedną próbę. Zapisana zgoda, uprawnienie manage_options i kontrola formularza muszą nadal być ważne. Znacznik nonce utrudnia wywołanie żądania z obcej strony; osobna kontrola uprawnień decyduje, czy konto może wykonać operację.

stats.example.com to adres zastępczy. Rzeczywiste użycie wymaga działającej usługi i zgodnych z rzeczywistością informacji o danych. Kod demonstracyjny pozostaje poza witryną produkcyjną.

PHP
<?php
/**
 * Plugin Name:       Reading Time Badge
 * Description:       Shows the estimated reading time above posts. Usage statistics and a credit link are opt-in.
 * Version:           1.0.0
 * Requires at least: 6.5
 * Requires PHP:      7.4
 * License:           GPLv2 or later
 * License URI:       https://www.gnu.org/licenses/gpl-2.0.html
 * Text Domain:       reading-time-badge
 *
 * @package ReadingTimeBadge
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

define( 'RTBADGE_VERSION', '1.0.0' );
define( 'RTBADGE_STATS_URL', 'https://stats.example.com/v1/ping' );

/**
 * Returns the settings merged with defaults. Every outgoing feature is off by default.
 *
 * @return array
 */
function rtbadge_get_settings() {
	$defaults = array(
		'share_stats' => false,
		'show_credit' => false,
	);
	return wp_parse_args( (array) get_option( 'rtbadge_settings', array() ), $defaults );
}

/**
 * Stores exactly two booleans, whatever the form sends.
 *
 * @param mixed $input Raw option value.
 * @return array
 */
function rtbadge_sanitize_settings( $input ) {
	$input = is_array( $input ) ? $input : array();
	return array(
		'share_stats' => isset( $input['share_stats'] ) && in_array( $input['share_stats'], array( true, '1' ), true ),
		'show_credit' => isset( $input['show_credit'] ) && in_array( $input['show_credit'], array( true, '1' ), true ),
	);
}

add_action( 'admin_init', 'rtbadge_register_settings' );

/**
 * Registers the option with a sanitize callback.
 */
function rtbadge_register_settings() {
	register_setting(
		'rtbadge',
		'rtbadge_settings',
		array(
			'type'              => 'array',
			'sanitize_callback' => 'rtbadge_sanitize_settings',
			'default'           => array(
				'share_stats' => false,
				'show_credit' => false,
			),
		)
	);
}

add_action( 'admin_menu', 'rtbadge_add_settings_page' );

/**
 * Adds the settings page below Settings.
 */
function rtbadge_add_settings_page() {
	add_options_page(
		__( 'Reading Time Badge', 'reading-time-badge' ),
		__( 'Reading Time Badge', 'reading-time-badge' ),
		'manage_options',
		'rtbadge',
		'rtbadge_render_settings_page'
	);
}

/**
 * Renders two unchecked-by-default opt-in checkboxes.
 */
function rtbadge_render_settings_page() {
	if ( ! current_user_can( 'manage_options' ) ) {
		return;
	}
	$settings = rtbadge_get_settings();
	?>
	<div class="wrap">
		<h1><?php echo esc_html( get_admin_page_title() ); ?></h1>
		<form action="options.php" method="post">
			<?php settings_fields( 'rtbadge' ); ?>
			<p>
				<label>
					<input type="checkbox" name="rtbadge_settings[share_stats]" value="1" <?php checked( $settings['share_stats'] ); ?>>
					<?php esc_html_e( 'Allow sending plugin, WordPress and PHP versions to stats.example.com with the separate Send statistics button.', 'reading-time-badge' ); ?>
				</label>
			</p>
			<p>
				<label>
					<input type="checkbox" name="rtbadge_settings[show_credit]" value="1" <?php checked( $settings['show_credit'] ); ?>>
					<?php esc_html_e( 'Show a link to the plugin website next to the reading time on the public site.', 'reading-time-badge' ); ?>
				</label>
			</p>
			<?php submit_button(); ?>
		</form>
		<form action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="post">
			<input type="hidden" name="action" value="rtbadge_send_stats">
			<?php wp_nonce_field( 'rtbadge_send_stats' ); ?>
			<?php submit_button( __( 'Send statistics once', 'reading-time-badge' ), 'secondary' ); ?>
		</form>
	</div>
	<?php
}

add_action( 'admin_post_rtbadge_send_stats', 'rtbadge_send_stats' );

/**
 * Sends one request after a deliberate action by an authorized administrator.
 */
function rtbadge_send_stats() {
	if ( ! isset( $_SERVER['REQUEST_METHOD'] ) || 'POST' !== $_SERVER['REQUEST_METHOD'] ) {
		wp_die( esc_html__( 'POST is required.', 'reading-time-badge' ) );
	}
	if ( ! current_user_can( 'manage_options' ) ) {
		wp_die( esc_html__( 'Permission denied.', 'reading-time-badge' ) );
	}
	check_admin_referer( 'rtbadge_send_stats' );
	$settings = rtbadge_get_settings();
	if ( true !== $settings['share_stats'] ) {
		wp_die( esc_html__( 'Statistics sharing is disabled. Save the setting before sending.', 'reading-time-badge' ) );
	}
	$response = wp_safe_remote_post(
		RTBADGE_STATS_URL,
		array(
			'timeout'     => 5,
			'redirection' => 0,
			'user-agent'  => 'reading-time-badge/' . RTBADGE_VERSION,
			'body'        => array(
				'plugin_version' => RTBADGE_VERSION,
				'wp_version'     => get_bloginfo( 'version' ),
				'php_version'    => PHP_VERSION,
			),
		)
	);
	if ( is_wp_error( $response ) ) {
		wp_die( esc_html__( 'The request failed. No automatic retry is scheduled.', 'reading-time-badge' ) );
	}
	$status = wp_remote_retrieve_response_code( $response );
	if ( $status < 200 || $status >= 300 ) {
		wp_die( esc_html__( 'The service did not return a successful HTTP response.', 'reading-time-badge' ) );
	}
	wp_die( esc_html__( 'The service returned a successful HTTP response. This does not verify storage.', 'reading-time-badge' ) );
}

add_filter( 'the_content', 'rtbadge_prepend_reading_time' );

/**
 * Prepends the reading time. The credit link appears only after opt-in.
 *
 * @param string $content Post content.
 * @return string
 */
function rtbadge_prepend_reading_time( $content ) {
	if ( ! is_singular( 'post' ) || ! in_the_loop() || ! is_main_query() ) {
		return $content;
	}
	$words   = preg_split( '/\s+/u', trim( wp_strip_all_tags( $content ) ), -1, PREG_SPLIT_NO_EMPTY );
	if ( false === $words ) {
		return $content;
	}
	$minutes = max( 1, (int) ceil( count( $words ) / 200 ) ); // Assumes 200 words per minute.

	$badge = '<p class="rtbadge">' . esc_html(
		sprintf(
			/* translators: %d: estimated reading time in minutes */
			_n( '%d minute read', '%d minutes read', $minutes, 'reading-time-badge' ),
			$minutes
		)
	);

	$settings = rtbadge_get_settings();
	if ( true === $settings['show_credit'] ) {
		$badge .= ' &middot; <a href="' . esc_url( 'https://example.com/reading-time-badge/' ) . '">'
			. esc_html__( 'Reading Time Badge', 'reading-time-badge' ) . '</a>';
	}

	return $badge . '</p>' . $content;
}

Żądanie zawiera trzy pola z wersjami oprogramowania. Własny User-Agent zastępuje domyślną identyfikację HTTP API WordPressa, która zawiera również adres witryny. Odbiorca nadal widzi źródłowy adres IP serwera. Przekierowania są wyłączone. Odpowiedź HTTP z zakresu 200–299 potwierdza prawidłową odpowiedź serwera, a nie zapis danych. Kolejne kliknięcie może wywołać następną próbę. Przykład nie zawiera automatycznych powtórzeń ani tygodniowej blokady.

Formularze mają oddzielne zadania: zapis zmian przechowuje wybór, a drugi przycisk wysyła raz. Usunięcie zaznaczenia także wymaga zapisania przed zablokowaniem kolejnych wysyłek. Strona potwierdzenia jest celowo prosta; gotowa wtyczka może zamiast tego pokazać odpowiedni komunikat na stronie ustawień.

Opis przesyłania w readme

Dokumentacja podaje cel, moment wywołania, dane i odbiorcę. Linki do usługi, warunków i informacji o prywatności muszą w gotowej wtyczce prowadzić do rzeczywistych stron. Poniższy angielski fragment jest wzorem dla tego samego ręcznego działania:

Tekst
== Privacy and external services ==

Reading Time Badge calculates reading time locally and works without an external service.
Statistics sharing and the public credit link are disabled by default.

Saving the statistics opt-in does not send a request. After that setting is saved,
an administrator can press "Send statistics once" to send one request to
https://stats.example.com/v1/ping. Each additional click can send another request.
Clearing the opt-in and saving the setting prevents further sends by this feature.

The example request body contains plugin, WordPress and PHP versions.
The example does not add site content or the site URL to that body or its custom user agent.
The receiving service can see the server's source IP address.
No automatic retry or weekly schedule is implemented.

The example addresses below are placeholders and must be replaced with actual service details.
* Service: https://stats.example.com/
* Terms of use: https://stats.example.com/terms/
* Privacy policy: https://stats.example.com/privacy/

Nazwa i stały adres

Slug to krótka nazwa w adresie, na przykład wordpress.org/plugins/reading-time-badge. Tę wartość wykorzystują również katalog wtyczki, adres SVN i domena tekstowa tłumaczeń. Początkowa propozycja pochodzi z Plugin Name w nagłówku głównego pliku.

Oficjalne strony różnie opisują konflikt nazw: strona zgłoszeń podaje dopisanie liczby, a FAQ ostrzeżenie przy przesyłaniu. Znaczenie ma więc faktycznie potwierdzony slug. Oryginalna nazwa pozwala uniknąć polegania na automatycznym numerowaniu.

Strona zgłoszeń dopuszcza jedną samodzielną zmianę sluga przed rozpoczęciem przeglądu. Podczas przeglądu zmiana jest uzgadniana w dotychczasowym wątku e-mail. Przed zatwierdzeniem zespół może jeszcze zmienić slug; po zatwierdzeniu zmiana nie jest dostępna. Wyświetlana nazwa wtyczki może później ulec zmianie.

Cudza marka nie może być jedynym ani pierwszym członem sluga bez potwierdzonego prawa własności lub upoważnienia. „Delivery Dates for WooCommerce” pokazuje funkcję z dopisaną marką; „WooCommerce Delivery Dates” może sugerować oficjalne pochodzenie. Pierwszy wzorzec również nie oznacza automatycznej zgody prawnej na każde konkretne wykorzystanie nazwy.

PHP
<?php
/**
 * Plugin Name: Delivery Dates for WooCommerce
 * Description: Lets customers pick a delivery date at checkout.
 * Version:     1.0.0
 * License:     GPLv2 or later
 * Text Domain: delivery-dates-for-woocommerce
 *
 * @package DeliveryDatesForWooCommerce
 */

// Main file: delivery-dates-for-woocommerce/delivery-dates-for-woocommerce.php
// Slug proposed on submission: delivery-dates-for-woocommerce

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

Od zgłoszenia do publikacji

ZIP musi dawać się zainstalować jako wtyczka. FAQ wskazuje limit 10 MB; zbędne pliki robocze zwiększają rozmiar pakietu. Od października 2024 r. konta z prawem zgłoszenia lub commita wymagają uwierzytelniania dwuskładnikowego, czyli dodatkowego potwierdzenia logowania poza hasłem. Dla SVN dostępne jest osobne hasło.

Ogłoszenie z 1 października 2024 r. opisuje Plugin Check jako kontrolę wstępną: błędy w kategorii „Plugin Repo” blokują zgłoszenie. To udokumentowany punkt wyjścia; aktualne kontrole mogą być rozwijane. Poprawny wynik automatyczny nie zastępuje późniejszej oceny zespołu.

Uwagi są wyjaśniane w tym samym wątku e-mail. Po odrzuceniu z powodu przeglądu niezakończonego po trzech miesiącach FAQ przewiduje ponowne zgłoszenie i odpowiedź na starą wiadomość. Przy innych powodach odrzucenia potrzebna jest rozmowa w istniejącym wątku, a nie nowe zgłoszenie.

Zatwierdzenie zapewnia dostęp do SVN. SVN przechowuje tutaj wersje gotowe do publikacji, a nie każdy etap pracy. trunk/ zawiera bieżący kod, tags/ nazwane wersje, a assets/ obrazy katalogu. Commit przesyła zmiany do repozytorium i może uruchomić publikację.

Osobnym etapem jest dystrybucja przez API aktualizacji. Ogłoszenie z 9 września 2026 r. podaje sześć godzin oczekiwania i automatyczną kontrolę bezpieczeństwa. Wysoki wynik ryzyka może zablokować wydanie. Ta dystrybucja nie jest tym samym co samo zapisanie plików w SVN.

Od ZIP-a wtyczki do publikacji
Zgłoszenie, przegląd i publikacja to oddzielne etapy. Sześciogodzinne oczekiwanie na dystrybucję aktualizacji opisano we wrześniu 2026 r.

Czego te kontrole nie potwierdzają

Historyczna liczba zgłoszeń w kolejce opisuje stan, a nie czas oczekiwania konkretnej wtyczki. Mała liczba nowych zgłoszeń nie gwarantuje szybkiej decyzji. Strona zgłoszeń podaje cel pięciu dni roboczych i zakres od jednego do dziesięciu dni zależnie od złożoności. Nie jest to zobowiązanie do dotrzymania terminu.

Przykład sprawdzono w izolacji pod kątem uprawnień, zgody, błędów wysyłki i wyświetlania. Takie testy nie zastępują pełnego uruchomienia w WordPressie, Plugin Check ani decyzji zespołu katalogu.

Pytania i odpowiedzi

Czy bezpłatna wtyczka może reklamować ofertę Pro?

Tak, w opisanych granicach zasad 5, 8 i 11. Funkcje zawarte w bezpłatnym pakiecie pozostają dostępne. Osobny dodatek albo rzeczywista usługa zewnętrzna mogą być płatne.

Czy wystarczy poprawny wynik Plugin Check?

Nie. Taki wynik nie rozstrzyga ostatecznie licencji, celu usługi, prezentacji i praw do nazwy. Ocena zespołu pozostaje konieczna.

Czy brak błędu wysyłki dowodzi zapisu danych?

Nie. Nawet poprawna odpowiedź HTTP nie dowodzi trwałego zapisania danych przez odbiorcę. Bez zgody albo poprawnej kontroli formularza i uprawnień przykład nie wysyła żądania.

Ile wtyczek może jednocześnie czekać na ocenę?

FAQ zwykle dopuszcza jedno zgłoszenie. Dla autorów z ponad milionem aktywnych instalacji wtyczek obowiązuje wyższy limit, do dziesięciu. Dodatkowe konta nie mogą służyć obchodzeniu ograniczenia.

Lukas Wójcik

Lukas Wójcik

Systems architect and technology enthusiast specializing in scalable tracking solutions, GMP Stack (GA4 & GTM), and robust backend architectures. Advocate for clean code and privacy-first design.

Kontakt

Masz pytanie lub pomysł na projekt internetowy? Napisz krótko, o co chodzi. Formularz korzysta z reCAPTCHA do ochrony przed spamem.

Napisanie komentarza

Doświadczenia z innymi wtyczkami lub środowiskami hostingowymi oraz pytania o konfigurację są tu mile widziane.

Adres e-mail nie jest publikowany. Pola obowiązkowe oznaczono gwiazdką.