{"id":20877,"date":"2026-10-12T20:48:00","date_gmt":"2026-10-12T18:48:00","guid":{"rendered":"https:\/\/www.lukaswojcik.com\/blog\/?p=20877"},"modified":"2026-10-09T22:46:44","modified_gmt":"2026-10-09T20:46:44","slug":"cykl-zycia-wtyczki-odinstalowanie","status":"publish","type":"post","link":"https:\/\/www.lukaswojcik.com\/blog\/pl\/wordpress-plugins-tricks-pl\/cykl-zycia-wtyczki-odinstalowanie\/","title":{"rendered":"Cykl \u017cycia wtyczki: aktywacja, dezaktywacja, odinstalowanie"},"content":{"rendered":"<p>Wiele wtyczek zostawia \u015blady d\u0142ugo po tym, jak przesta\u0142y robi\u0107 cokolwiek po\u017cytecznego: tabel\u0119, kt\u00f3rej nikt ju\u017c nie czyta, zdarzenia cron bez callbacka, kt\u00f3ry m\u00f3g\u0142by je obs\u0142u\u017cy\u0107, czy uprawnienie (capability) przy roli administratora, kt\u00f3re nie reguluje ju\u017c dost\u0119pu do \u017cadnego ekranu. WordPress udost\u0119pnia trzy osobne punkty wej\u015bcia dla aktywacji, dezaktywacji i odinstalowania. Warto zna\u0107 ich mniej oczywiste zachowania: hook aktywacji nie uruchamia si\u0119 przy aktualizacjach, aktywacja sieciowa w Multisite wywo\u0142uje go dok\u0142adnie raz zamiast raz na ka\u017cd\u0105 witryn\u0119, a procedura odinstalowania zarejestrowana jako closure ko\u0144czy si\u0119 b\u0142\u0119dem krytycznym.<\/p>\n<p>Artyku\u0142 prowadzi ma\u0142\u0105, ale kompletn\u0105 wtyczk\u0119 przez wszystkie trzy fazy. Wtyczka zak\u0142ada w\u0142asn\u0105 tabel\u0119 za pomoc\u0105 <code>dbDelta()<\/code>, zapisuje wersj\u0119 schematu i migruje dane przy aktualizacjach, planuje codzienne zdarzenie cron, nadaje administratorom w\u0142asn\u0105 capability i usuwa to wszystko przez plik <code>uninstall.php<\/code>, kt\u00f3ry kasuje dane wy\u0142\u0105cznie po wyra\u017anej zgodzie. Ka\u017cde stwierdzenie o zachowaniu rdzenia zosta\u0142o sprawdzone w podr\u0119czniku, w dokumentacji funkcji i w kodzie \u017ar\u00f3d\u0142owym WordPressa 7.1.2, aktualnej wersji na dzie\u0144 29.09.2026.<\/p>\n<h2>Trzy fazy, trzy punkty wej\u015bcia<\/h2>\n<p>Podr\u0119cznik dla tw\u00f3rc\u00f3w wtyczek wyra\u017anie rozdziela fazy: aktywacja s\u0142u\u017cy do regu\u0142 przepisywania adres\u00f3w, w\u0142asnych tabel i domy\u015blnych opcji, dezaktywacja usuwa dane tymczasowe, takie jak cache, a dopiero odinstalowanie powinno kasowa\u0107 dane trwa\u0142e, czyli opcje i tabele.<\/p>\n<p>Od strony technicznej <code>register_activation_hook()<\/code> i <code>register_deactivation_hook()<\/code> to cienkie nak\u0142adki. Obie funkcje przepuszczaj\u0105 przekazany plik przez <code>plugin_basename()<\/code> i podpinaj\u0105 callback pod dynamiczn\u0105 akcj\u0119 <code>activate_{$plugin}<\/code> lub <code>deactivate_{$plugin}<\/code>. Pierwszym argumentem musi wi\u0119c by\u0107 g\u0142\u00f3wny plik wtyczki z nag\u0142\u00f3wkiem, zwykle <code>__FILE__<\/code> w tym w\u0142a\u015bnie pliku. Odinstalowanie dzia\u0142a inaczej: WordPress albo do\u0142\u0105cza plik <code>uninstall.php<\/code> z folderu wtyczki, albo wywo\u0142uje callback zarejestrowany przez <code>register_uninstall_hook()<\/code>. Oba warianty dzia\u0142aj\u0105 tylko przy usuwaniu wtyczki, nie przy jej dezaktywacji.<\/p>\n<table>\n<thead>\n<tr>\n<th>Faza<\/th>\n<th>Punkt wej\u015bcia<\/th>\n<th>Przyk\u0142adowa wtyczka: zak\u0142ada lub usuwa<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Aktywacja<\/td>\n<td><code>register_activation_hook()<\/code><\/td>\n<td>zak\u0142ada tabel\u0119, wersj\u0119 schematu, capability i zdarzenie cron<\/td>\n<\/tr>\n<tr>\n<td>Aktualizacja<\/td>\n<td>brak hooka, kontrola wersji na <code>plugins_loaded<\/code><\/td>\n<td>ta sama procedura konfiguracji plus migracja danych<\/td>\n<\/tr>\n<tr>\n<td>Dezaktywacja<\/td>\n<td><code>register_deactivation_hook()<\/code><\/td>\n<td>usuwa zdarzenie cron i transient, reszt\u0119 zostawia<\/td>\n<\/tr>\n<tr>\n<td>Odinstalowanie<\/td>\n<td><code>uninstall.php<\/code><\/td>\n<td>zawsze usuwa capability, cron i cache; tabel\u0119, opcje i meta u\u017cytkownik\u00f3w tylko po zgodzie<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<figure class=\"lw-diagram\">\n<img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/diagrams\/wp-plugin-lebenszyklus-pl.png?v=20260930\" width=\"1120\" height=\"580\" alt=\"Cykl \u017cycia przyk\u0142adowej wtyczki LW Search Log: aktywacja zak\u0142ada tabel\u0119, opcj\u0119 wersji, capability i codzienny cron; dezaktywacja usuwa tylko zdarzenie cron i transient; odinstalowanie zawsze usuwa capability i cron, a tabel\u0119 i meta u\u017cytkownik\u00f3w tylko po zgodzie; aktualizacja powtarza konfiguracj\u0119\"><figcaption>Przyk\u0142adowa wtyczka LW Search Log: aktywacja konfiguruje, dezaktywacja zatrzymuje, odinstalowanie kasuje dane tylko po zgodzie<\/figcaption><\/figure>\n<h2>Aktywacja to nie hook aktualizacji<\/h2>\n<p>Od WordPressa 3.1 hook aktywacji nie uruchamia si\u0119 przy aktualizacjach. Andrew Nacin uzasadni\u0142 t\u0119 zmian\u0119 w pa\u017adzierniku 2010 roku na blogu Make WordPress Core: wcze\u015bniej hook dzia\u0142a\u0142 przy pojedynczych aktualizacjach, przy zbiorczych ju\u017c nie, a r\u0119czne aktualizacje przez FTP lub SVN nigdy go nie wywo\u0142ywa\u0142y. Zalecenie z tego samego wpisu pozostaje aktualne: wersj\u0119 nale\u017cy zapisa\u0107 w bazie danych, por\u00f3wna\u0107 z wersj\u0105 w kodzie i przy rozbie\u017cno\u015bci uruchomi\u0107 procedur\u0119 aktualizacji.<\/p>\n<p>Obecny kod \u017ar\u00f3d\u0142owy to potwierdza. Przed aktualizacj\u0105 <code>Plugin_Upgrader::deactivate_plugin_before_upgrade()<\/code> dezaktywuje aktywn\u0105 wtyczk\u0119 wywo\u0142aniem <code>deactivate_plugins( $plugin, true )<\/code>; drugi argument oznacza tryb cichy, wi\u0119c \u017caden hook dezaktywacji si\u0119 nie uruchamia. Przy aktualizacjach w tle przez cron wtyczka w og\u00f3le nie jest dezaktywowana. Nast\u0119pnie <code>wp-admin\/update.php<\/code> ponownie aktywuje wtyczk\u0119 wywo\u0142aniem <code>activate_plugin( $plugin, '', ! empty( $_GET['networkwide'] ), true )<\/code>, r\u00f3wnie\u017c po cichu. Docblock funkcji <code>activate_plugin()<\/code> stwierdza, \u017ce cicha aktywacja pomija hooki aktywacji.<\/p>\n<p>Hook <code>upgrader_process_complete<\/code> s\u0142abo nadaje si\u0119 do migracji. Uruchamia si\u0119 w \u017c\u0105daniu, kt\u00f3re przeprowadzi\u0142o aktualizacj\u0119, a notatka w dokumentacji hooka zwraca uwag\u0119, \u017ce w tym momencie dzia\u0142a jeszcze stary kod wtyczki. Migracja napisana dla wersji 2 zadzia\u0142a\u0142aby wi\u0119c dopiero o jedn\u0105 aktualizacj\u0119 p\u00f3\u017aniej. Kontrola wersji na <code>plugins_loaded<\/code>, pokazana w rozdziale podr\u0119cznika o w\u0142asnych tabelach, dzia\u0142a natomiast przy ka\u017cdym \u017c\u0105daniu ju\u017c z nowym kodem, niezale\u017cnie od tego, jak\u0105 drog\u0105 dotar\u0142a aktualizacja.<\/p>\n<h2>W\u0142asna tabela z dbDelta i wersjonowanym schematem<\/h2>\n<p>To, czy w\u0142asna tabela w og\u00f3le si\u0119 op\u0142aca, omawia <a href=\"https:\/\/www.lukaswojcik.com\/blog\/pl\/tworzenie-stron-internetowych\/baza-danych-wordpressa-ograniczenia-wydajnosci-wp_postmeta-i-budowa\/\">artyku\u0142 o granicach wydajno\u015bci wp_postmeta<\/a>; tutaj tabela jest za\u0142o\u017ceniem. <code>dbDelta()<\/code> znajduje si\u0119 w pliku <code>wp-admin\/includes\/upgrade.php<\/code>, kt\u00f3ry trzeba do\u0142\u0105czy\u0107 jawnie. Funkcja por\u00f3wnuje instrukcj\u0119 <code>CREATE TABLE<\/code> z istniej\u0105c\u0105 tabel\u0105 i uzupe\u0142nia braki. Poniewa\u017c analizuje SQL jako tekst, jest bardzo wymagaj\u0105ca co do formatu. Podr\u0119cznik wymaga:<\/p>\n<ul>\n<li>ka\u017cdego pola w osobnym wierszu;<\/li>\n<li>dw\u00f3ch spacji mi\u0119dzy <code>PRIMARY KEY<\/code> a definicj\u0105 klucza;<\/li>\n<li>s\u0142owa <code>KEY<\/code> zamiast synonimu <code>INDEX<\/code> i co najmniej jednego <code>KEY<\/code>;<\/li>\n<li>braku apostrof\u00f3w i grawis\u00f3w wok\u00f3\u0142 nazw p\u00f3l;<\/li>\n<li>typ\u00f3w p\u00f3l zapisanych ma\u0142ymi literami, a s\u0142\u00f3w kluczowych SQL, takich jak <code>CREATE TABLE<\/code>, wielkimi;<\/li>\n<li>d\u0142ugo\u015bci przy ka\u017cdym typie pola, kt\u00f3ry j\u0105 przyjmuje, na przyk\u0142ad <code>int(11)<\/code>.<\/li>\n<\/ul>\n<p>Dokumentacja funkcji dodaje ograniczenia: <code>dbDelta()<\/code> nie usuwa kolumn, pole o zmienionej nazwie trafia do tabeli jako dodatkowa kolumna, a zwracane komunikaty nie dowodz\u0105, \u017ce zmiana rzeczywi\u015bcie zosta\u0142a wykonana. Zmiana nazw, usuwanie kolumn i przekszta\u0142canie danych nale\u017c\u0105 wi\u0119c do osobnych krok\u00f3w migracji. Zestaw znak\u00f3w dostarcza <code>$wpdb-&gt;get_charset_collate()<\/code>.<\/p>\n<p>Poni\u017cej pe\u0142ny plik g\u0142\u00f3wny przyk\u0142adowej wtyczki. Rejestruje ona wyszukiwania z frontendu w tabeli, raz dziennie usuwa wiersze starsze ni\u017c 90 dni i w menu \u201eNarz\u0119dzia\u201d pokazuje najcz\u0119stsze frazy wszystkim, kt\u00f3rzy maj\u0105 capability <code>lwsl_view_log<\/code>.<\/p>\n<pre><code>&lt;?php\n\/**\n * Plugin Name:       LW Search Log\n * Description:       Stores front-end search terms in a custom table and prunes old rows once a day.\n * Version:           1.1.0\n * Requires at least: 6.5\n * Requires PHP:      7.4\n * Author:            Lukas Wojcik\n * License:           GPL-2.0-or-later\n * License URI:       https:\/\/www.gnu.org\/licenses\/gpl-2.0.html\n * Text Domain:       lw-search-log\n *\n * @package LW_Search_Log\n *\/\n\ndefined( 'ABSPATH' ) || exit;\n\nconst LWSL_DB_VERSION = 2;\nconst LWSL_CRON_HOOK  = 'lwsl_prune_log';\nconst LWSL_CAP        = 'lwsl_view_log';\n\n\/**\n * Returns the log table name of the current site.\n *\n * @return string\n *\/\nfunction lwsl_table() {\n\tglobal $wpdb;\n\treturn $wpdb-&gt;prefix . 'lwsl_searches';\n}\n\n\/**\n * Creates the log table or brings it to the current structure.\n *\/\nfunction lwsl_create_table() {\n\tglobal $wpdb;\n\n\trequire_once ABSPATH . 'wp-admin\/includes\/upgrade.php';\n\n\t$table   = lwsl_table();\n\t$collate = $wpdb-&gt;get_charset_collate();\n\n\t\/\/ dbDelta() parses this text: one column per line, two spaces after\n\t\/\/ PRIMARY KEY, KEY instead of INDEX, no backticks around names.\n\t$sql = \"CREATE TABLE {$table} (\n\tid bigint(20) unsigned NOT NULL AUTO_INCREMENT,\n\tterm varchar(190) NOT NULL DEFAULT '',\n\tresult_count int(11) unsigned NOT NULL DEFAULT 0,\n\tsearched_at datetime NOT NULL,\n\tPRIMARY KEY  (id),\n\tKEY searched_at (searched_at)\n) {$collate};\";\n\n\tdbDelta( $sql );\n}\n\n\/**\n * Data migration for schema version 2: terms are stored in lower case.\n * The new column result_count is added by dbDelta() itself.\n *\/\nfunction lwsl_migrate_to_2() {\n\tglobal $wpdb;\n\t\/\/ phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching\n\t$wpdb-&gt;query( $wpdb-&gt;prepare( 'UPDATE %i SET term = LOWER(term)', lwsl_table() ) );\n}\n\n\/**\n * Brings the current site to the state this code expects.\n * Idempotent: used on activation, after updates and for new sites.\n *\/\nfunction lwsl_setup_site() {\n\t$installed = (int) get_option( 'lwsl_db_version', 0 );\n\n\tlwsl_create_table();\n\n\tif ( $installed &gt; 0 &amp;&amp; $installed &lt; 2 ) {\n\t\tlwsl_migrate_to_2();\n\t}\n\n\t$role = get_role( 'administrator' );\n\tif ( $role &amp;&amp; ! $role-&gt;has_cap( LWSL_CAP ) ) {\n\t\t$role-&gt;add_cap( LWSL_CAP );\n\t}\n\n\tif ( ! wp_next_scheduled( LWSL_CRON_HOOK ) ) {\n\t\twp_schedule_event( time() + HOUR_IN_SECONDS, 'daily', LWSL_CRON_HOOK );\n\t}\n\n\t\/\/ Read on every request by lwsl_maybe_upgrade(), so it stays autoloaded.\n\tupdate_option( 'lwsl_db_version', LWSL_DB_VERSION, true );\n}\n\n\/**\n * Runs a callback once for every site of the network, 100 sites per query.\n *\n * @param callable $callback Function without parameters.\n *\/\nfunction lwsl_for_each_site( $callback ) {\n\t$offset = 0;\n\tdo {\n\t\t$site_ids = get_sites(\n\t\t\tarray(\n\t\t\t\t'fields' =&gt; 'ids',\n\t\t\t\t'number' =&gt; 100,\n\t\t\t\t'offset' =&gt; $offset,\n\t\t\t)\n\t\t);\n\t\tforeach ( $site_ids as $site_id ) {\n\t\t\tswitch_to_blog( $site_id );\n\t\t\tcall_user_func( $callback );\n\t\t\trestore_current_blog();\n\t\t}\n\t\t$offset += 100;\n\t} while ( 100 === count( $site_ids ) );\n}\n\n\/**\n * Activation: set up the current site, or every site on network activation.\n *\n * @param bool $network_wide True when the plugin is network-activated.\n *\/\nfunction lwsl_activate( $network_wide = false ) {\n\tif ( is_multisite() &amp;&amp; $network_wide ) {\n\t\t\/\/ On large networks the sites are set up lazily by lwsl_maybe_upgrade().\n\t\tif ( ! wp_is_large_network() ) {\n\t\t\tlwsl_for_each_site( 'lwsl_setup_site' );\n\t\t}\n\t\treturn;\n\t}\n\tlwsl_setup_site();\n}\nregister_activation_hook( __FILE__, 'lwsl_activate' );\n\n\/**\n * Update path: activation hooks do not run on updates, so the stored\n * schema version is compared with the code on every request.\n *\/\nfunction lwsl_maybe_upgrade() {\n\tif ( (int) get_option( 'lwsl_db_version', 0 ) &lt; LWSL_DB_VERSION ) {\n\t\tlwsl_setup_site();\n\t}\n}\nadd_action( 'plugins_loaded', 'lwsl_maybe_upgrade' );\n\n\/**\n * Stops scheduled work and drops caches on the current site. Keeps all data.\n *\/\nfunction lwsl_teardown_site() {\n\twp_clear_scheduled_hook( LWSL_CRON_HOOK );\n\tdelete_transient( 'lwsl_top_terms' );\n}\n\n\/**\n * Deactivation: current site, or every site on network deactivation.\n *\n * @param bool $network_deactivating True when the plugin is network-deactivated.\n *\/\nfunction lwsl_deactivate( $network_deactivating = false ) {\n\tif ( is_multisite() &amp;&amp; $network_deactivating ) {\n\t\tlwsl_for_each_site( 'lwsl_teardown_site' );\n\t\treturn;\n\t}\n\tlwsl_teardown_site();\n}\nregister_deactivation_hook( __FILE__, 'lwsl_deactivate' );\n\n\/**\n * Cron callback: deletes log rows older than 90 days.\n *\/\nfunction lwsl_prune_log() {\n\tglobal $wpdb;\n\t$cutoff = gmdate( 'Y-m-d H:i:s', time() - 90 * DAY_IN_SECONDS );\n\t\/\/ phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching\n\t$wpdb-&gt;query( $wpdb-&gt;prepare( 'DELETE FROM %i WHERE searched_at &lt; %s', lwsl_table(), $cutoff ) );\n\tdelete_transient( 'lwsl_top_terms' );\n}\nadd_action( LWSL_CRON_HOOK, 'lwsl_prune_log' );\n\n\/**\n * Logs the search term of the main front-end query.\n *\/\nfunction lwsl_log_search() {\n\tglobal $wpdb, $wp_query;\n\n\tif ( ! is_search() || is_paged() ) {\n\t\treturn;\n\t}\n\n\t$term = mb_substr( sanitize_text_field( get_search_query( false ) ), 0, 190 );\n\tif ( '' === $term ) {\n\t\treturn;\n\t}\n\n\t\/\/ phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching\n\t$wpdb-&gt;query(\n\t\t$wpdb-&gt;prepare(\n\t\t\t'INSERT INTO %i (term, result_count, searched_at) VALUES (LOWER(%s), %d, %s)',\n\t\t\tlwsl_table(),\n\t\t\t$term,\n\t\t\t(int) $wp_query-&gt;found_posts,\n\t\t\tcurrent_time( 'mysql', true )\n\t\t)\n\t);\n}\nadd_action( 'wp', 'lwsl_log_search' );\n\n\/**\n * Adds the log page under Tools, visible with the plugin capability only.\n *\/\nfunction lwsl_admin_menu() {\n\tadd_management_page(\n\t\t__( 'Search log', 'lw-search-log' ),\n\t\t__( 'Search log', 'lw-search-log' ),\n\t\tLWSL_CAP,\n\t\t'lwsl-search-log',\n\t\t'lwsl_render_page'\n\t);\n}\nadd_action( 'admin_menu', 'lwsl_admin_menu' );\n\n\/**\n * Renders the top terms (cached in a transient) and the searches since the\n * current user's last visit (stored in user meta).\n *\/\nfunction lwsl_render_page() {\n\tglobal $wpdb;\n\n\t$user_id   = get_current_user_id();\n\t$last_seen = (int) get_user_meta( $user_id, 'lwsl_last_viewed', true );\n\tupdate_user_meta( $user_id, 'lwsl_last_viewed', time() );\n\n\t$top = get_transient( 'lwsl_top_terms' );\n\tif ( false === $top ) {\n\t\t\/\/ phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- cached in a transient.\n\t\t$top = $wpdb-&gt;get_results(\n\t\t\t$wpdb-&gt;prepare( 'SELECT term, COUNT(*) AS hits FROM %i GROUP BY term ORDER BY hits DESC LIMIT 20', lwsl_table() )\n\t\t);\n\t\tset_transient( 'lwsl_top_terms', $top, HOUR_IN_SECONDS );\n\t}\n\n\t\/\/ phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching\n\t$new = (int) $wpdb-&gt;get_var(\n\t\t$wpdb-&gt;prepare( 'SELECT COUNT(*) FROM %i WHERE searched_at &gt; %s', lwsl_table(), gmdate( 'Y-m-d H:i:s', $last_seen ) )\n\t);\n\n\techo '&lt;div class=\"wrap\"&gt;&lt;h1&gt;' . esc_html__( 'Search log', 'lw-search-log' ) . '&lt;\/h1&gt;&lt;p&gt;';\n\techo esc_html(\n\t\tsprintf(\n\t\t\t\/* translators: %d: number of searches since the last visit *\/\n\t\t\t__( 'New searches since the last visit: %d', 'lw-search-log' ),\n\t\t\t$new\n\t\t)\n\t);\n\techo '&lt;\/p&gt;&lt;ol&gt;';\n\tforeach ( $top as $row ) {\n\t\tprintf( '&lt;li&gt;%s (%d)&lt;\/li&gt;', esc_html( $row-&gt;term ), (int) $row-&gt;hits );\n\t}\n\techo '&lt;\/ol&gt;&lt;\/div&gt;';\n}\n\n\/**\n * Multisite: drop the log table together with a deleted site.\n *\n * @param string[] $tables  Tables WordPress is about to drop.\n * @param int      $site_id ID of the deleted site.\n * @return string[]\n *\/\nfunction lwsl_drop_site_table( $tables, $site_id ) {\n\tglobal $wpdb;\n\t$tables[] = $wpdb-&gt;get_blog_prefix( $site_id ) . 'lwsl_searches';\n\treturn $tables;\n}\nadd_filter( 'wpmu_drop_tables', 'lwsl_drop_site_table', 10, 2 );<\/code><\/pre>\n<p>Sercem wtyczki jest <code>lwsl_setup_site()<\/code>. Funkcja jest idempotentna: <code>dbDelta()<\/code> niczego nie zmienia, gdy tabela ju\u017c pasuje, capability zapisuje si\u0119 tylko wtedy, gdy jej brakuje, a zdarzenie cron zostaje zaplanowane tylko wtedy, gdy <code>wp_next_scheduled()<\/code> \u017cadnego nie znajdzie. Dzi\u0119ki temu da si\u0119 j\u0105 bezpiecznie wywo\u0142a\u0107 z hooka aktywacji, z kontroli wersji i dla jeszcze nieskonfigurowanych witryn w sieci. Wersja schematu 2 pokazuje oba rodzaje migracji. Now\u0105 kolumn\u0119 <code>result_count<\/code> <code>dbDelta()<\/code> dodaje samodzielnie, natomiast zamiana istniej\u0105cych fraz na ma\u0142e litery to migracja danych z w\u0142asnym krokiem, kt\u00f3ry uruchamia si\u0119 tylko przy zapisanej wersji 1.<\/p>\n<p>Dwa szczeg\u00f3\u0142y \u0142atwo przeoczy\u0107. Opcja <code>lwsl_db_version<\/code> jest odczytywana przy ka\u017cdym \u017c\u0105daniu, dlatego zapisuje si\u0119 j\u0105 z w\u0142\u0105czonym autoload; w przeciwnym razie ka\u017cde wy\u015bwietlenie strony kosztowa\u0142oby dodatkowe zapytanie. Przy ka\u017cdym wywo\u0142aniu <code>add_cap()<\/code> przekazuje ca\u0142\u0105 opcj\u0119 r\u00f3l do <code>update_option()<\/code>. Ta funkcja zapisuje j\u0105 w bazie tylko wtedy, gdy capability jest nowa. Mimo to przyk\u0142ad dodaje uprawnienie wy\u0142\u0105cznie w procedurze konfiguracji, a nie na <code>init<\/code>. Nazwy tabel trafiaj\u0105 do zapyta\u0144 przez symbol zast\u0119pczy <code>%i<\/code>, kt\u00f3ry <code>$wpdb-&gt;prepare()<\/code> obs\u0142uguje dla identyfikator\u00f3w od WordPressa 6.2.<\/p>\n<h2>Dezaktywacja: zatrzyma\u0107, nie kasowa\u0107<\/h2>\n<p>Dezaktywacja bywa tymczasowa, na przyk\u0142ad podczas szukania b\u0142\u0119du. Przyk\u0142ad usuwa wi\u0119c tylko to, co bez wtyczki dzia\u0142a\u0142oby dalej albo po ponownej aktywacji by\u0142oby nieaktualne: zdarzenie cron i zapisan\u0105 w transiencie list\u0119 najcz\u0119stszych fraz. Tabela, wersja schematu, capability i meta u\u017cytkownik\u00f3w zostaj\u0105.<\/p>\n<p>Do obs\u0142ugi crona s\u0142u\u017c\u0105 dwie funkcje. <code>wp_clear_scheduled_hook()<\/code> usuwa wszystkie zdarzenia hooka z podanymi argumentami, a dokumentacja podkre\u015bla, \u017ce argumenty musz\u0105 si\u0119 dok\u0142adnie zgadza\u0107. Je\u015bli wtyczka planuje ten sam hook z r\u00f3\u017cnymi argumentami, pomo\u017ce tylko <code>wp_unschedule_hook()<\/code>: funkcja istnieje od wersji 4.9, usuwa wszystkie zdarzenia hooka bez wzgl\u0119du na argumenty, a jej docblock wprost wymienia sprz\u0105tanie kolejki cron przy dezaktywacji jako zastosowanie. Przyk\u0142ad planuje zdarzenie bez argument\u00f3w; procedura odinstalowania mimo to si\u0119ga dla pewno\u015bci po drug\u0105 funkcj\u0119.<\/p>\n<p>Callback dezaktywacji otrzymuje warto\u015b\u0107 logiczn\u0105, kt\u00f3ra w Multisite jest prawdziwa przy dezaktywacji sieciowej. <code>lwsl_deactivate()<\/code> sprz\u0105ta wtedy na wszystkich witrynach. Capability przy dezaktywacji celowo zostaje: bez wtyczki \u017caden kod jej nie sprawdza, a usuni\u0119cie i ponowne dodanie oznacza\u0142oby dwa zb\u0119dne zapisy opcji r\u00f3l na ka\u017cdej witrynie.<\/p>\n<h2>Odinstalowanie: uninstall.php, register_uninstall_hook i zgoda<\/h2>\n<p>Przy usuwaniu wtyczki <code>delete_plugins()<\/code> wywo\u0142uje dla ka\u017cdej z nich <code>uninstall_plugin()<\/code>, zanim znikn\u0105 pliki. Kod \u017ar\u00f3d\u0142owy rozstrzyga te\u017c pierwsze\u0144stwo mi\u0119dzy wariantami: je\u015bli istnieje <code>uninstall.php<\/code>, WordPress usuwa ewentualnie zarejestrowany callback z opcji <code>uninstall_plugins<\/code>, definiuje sta\u0142\u0105 <code>WP_UNINSTALL_PLUGIN<\/code> z nazw\u0105 bazow\u0105 wtyczki i do\u0142\u0105cza wy\u0142\u0105cznie ten plik. G\u0142\u00f3wny plik wtyczki nie zostaje przy tym za\u0142adowany. Dlatego plik pokazany ni\u017cej wypisuje ka\u017cd\u0105 nazw\u0119 w ca\u0142o\u015bci, zamiast korzysta\u0107 ze sta\u0142ych takich jak <code>LWSL_CAP<\/code>. Dopiero gdy <code>uninstall.php<\/code> nie istnieje, WordPress do\u0142\u0105cza plik g\u0142\u00f3wny i wykonuje zapisany callback na <code>uninstall_{$file}<\/code>; wtedy uruchamia si\u0119 r\u00f3wnie\u017c ka\u017cdy wiersz kodu na poziomie pliku.<\/p>\n<p>Sprawdzenie sta\u0142ej <code>WP_UNINSTALL_PLUGIN<\/code> na pocz\u0105tku pliku chroni przed bezpo\u015brednim wywo\u0142aniem, czego wymaga podr\u0119cznik. Dla <code>register_uninstall_hook()<\/code> obowi\u0105zuj\u0105 ostrzejsze regu\u0142y ni\u017c dla dw\u00f3ch pozosta\u0142ych funkcji rejestruj\u0105cych, bo callback trafia do opcji w bazie. Closure nie da si\u0119 zserializowa\u0107, co ko\u0144czy si\u0119 b\u0142\u0119dem krytycznym; metoda obiektu zostaje odrzucona z komunikatem <code>_doing_it_wrong()<\/code>. Dozwolone s\u0105 tylko nazwy funkcji i metody statyczne. Ka\u017cde wywo\u0142anie odczytuje opcj\u0119 i zapisuje j\u0105, gdy brakuje wpisu albo r\u00f3\u017cni si\u0119 on od podanego; rejestracja nale\u017cy wi\u0119c do aktywacji, a nie do ka\u017cdego \u017c\u0105dania.<\/p>\n<pre><code>\/\/ Counter-example: what register_uninstall_hook() accepts and what it rejects.\n\n\/\/ Accepted: a function name or a static method. The callback is stored\n\/\/ in the option uninstall_plugins, so register it once, on activation.\nregister_uninstall_hook( __FILE__, 'lwsl_uninstall' );\nregister_uninstall_hook( __FILE__, array( 'LWSL_Plugin', 'uninstall' ) );\n\n\/\/ Rejected: a closure cannot be serialized into that option (fatal error),\n\/\/ an object method triggers _doing_it_wrong() and is not registered.\nregister_uninstall_hook( __FILE__, function () {} );\nregister_uninstall_hook( __FILE__, array( new LWSL_Plugin(), 'uninstall' ) );<\/code><\/pre>\n<p>Co oznacza \u201eusuwanie danych przy odinstalowaniu\u201d jako zgoda typu opt-in? Usuni\u0119cie wtyczki nie musi oznacza\u0107 po\u017cegnania z jej danymi; tak\u017ce ponowna instalacja, kt\u00f3ra ma wykluczy\u0107 uszkodzone pliki, zaczyna si\u0119 od usuni\u0119cia. Przyk\u0142ad dzieli wi\u0119c sprz\u0105tanie na dwie grupy. Pozosta\u0142o\u015bci techniczne znikaj\u0105 zawsze: zdarzenia cron, transienty i capability s\u0105 bez wtyczki bezu\u017cyteczne, a aktywacja i tak tworzy je na nowo. Tre\u015bci i konfiguracja znikaj\u0105 tylko po wyra\u017anym \u201etak\u201d: tabela dziennika, wersja schematu, meta u\u017cytkownik\u00f3w i sam prze\u0142\u0105cznik. Bez zgody ponowna instalacja zastaje stary dziennik razem z wersj\u0105 schematu.<\/p>\n<pre><code>&lt;?php\n\/**\n * Uninstall routine of LW Search Log.\n *\n * WordPress includes this file when the plugin is deleted. The main plugin\n * file is not loaded, so every name is spelled out here.\n *\n * @package LW_Search_Log\n *\/\n\n\/\/ Only run when WordPress itself starts the uninstall.\nif ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {\n\texit;\n}\n\n\/**\n * Cleans one site: technical leftovers always, data only after opt-in.\n *\n * @param bool $delete_data Whether the site owner opted in to data removal.\n *\/\nfunction lwsl_uninstall_site( $delete_data ) {\n\tglobal $wpdb;\n\n\t\/\/ Always: scheduled events, caches and the capability.\n\twp_unschedule_hook( 'lwsl_prune_log' );\n\tdelete_transient( 'lwsl_top_terms' );\n\n\tforeach ( wp_roles()-&gt;role_objects as $role ) {\n\t\tif ( $role-&gt;has_cap( 'lwsl_view_log' ) ) {\n\t\t\t$role-&gt;remove_cap( 'lwsl_view_log' );\n\t\t}\n\t}\n\n\tif ( ! $delete_data ) {\n\t\treturn;\n\t}\n\n\t\/\/ Opt-in only: the log table and the schema version.\n\t\/\/ phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange\n\t$wpdb-&gt;query( $wpdb-&gt;prepare( 'DROP TABLE IF EXISTS %i', $wpdb-&gt;prefix . 'lwsl_searches' ) );\n\tdelete_option( 'lwsl_db_version' );\n}\n\n\/\/ The opt-in switch: a network option on multisite, a normal option otherwise.\n$lwsl_delete_data = (bool) get_site_option( 'lwsl_delete_data_on_uninstall', false );\n\nif ( is_multisite() ) {\n\t$lwsl_offset = 0;\n\tdo {\n\t\t$lwsl_site_ids = get_sites(\n\t\t\tarray(\n\t\t\t\t'fields' =&gt; 'ids',\n\t\t\t\t'number' =&gt; 100,\n\t\t\t\t'offset' =&gt; $lwsl_offset,\n\t\t\t)\n\t\t);\n\t\tforeach ( $lwsl_site_ids as $lwsl_site_id ) {\n\t\t\tswitch_to_blog( $lwsl_site_id );\n\t\t\tlwsl_uninstall_site( $lwsl_delete_data );\n\t\t\trestore_current_blog();\n\t\t}\n\t\t$lwsl_offset += 100;\n\t} while ( 100 === count( $lwsl_site_ids ) );\n} else {\n\tlwsl_uninstall_site( $lwsl_delete_data );\n}\n\nif ( $lwsl_delete_data ) {\n\t\/\/ wp_usermeta is shared by all sites: one call removes the key for every user.\n\tdelete_metadata( 'user', 0, 'lwsl_last_viewed', '', true );\n\tdelete_site_option( 'lwsl_delete_data_on_uninstall' );\n}<\/code><\/pre>\n<p>Meta u\u017cytkownik\u00f3w usuwa <code>delete_metadata()<\/code> z pi\u0105tym argumentem <code>$delete_all<\/code> ustawionym na true, co kasuje klucz u wszystkich u\u017cytkownik\u00f3w naraz. <code>delete_user_meta()<\/code> dzia\u0142a za ka\u017cdym razem tylko dla jednego identyfikatora u\u017cytkownika. <code>delete_transient()<\/code> uwzgl\u0119dnia ponadto zewn\u0119trzny cache obiekt\u00f3w i w takim przypadku usuwa wpis w\u0142a\u015bnie tam, a nie w tabeli opcji. Zapytanie <code>LIKE<\/code> na <code>_transient_%<\/code> w <code>wp_options<\/code> takiego cache nie obejmuje.<\/p>\n<p>Spos\u00f3b ustawiania prze\u0142\u0105cznika to zadanie strony ustawie\u0144; Settings API omawia <span class=\"lw-artikel-geplant\">osobny artyku\u0142 z tej serii<\/span>. Do testu wystarczy WP-CLI. <code>wp plugin uninstall<\/code> z opcj\u0105 <code>--skip-delete<\/code> wykonuje tylko procedur\u0119 odinstalowania i zostawia pliki, a <code>wp plugin delete<\/code> usuwa pliki bez dezaktywacji i bez odinstalowania. T\u0119 r\u00f3\u017cnic\u0119 dok\u0142adniej opisuje <a href=\"https:\/\/www.lukaswojcik.com\/blog\/pl\/wordpress-plugins-tricks-pl\/polecenia-usuwania-w-wp-cli-ktorych-tabel-dotyka-kazde-z-nich\/\">artyku\u0142 o poleceniach usuwania w WP-CLI i tabelach, kt\u00f3rych dotykaj\u0105<\/a>.<\/p>\n<pre><code># Single site: opt in, then run only the uninstall routine (files stay).\nwp option update lwsl_delete_data_on_uninstall 1\nwp plugin deactivate lw-search-log\nwp plugin uninstall lw-search-log --skip-delete\n\n# Multisite: the switch is a network option.\nwp site option update lwsl_delete_data_on_uninstall 1\nwp plugin deactivate lw-search-log --network\nwp plugin uninstall lw-search-log --skip-delete\n\n# Deletes the files only: neither deactivation nor uninstall code runs.\nwp plugin delete lw-search-log<\/code><\/pre>\n<h2>Multisite: raz na sie\u0107, dane na ka\u017cdej witrynie<\/h2>\n<p>W Multisite wi\u0119kszo\u015b\u0107 danych przyk\u0142adu jest przechowywana osobno dla ka\u017cdej witryny. Tabela ma prefiks witryny, ka\u017cda witryna ma w\u0142asne opcje i transienty, zdarzenia cron znajduj\u0105 si\u0119 w jej opcji <code>cron<\/code>, a role w opcji o nazwie z\u0142o\u017conej z prefiksu witryny i <code>user_roles<\/code>. Metadane u\u017cytkownik\u00f3w s\u0105 natomiast przechowywane w jednej tabeli dla ca\u0142ej sieci. Prze\u0142\u0105cznik zgody jest odczytywany przez <code>get_site_option()<\/code> jako opcja sieciowa; w pojedynczej instalacji jest to zwyk\u0142a opcja.<\/p>\n<p>Aktywacja sieciowa wywo\u0142uje hook aktywacji dok\u0142adnie raz, w kontek\u015bcie bie\u017c\u0105cej witryny i z <code>$network_wide<\/code> ustawionym na true. <code>activate_plugin()<\/code> ustawia t\u0119 warto\u015b\u0107 tak\u017ce wtedy, gdy nag\u0142\u00f3wek wtyczki zawiera <code>Network: true<\/code>. O wszystkie pozosta\u0142e witryny wtyczka musi zadba\u0107 sama. <code>lwsl_for_each_site()<\/code> robi to za pomoc\u0105 <code>get_sites()<\/code> i <code>switch_to_blog()<\/code>. Czyhaj\u0105 tu dwie pu\u0142apki: <code>get_sites()<\/code> bez dodatkowych parametr\u00f3w zwraca najwy\u017cej 100 witryn, dlatego p\u0119tla jawnie stronicuje wyniki; a <code>switch_to_blog()<\/code> prze\u0142\u0105cza tylko kontekst bazy danych, nie za\u0142adowany kod. Tutaj nie ma to znaczenia, bo p\u0119tla wywo\u0142uje wy\u0142\u0105cznie funkcje tej wtyczki.<\/p>\n<p>W du\u017cych sieciach p\u0119tla po wszystkich witrynach podczas aktywacji mo\u017ce trafi\u0107 na limity czasu. WordPress uznaje sie\u0107 za du\u017c\u0105 powy\u017cej 10 000 witryn lub u\u017cytkownik\u00f3w, a wynik <code>wp_is_large_network()<\/code> da si\u0119 filtrowa\u0107. W takim przypadku przyk\u0142ad pomija p\u0119tl\u0119 i polega na kontroli wersji: <code>lwsl_maybe_upgrade()<\/code> dzia\u0142a przy ka\u017cdym \u017c\u0105daniu ka\u017cdej witryny, na kt\u00f3rej wtyczka jest aktywna, i konfiguruje witryn\u0119 przy jej pierwszym \u017c\u0105daniu. Obejmuje to r\u00f3wnie\u017c witryny utworzone po aktywacji. Kto chce konfigurowa\u0107 nowe witryny natychmiast, mo\u017ce podpi\u0105\u0107 si\u0119 pod <code>wp_initialize_site<\/code>; rdze\u0144 wykonuje tam w\u0142asn\u0105 inicjalizacj\u0119 z priorytetem 10, wi\u0119c callback wtyczki nale\u017cy zarejestrowa\u0107 z p\u00f3\u017aniejszym priorytetem.<\/p>\n<p>Usuni\u0119cie pojedynczej witryny obs\u0142uguje filtr <code>wpmu_drop_tables<\/code>, kt\u00f3ry wymienia tabele usuwane przez WordPressa razem z witryn\u0105. Przyk\u0142ad dopisuje tam swoj\u0105 tabel\u0119 niezale\u017cnie od zgody, bo i tak znika ca\u0142a witryna. Usuni\u0119cie samej wtyczki jest w Multisite zarezerwowane dla superadministrator\u00f3w, jak pokazuje mapowanie capability <code>delete_plugins<\/code>, a <code>uninstall.php<\/code> uruchamia si\u0119 wtedy raz w panelu sieci. P\u0119tla po wszystkich witrynach w procedurze odinstalowania jest wi\u0119c obowi\u0105zkowa; podr\u0119cznik wprost ostrzega, \u017ce w du\u017cych sieciach mo\u017ce poch\u0142ania\u0107 du\u017co zasob\u00f3w.<\/p>\n<h2>Ograniczenia i otwarte kwestie<\/h2>\n<p>Przyk\u0142adowy kod przetestowano w WordPressie 7.1.2 (PHP 8.4, MariaDB 11.8) na pojedynczej instalacji i w sieci opartej na podkatalogach: aktywacj\u0119, aktywacj\u0119 sieciow\u0105, witryn\u0119 utworzon\u0105 p\u00f3\u017aniej, usuni\u0119cie witryny, aktualizacj\u0119 ze schematu 1 do 2, dezaktywacj\u0119 oraz odinstalowanie ze zgod\u0105 i bez niej. Plugin Check 2.1.0 nie zg\u0142asza \u017cadnych uwag do obu plik\u00f3w PHP.<\/p>\n<ul>\n<li>R\u00f3wnoleg\u0142e \u017c\u0105dania tu\u017c po aktualizacji mog\u0105 wykona\u0107 <code>lwsl_setup_site()<\/code> dwukrotnie. Tutaj jest to nieszkodliwe, bo ka\u017cdy krok jest idempotentny; inne migracje wymagaj\u0105 blokady.<\/li>\n<li>Podr\u0119cznik wymaga podawania d\u0142ugo\u015bci tak\u017ce przy typach ca\u0142kowitych, takich jak <code>int(11)<\/code>. W MariaDB 11.8 powtarzane wywo\u0142ania <code>dbDelta()<\/code> z <code>int(11)<\/code> nie zg\u0142asza\u0142y zmian; bez podanej d\u0142ugo\u015bci ka\u017cde wywo\u0142anie zg\u0142asza\u0142o \u201eChanged type\u201d, bo MariaDB pokazuje <code>int(10)<\/code>. W MySQL od 8.0.17 rdze\u0144 od WordPressa 6.1 pomija same r\u00f3\u017cnice szeroko\u015bci (wed\u0142ug kodu \u017ar\u00f3d\u0142owego, bez pomiaru).<\/li>\n<li>Capabilities przypisane bezpo\u015brednio pojedynczym u\u017cytkownikom s\u0105 zapisane w meta u\u017cytkownik\u00f3w i p\u0119tla po rolach ich nie usuwa.<\/li>\n<li>W instalacjach z kilkoma sieciami <code>get_sites()<\/code> bez <code>network_id<\/code> zwraca witryny wszystkich sieci, a prze\u0142\u0105cznik zgody jest zapisany osobno dla ka\u017cdej sieci. W\u0142a\u015bciwe zachowanie w takim przypadku pozostaje otwarte.<\/li>\n<li>Usuni\u0119cie wtyczki przez FTP, Git lub skrypt wdro\u017ceniowy ca\u0142kowicie omija <code>uninstall.php<\/code>. Wtedy \u017cadna wtyczka nie jest w stanie po sobie posprz\u0105ta\u0107.<\/li>\n<\/ul>\n<div class=\"lw-faq\">\n<h2>Pytania i odpowiedzi<\/h2>\n<h3>Czy uninstall.php dzia\u0142a tak\u017ce wtedy, gdy wtyczk\u0119 usuni\u0119to przez FTP lub poleceniem wp plugin delete?<\/h3>\n<p>Nie. WordPress wywo\u0142uje procedur\u0119 odinstalowania tylko z funkcji <code>delete_plugins()<\/code>, czyli przy usuwaniu wtyczki w panelu. WP-CLI oferuje do tego <code>wp plugin uninstall<\/code>; wed\u0142ug dokumentacji <code>wp plugin delete<\/code> usuwa jedynie pliki, bez dezaktywacji i bez odinstalowania. Przy FTP, Git lub skryptach wdro\u017ceniowych wszystko zostaje w bazie danych.<\/p>\n<h3>Co si\u0119 dzieje, gdy wtyczka korzysta jednocze\u015bnie z uninstall.php i register_uninstall_hook()?<\/h3>\n<p>Wygrywa plik. <code>uninstall_plugin()<\/code> najpierw sprawdza, czy istnieje <code>uninstall.php<\/code>, nast\u0119pnie usuwa zarejestrowany callback z opcji <code>uninstall_plugins<\/code> i do\u0142\u0105cza tylko ten plik. Callback nie zostaje wtedy nigdy wywo\u0142any.<\/p>\n<h3>Dlaczego kontrola wersji dzia\u0142a na plugins_loaded, a nie na admin_init?<\/h3>\n<p>Aktualizacje docieraj\u0105 nie tylko przez panel, lecz tak\u017ce przez WP-CLI, automatyczne aktualizacje w tle albo wgrane pliki. Na <code>admin_init<\/code> migracja uruchomi\u0142aby si\u0119 dopiero po otwarciu panelu; do tego czasu nowy kod dzia\u0142a\u0142by na frontendzie ze starym schematem. <code>plugins_loaded<\/code> dzia\u0142a przy ka\u017cdym \u017c\u0105daniu, a podr\u0119cznik umieszcza kontrol\u0119 w\u0142a\u015bnie tam. Opcj\u0119 z wersj\u0105 schematu warto wi\u0119c zapisywa\u0107 z w\u0142\u0105czonym autoload.<\/p>\n<\/div>\n<div class=\"lw-quellen\">\n<h2>\u0179r\u00f3d\u0142a<\/h2>\n<p>Wszystkie \u017ar\u00f3d\u0142a pobrano 29.09.2026.<\/p>\n<ul>\n<li><a href=\"https:\/\/developer.wordpress.org\/plugins\/plugin-basics\/activation-deactivation-hooks\/\" target=\"_blank\" rel=\"noopener noreferrer\">Plugin Handbook: Activation \/ Deactivation Hooks<\/a><\/li>\n<li><a href=\"https:\/\/developer.wordpress.org\/plugins\/plugin-basics\/uninstall-methods\/\" target=\"_blank\" rel=\"noopener noreferrer\">Plugin Handbook: Uninstall Methods<\/a><\/li>\n<li><a href=\"https:\/\/developer.wordpress.org\/plugins\/creating-tables-with-plugins\/\" target=\"_blank\" rel=\"noopener noreferrer\">Plugin Handbook: Creating Tables with Plugins<\/a><\/li>\n<li><a href=\"https:\/\/make.wordpress.org\/core\/2010\/10\/27\/plugin-activation-hooks-no-longer-fire-for-updates\/\" target=\"_blank\" rel=\"noopener noreferrer\">Make WordPress Core: Plugin activation hooks no longer fire for updates (27.10.2010)<\/a><\/li>\n<li><a href=\"https:\/\/developer.wordpress.org\/reference\/functions\/register_deactivation_hook\/\" target=\"_blank\" rel=\"noopener noreferrer\">Dokumentacja funkcji: register_deactivation_hook()<\/a><\/li>\n<li><a href=\"https:\/\/developer.wordpress.org\/reference\/functions\/register_uninstall_hook\/\" target=\"_blank\" rel=\"noopener noreferrer\">Dokumentacja funkcji: register_uninstall_hook()<\/a><\/li>\n<li><a href=\"https:\/\/developer.wordpress.org\/reference\/functions\/dbdelta\/\" target=\"_blank\" rel=\"noopener noreferrer\">Dokumentacja funkcji: dbDelta()<\/a><\/li>\n<li><a href=\"https:\/\/developer.wordpress.org\/reference\/hooks\/upgrader_process_complete\/\" target=\"_blank\" rel=\"noopener noreferrer\">Dokumentacja hooka: upgrader_process_complete<\/a><\/li>\n<li><a href=\"https:\/\/developer.wordpress.org\/reference\/functions\/wp_clear_scheduled_hook\/\" target=\"_blank\" rel=\"noopener noreferrer\">Dokumentacja funkcji: wp_clear_scheduled_hook()<\/a><\/li>\n<li><a href=\"https:\/\/developer.wordpress.org\/reference\/functions\/wp_unschedule_hook\/\" target=\"_blank\" rel=\"noopener noreferrer\">Dokumentacja funkcji: wp_unschedule_hook()<\/a><\/li>\n<li><a href=\"https:\/\/developer.wordpress.org\/reference\/functions\/get_sites\/\" target=\"_blank\" rel=\"noopener noreferrer\">Dokumentacja funkcji: get_sites()<\/a><\/li>\n<li><a href=\"https:\/\/developer.wordpress.org\/reference\/functions\/switch_to_blog\/\" target=\"_blank\" rel=\"noopener noreferrer\">Dokumentacja funkcji: switch_to_blog()<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/WordPress\/wordpress-develop\/blob\/7.1.2\/src\/wp-admin\/includes\/plugin.php\" target=\"_blank\" rel=\"noopener noreferrer\">Kod \u017ar\u00f3d\u0142owy WordPress 7.1.2: wp-admin\/includes\/plugin.php<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/WordPress\/wordpress-develop\/blob\/7.1.2\/src\/wp-admin\/update.php\" target=\"_blank\" rel=\"noopener noreferrer\">Kod \u017ar\u00f3d\u0142owy WordPress 7.1.2: wp-admin\/update.php<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/WordPress\/wordpress-develop\/blob\/7.1.2\/src\/wp-admin\/includes\/class-plugin-upgrader.php\" target=\"_blank\" rel=\"noopener noreferrer\">Kod \u017ar\u00f3d\u0142owy WordPress 7.1.2: class-plugin-upgrader.php<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/WordPress\/wordpress-develop\/blob\/7.1.2\/src\/wp-includes\/plugin.php\" target=\"_blank\" rel=\"noopener noreferrer\">Kod \u017ar\u00f3d\u0142owy WordPress 7.1.2: wp-includes\/plugin.php<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/WordPress\/wordpress-develop\/blob\/7.1.2\/src\/wp-includes\/option.php\" target=\"_blank\" rel=\"noopener noreferrer\">Kod \u017ar\u00f3d\u0142owy WordPress 7.1.2: wp-includes\/option.php<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/WordPress\/wordpress-develop\/blob\/7.1.2\/src\/wp-includes\/meta.php\" target=\"_blank\" rel=\"noopener noreferrer\">Kod \u017ar\u00f3d\u0142owy WordPress 7.1.2: wp-includes\/meta.php<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/WordPress\/wordpress-develop\/blob\/7.1.2\/src\/wp-includes\/class-wp-roles.php\" target=\"_blank\" rel=\"noopener noreferrer\">Kod \u017ar\u00f3d\u0142owy WordPress 7.1.2: class-wp-roles.php<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/WordPress\/wordpress-develop\/blob\/7.1.2\/src\/wp-includes\/cron.php\" target=\"_blank\" rel=\"noopener noreferrer\">Kod \u017ar\u00f3d\u0142owy WordPress 7.1.2: wp-includes\/cron.php<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/WordPress\/wordpress-develop\/blob\/7.1.2\/src\/wp-includes\/ms-site.php\" target=\"_blank\" rel=\"noopener noreferrer\">Kod \u017ar\u00f3d\u0142owy WordPress 7.1.2: wp-includes\/ms-site.php<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/WordPress\/wordpress-develop\/blob\/7.1.2\/src\/wp-includes\/ms-default-filters.php\" target=\"_blank\" rel=\"noopener noreferrer\">Kod \u017ar\u00f3d\u0142owy WordPress 7.1.2: ms-default-filters.php<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/WordPress\/wordpress-develop\/blob\/7.1.2\/src\/wp-includes\/ms-functions.php\" target=\"_blank\" rel=\"noopener noreferrer\">Kod \u017ar\u00f3d\u0142owy WordPress 7.1.2: ms-functions.php<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/WordPress\/wordpress-develop\/blob\/7.1.2\/src\/wp-includes\/capabilities.php\" target=\"_blank\" rel=\"noopener noreferrer\">Kod \u017ar\u00f3d\u0142owy WordPress 7.1.2: capabilities.php<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/WordPress\/wordpress-develop\/blob\/7.1.2\/src\/wp-includes\/class-wpdb.php\" target=\"_blank\" rel=\"noopener noreferrer\">Kod \u017ar\u00f3d\u0142owy WordPress 7.1.2: class-wpdb.php<\/a><\/li>\n<li><a href=\"https:\/\/developer.wordpress.org\/cli\/commands\/plugin\/uninstall\/\" target=\"_blank\" rel=\"noopener noreferrer\">WP-CLI: wp plugin uninstall<\/a><\/li>\n<li><a href=\"https:\/\/developer.wordpress.org\/cli\/commands\/plugin\/delete\/\" target=\"_blank\" rel=\"noopener noreferrer\">WP-CLI: wp plugin delete<\/a><\/li>\n<li><a href=\"https:\/\/developer.wordpress.org\/cli\/commands\/site\/option\/update\/\" target=\"_blank\" rel=\"noopener noreferrer\">WP-CLI: wp site option update<\/a><\/li>\n<\/ul>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Hooki aktywacji pomijaj\u0105 aktualizacje, aktywacja sieciowa dzia\u0142a raz, a uninstall.php uruchamia si\u0119 bez pliku g\u0142\u00f3wnego. Kompletna przyk\u0142adowa wtyczka pokazuje wszystkie trzy fazy.<\/p>\n","protected":false},"author":1,"featured_media":20933,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[25],"tags":[92262,92280,92286],"class_list":["post-20877","post","type-post","status-publish","format-standard","hentry","category-wordpress-plugins-tricks-pl","tag-mysql-pl","tag-php-pl","tag-wordpress-pl"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Cykl \u017cycia wtyczki: aktywacja, dezaktywacja, odinstalowanie | Lukas Wojcik<\/title>\n<meta name=\"description\" content=\"Cykl \u017cycia wtyczki WordPress: tabela z dbDelta i wersjonowan\u0105 migracj\u0105, cron, capabilities oraz uninstall.php ze zgod\u0105 opt-in, gotowy na Multisite.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.lukaswojcik.com\/blog\/pl\/wordpress-plugins-tricks-pl\/cykl-zycia-wtyczki-odinstalowanie\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Cykl \u017cycia wtyczki: aktywacja, dezaktywacja, odinstalowanie | Lukas Wojcik\" \/>\n<meta property=\"og:description\" content=\"Cykl \u017cycia wtyczki WordPress: tabela z dbDelta i wersjonowan\u0105 migracj\u0105, cron, capabilities oraz uninstall.php ze zgod\u0105 opt-in, gotowy na Multisite.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.lukaswojcik.com\/blog\/pl\/wordpress-plugins-tricks-pl\/cykl-zycia-wtyczki-odinstalowanie\/\" \/>\n<meta property=\"og:site_name\" content=\"Lukas Wojcik - Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-10-12T18:48:00+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/09\/fi-20877-cykl-zycia-wtyczki-odinstalowanie.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"630\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Lukas Wojcik\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Lukas Wojcik\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"22 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/wordpress-plugins-tricks-pl\\\/cykl-zycia-wtyczki-odinstalowanie\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/wordpress-plugins-tricks-pl\\\/cykl-zycia-wtyczki-odinstalowanie\\\/\"},\"author\":{\"name\":\"Lukas Wojcik\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\"},\"headline\":\"Cykl \u017cycia wtyczki: aktywacja, dezaktywacja, odinstalowanie\",\"datePublished\":\"2026-10-12T18:48:00+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/wordpress-plugins-tricks-pl\\\/cykl-zycia-wtyczki-odinstalowanie\\\/\"},\"wordCount\":2582,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\"},\"image\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/wordpress-plugins-tricks-pl\\\/cykl-zycia-wtyczki-odinstalowanie\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/09\\\/fi-20877-cykl-zycia-wtyczki-odinstalowanie.png\",\"keywords\":[\"MySQL\",\"PHP\",\"WordPress\"],\"articleSection\":[\"Wtyczki i triki WordPress\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/wordpress-plugins-tricks-pl\\\/cykl-zycia-wtyczki-odinstalowanie\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/wordpress-plugins-tricks-pl\\\/cykl-zycia-wtyczki-odinstalowanie\\\/\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/wordpress-plugins-tricks-pl\\\/cykl-zycia-wtyczki-odinstalowanie\\\/\",\"name\":\"Cykl \u017cycia wtyczki: aktywacja, dezaktywacja, odinstalowanie | Lukas Wojcik\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/wordpress-plugins-tricks-pl\\\/cykl-zycia-wtyczki-odinstalowanie\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/wordpress-plugins-tricks-pl\\\/cykl-zycia-wtyczki-odinstalowanie\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/09\\\/fi-20877-cykl-zycia-wtyczki-odinstalowanie.png\",\"datePublished\":\"2026-10-12T18:48:00+00:00\",\"description\":\"Cykl \u017cycia wtyczki WordPress: tabela z dbDelta i wersjonowan\u0105 migracj\u0105, cron, capabilities oraz uninstall.php ze zgod\u0105 opt-in, gotowy na Multisite.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/wordpress-plugins-tricks-pl\\\/cykl-zycia-wtyczki-odinstalowanie\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/wordpress-plugins-tricks-pl\\\/cykl-zycia-wtyczki-odinstalowanie\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/wordpress-plugins-tricks-pl\\\/cykl-zycia-wtyczki-odinstalowanie\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/09\\\/fi-20877-cykl-zycia-wtyczki-odinstalowanie.png\",\"contentUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/09\\\/fi-20877-cykl-zycia-wtyczki-odinstalowanie.png\",\"width\":1200,\"height\":630,\"caption\":\"Cykl \u017cycia wtyczki: aktywacja, dezaktywacja, odinstalowanie\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/wordpress-plugins-tricks-pl\\\/cykl-zycia-wtyczki-odinstalowanie\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Cykl \u017cycia wtyczki: aktywacja, dezaktywacja, odinstalowanie\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/\",\"name\":\"Lukas Wojcik - Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\",\"name\":\"Lukas Wojcik\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"contentUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"width\":424,\"height\":636,\"caption\":\"Lukas Wojcik\"},\"logo\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\"},\"sameAs\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Cykl \u017cycia wtyczki: aktywacja, dezaktywacja, odinstalowanie | Lukas Wojcik","description":"Cykl \u017cycia wtyczki WordPress: tabela z dbDelta i wersjonowan\u0105 migracj\u0105, cron, capabilities oraz uninstall.php ze zgod\u0105 opt-in, gotowy na Multisite.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.lukaswojcik.com\/blog\/pl\/wordpress-plugins-tricks-pl\/cykl-zycia-wtyczki-odinstalowanie\/","og_locale":"en_US","og_type":"article","og_title":"Cykl \u017cycia wtyczki: aktywacja, dezaktywacja, odinstalowanie | Lukas Wojcik","og_description":"Cykl \u017cycia wtyczki WordPress: tabela z dbDelta i wersjonowan\u0105 migracj\u0105, cron, capabilities oraz uninstall.php ze zgod\u0105 opt-in, gotowy na Multisite.","og_url":"https:\/\/www.lukaswojcik.com\/blog\/pl\/wordpress-plugins-tricks-pl\/cykl-zycia-wtyczki-odinstalowanie\/","og_site_name":"Lukas Wojcik - Blog","article_published_time":"2026-10-12T18:48:00+00:00","og_image":[{"width":1200,"height":630,"url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/09\/fi-20877-cykl-zycia-wtyczki-odinstalowanie.png","type":"image\/png"}],"author":"Lukas Wojcik","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Lukas Wojcik","Est. reading time":"22 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.lukaswojcik.com\/blog\/pl\/wordpress-plugins-tricks-pl\/cykl-zycia-wtyczki-odinstalowanie\/#article","isPartOf":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/pl\/wordpress-plugins-tricks-pl\/cykl-zycia-wtyczki-odinstalowanie\/"},"author":{"name":"Lukas Wojcik","@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9"},"headline":"Cykl \u017cycia wtyczki: aktywacja, dezaktywacja, odinstalowanie","datePublished":"2026-10-12T18:48:00+00:00","mainEntityOfPage":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/pl\/wordpress-plugins-tricks-pl\/cykl-zycia-wtyczki-odinstalowanie\/"},"wordCount":2582,"commentCount":0,"publisher":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9"},"image":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/pl\/wordpress-plugins-tricks-pl\/cykl-zycia-wtyczki-odinstalowanie\/#primaryimage"},"thumbnailUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/09\/fi-20877-cykl-zycia-wtyczki-odinstalowanie.png","keywords":["MySQL","PHP","WordPress"],"articleSection":["Wtyczki i triki WordPress"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.lukaswojcik.com\/blog\/pl\/wordpress-plugins-tricks-pl\/cykl-zycia-wtyczki-odinstalowanie\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.lukaswojcik.com\/blog\/pl\/wordpress-plugins-tricks-pl\/cykl-zycia-wtyczki-odinstalowanie\/","url":"https:\/\/www.lukaswojcik.com\/blog\/pl\/wordpress-plugins-tricks-pl\/cykl-zycia-wtyczki-odinstalowanie\/","name":"Cykl \u017cycia wtyczki: aktywacja, dezaktywacja, odinstalowanie | Lukas Wojcik","isPartOf":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/pl\/wordpress-plugins-tricks-pl\/cykl-zycia-wtyczki-odinstalowanie\/#primaryimage"},"image":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/pl\/wordpress-plugins-tricks-pl\/cykl-zycia-wtyczki-odinstalowanie\/#primaryimage"},"thumbnailUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/09\/fi-20877-cykl-zycia-wtyczki-odinstalowanie.png","datePublished":"2026-10-12T18:48:00+00:00","description":"Cykl \u017cycia wtyczki WordPress: tabela z dbDelta i wersjonowan\u0105 migracj\u0105, cron, capabilities oraz uninstall.php ze zgod\u0105 opt-in, gotowy na Multisite.","breadcrumb":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/pl\/wordpress-plugins-tricks-pl\/cykl-zycia-wtyczki-odinstalowanie\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.lukaswojcik.com\/blog\/pl\/wordpress-plugins-tricks-pl\/cykl-zycia-wtyczki-odinstalowanie\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.lukaswojcik.com\/blog\/pl\/wordpress-plugins-tricks-pl\/cykl-zycia-wtyczki-odinstalowanie\/#primaryimage","url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/09\/fi-20877-cykl-zycia-wtyczki-odinstalowanie.png","contentUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/09\/fi-20877-cykl-zycia-wtyczki-odinstalowanie.png","width":1200,"height":630,"caption":"Cykl \u017cycia wtyczki: aktywacja, dezaktywacja, odinstalowanie"},{"@type":"BreadcrumbList","@id":"https:\/\/www.lukaswojcik.com\/blog\/pl\/wordpress-plugins-tricks-pl\/cykl-zycia-wtyczki-odinstalowanie\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.lukaswojcik.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Cykl \u017cycia wtyczki: aktywacja, dezaktywacja, odinstalowanie"}]},{"@type":"WebSite","@id":"https:\/\/www.lukaswojcik.com\/blog\/#website","url":"https:\/\/www.lukaswojcik.com\/blog\/","name":"Lukas Wojcik - Blog","description":"","publisher":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.lukaswojcik.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9","name":"Lukas Wojcik","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","contentUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","width":424,"height":636,"caption":"Lukas Wojcik"},"logo":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg"},"sameAs":["https:\/\/www.lukaswojcik.com\/blog"]}]}},"_links":{"self":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/posts\/20877","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/comments?post=20877"}],"version-history":[{"count":2,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/posts\/20877\/revisions"}],"predecessor-version":[{"id":21843,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/posts\/20877\/revisions\/21843"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/media\/20933"}],"wp:attachment":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/media?parent=20877"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/categories?post=20877"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/tags?post=20877"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}