{"id":229568,"date":"2022-11-23T15:30:00","date_gmt":"2022-11-23T12:30:00","guid":{"rendered":"https:\/\/wordpress.mediadoma.com\/?p=229568"},"modified":"2022-11-09T08:30:33","modified_gmt":"2022-11-09T05:30:33","slug":"praca-z-klasami-szablonami-i-czesciami-w-wordpress","status":"publish","type":"post","link":"https:\/\/wordpress.mediadoma.com\/pl\/praca-z-klasami-szablonami-i-czesciami-w-wordpress\/","title":{"rendered":"Praca z klasami, szablonami i cz\u0119\u015bciami w WordPress"},"content":{"rendered":"\n<p>Kiedy usiad\u0142em, \u017ceby zacz\u0105\u0107 ten post, planowa\u0142em napisa\u0107 co\u015b o wiele bardziej zaanga\u017cowanego ni\u017c to, czym zamierzam si\u0119 podzieli\u0107. Pocz\u0105tkowo chcia\u0142em przej\u015b\u0107 przez jedn\u0105 z dw\u00f3ch rzeczy:<\/p>\n<ul>\n<li>Kompletny przewodnik po konfigurowaniu \u015brodowiska programistycznego,<\/li>\n<li>Integracja narz\u0119dzi jako\u015bci kodu z PhpStorm<\/li>\n<\/ul>\n<p>Pierwszym z nich by\u0142oby skupienie si\u0119 na wielu innych rzeczach, o kt\u00f3rych m\u00f3wi\u0142em, powi\u0105zanie ich wszystkich razem i posiadanie ostatecznego odniesienia. Ale to jest co\u015b, na co chcia\u0142bym po\u015bwi\u0119ci\u0107 troch\u0119 czasu, aby upewni\u0107 si\u0119, \u017ce jest zrobione dobrze.<\/p>\n<p>Drugi to taki, kt\u00f3ry uwa\u017cam za wa\u017cny, ale jestem w fazie przej\u015bciowej z niekt\u00f3rymi moimi w\u0142asnymi narz\u0119dziami. Dop\u00f3ki tego nie zrobi\u0119, wola\u0142bym o tym nie pisa\u0107.<\/p>\n<p>Mimo to zawsze jest co\u015b do ukrycia, prawda? Wi\u0119c dzisiaj zdecydowa\u0142em si\u0119 na co\u015b prostszego: rozbicie u\u017cycia klas, szablon\u00f3w i podszablon\u00f3w we wtyczkach WordPress na prostym przyk\u0142adzie.<\/p>\n<h2>Klasy, szablony i cz\u0119\u015bci w WordPress<\/h2>\n<p>W przypadku tego konkretnego tematu, natychmiastowe pytanie, kt\u00f3re mo\u017ce przyj\u015b\u0107 do g\u0142owy, jest proste: po co zawraca\u0107 sobie g\u0142ow\u0119 m\u00f3wieniem o tym?<\/p>\n<p>Poniewa\u017c jest rok 2018 i wci\u0105\u017c widzimy mieszank\u0119 PHP, CSS, znacznik\u00f3w i JavaScript w jednym pliku. Nie chodzi o to, aby uderza\u0107 w inne technologie, kt\u00f3re domy\u015blnie to robi\u0105 (takie jak React). M\u00f3wi\u0119 konkretnie o wtyczkach do WordPressa i pisaniu mo\u017cliwego do utrzymania kodu w taki spos\u00f3b, aby [oczywi\u015bcie] by\u0142 \u0142atwy w utrzymaniu, pisaniu i czytaniu.<\/p>\n<h3>Praktyczny przyk\u0142ad<\/h3>\n<p>Za\u0142\u00f3\u017cmy, \u017ce pracujesz nad stron\u0105 podmenu dotycz\u0105c\u0105 czego\u015b, co ma si\u0119 pojawi\u0107 w menu niestandardowym. <a href=\"https:\/\/gist.github.com\/tommcfarlin\/f72e1444fb01cff19de2c58f0aacab34#file-00-addmenupage-php\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">Rejestrujesz swoj\u0105 stron\u0119<\/a> za pomoc\u0105 API WordPress:<\/p>\n<pre><code>&lt;?php\n\npublic function addMenuPage()\n{\n    add_menu_page(\n      'Acme Menu',\n      'Acme Menu',\n      'manage_options',\n      'acme-custom-menu',\n      array($this, 'display'),\n      'dashicons-dashboard',\n      30\n    );\n\n    add_submenu_page(\n      'acme-custom-menu',\n      'Acme Menu',\n      'Acme Menu',\n      'Acme Menu',\n      'acme-custom-menu',\n      array($this, 'display')\n    );\n}\n<\/code><\/pre>\n<p>Ale kiedy konfigurujesz funkcj\u0119 wywo\u0142ania zwrotnego do wy\u015bwietlania strony, <strong>nie<\/strong> u\u017cywasz tej funkcji do mieszania wszystkich r\u00f3\u017cnych j\u0119zyk\u00f3w. Zamiast tego u\u017cywasz go do <strong><a href=\"https:\/\/gist.github.com\/tommcfarlin\/f72e1444fb01cff19de2c58f0aacab34#file-01-display-php\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">do\u0142\u0105czenia pliku.<\/a><\/strong><\/p>\n<pre><code>&lt;?php\n\npublic function display()\n{\n    include_once $this-&gt;pluginPath. 'views\/acme-settings.php';\n}\n<\/code><\/pre>\n<p>Zauwa\u017c, \u017ce w powy\u017cszym pliku odwo\u0142uj\u0119 si\u0119 do w\u0142a\u015bciwo\u015bci <strong>$this-&gt;pluginPath<\/strong>. Jest to ustawiane w konstruktorze klasy, dzi\u0119ki czemu mog\u0119 \u0142atwo uzyska\u0107 dost\u0119p do katalogu g\u0142\u00f3wnego wtyczki.<\/p>\n<p>Zreszt\u0105, jak mo\u017ce wygl\u0105da\u0107 ten plik?<\/p>\n<h3>Szablon i cz\u0119\u015bciowe<\/h3>\n<p>W tym przypadku zak\u0142adam, \u017ce Tw\u00f3j szablon ma dostarczy\u0107 informacji u\u017cytkownikowi i b\u0119dzie prosi\u0107 o jego wprowadzenie. Cz\u0119\u015b\u0107 b\u0119dzie odpowiedzialna za wy\u015bwietlanie u\u017cytkownikowi komunikatu o sukcesie, b\u0142\u0119dzie lub ostrze\u017cenie.<\/p>\n<h4>Szablon<\/h4>\n<p>Aby by\u0142o to proste, staram si\u0119, aby zar\u00f3wno szablon, jak i podszablony by\u0142y jak najszczuplejsze. W tym przypadku za\u0142\u00f3\u017cmy, \u017ce wyrenderujemy stron\u0119, poprosimy u\u017cytkownika o zapisanie warto\u015bci, a je\u015bli warto\u015b\u0107 zostanie pomy\u015blnie zapisana (i dlatego istnieje w tabeli <strong>wp_options<\/strong> ), wy\u015bwietlimy komunikat o powodzeniu.<\/p>\n<p>To znaczy:<\/p>\n<ul>\n<li>szablon wy\u015bwietli tytu\u0142 strony, informacje, dane wej\u015bciowe i przycisk zapisu,<\/li>\n<li>w razie potrzeby cz\u0119\u015bciowy wy\u015bwietli komunikat o powodzeniu.<\/li>\n<\/ul>\n<p>Sp\u00f3jrz na kod <strong><a href=\"https:\/\/gist.github.com\/tommcfarlin\/f72e1444fb01cff19de2c58f0aacab34#file-02-acme-settings-php\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">szablonu poni\u017cej:<\/a><\/strong><\/p>\n<pre><code>&lt;?php\n\/**\n * Renders the settings page for the plugin.\n *\/\n?&gt;\n&lt;div class=\"wrap\"&gt;\n    &lt;h1 class=\"wp-heading-inline\"&gt;&lt;?php echo get_admin_page_title(); ?&gt;&lt;\/h1&gt;\n    &lt;?php if ($this-&gt;showSuccessMessage()) { ?&gt;\n      &lt;?php include_once 'partials\/settings-saved.php'; ?&gt;\n    ?&gt;\n    &lt;div id=\"acme-settings-schedule\"&gt;\n        &lt;form id=\"acme-form\" method=\"post\" action=\"&lt;?php echo esc_html(admin_url('admin-post.php')); ?&gt;\"\"&gt;\n            &lt;!-- This is where your settings go. --&gt;\n            &lt;p&gt;\n                &lt;?php\n                submit_button(\n                    'Save',\n                    'primary',\n                    'acme-save-settings',\n                    false\n                );\n                wp_nonce_field(\n                    'acme-save',\n                    'acme-save-nonce'\n                );\n                ?&gt;\n            &lt;\/p&gt;\n        &lt;\/form&gt;\n    &lt;\/div&gt;\n&lt;\/div&gt;\n<\/code><\/pre>\n<p>Zauwa\u017c, \u017ce tak, ma wej\u015bcie, przycisk zapisywania i jednorazowy, z kt\u00f3rych wszystkie s\u0105 wa\u017cne (ale wykraczaj\u0105 poza zakres tego postu) do zapisywania informacji.<\/p>\n<p>Ale zauwa\u017c, \u017ce ma funkcj\u0119 pomocnicz\u0105, kt\u00f3rej u\u017cywam do sprawdzania obecno\u015bci pomy\u015blnego zapisywania informacji. Ta funkcja znajduje si\u0119 w tej samej klasie, kt\u00f3ra odpowiada za renderowanie szablonu.<\/p>\n<h4>Cz\u0119\u015bciowy<\/h4>\n<p>Wygl\u0105da to mniej wi\u0119cej <strong><a href=\"https:\/\/gist.github.com\/tommcfarlin\/f72e1444fb01cff19de2c58f0aacab34#file-03-showsuccessmessage-php\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">tak:<\/a><\/strong><\/p>\n<pre><code>&lt;?php\n\npublic function showSuccessMessage()\n{\n  return (false !== get_option('acme_custom_setting'));\n}\n<\/code><\/pre>\n<p>Wynikowa cz\u0119\u015bciowa jest <strong><a href=\"https:\/\/gist.github.com\/tommcfarlin\/f72e1444fb01cff19de2c58f0aacab34#file-04-settings-saved-php\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">bardzo prosta:<\/a><\/strong><\/p>\n<pre><code>&lt;?php\n\/**\n * Renders the success message if the option has been properly saved.\n *\/\n?&gt;\n\n&lt;div class=\"notice-success notice is-dismissible\"&gt;\n    &lt;p&gt;Your settings have been successfully saved.&lt;\/p&gt;\n    &lt;button type=\"button\" class=\"notice-dismiss\"&gt;\n        &lt;span class=\"screen-reader-text\"&gt;Dismiss this notice.&lt;\/span&gt;\n    &lt;\/button&gt;\n&lt;\/div&gt;\n<\/code><\/pre>\n<p>Oczywi\u015bcie twoja implementacja funkcji mo\u017ce si\u0119 r\u00f3\u017cni\u0107. Celem nie jest pokazanie, jak zaimplementowa\u0107 funkcj\u0119, ale jak wykorzysta\u0107 funkcj\u0119 do sprawdzania informacji w celu wy\u015bwietlenia cz\u0119\u015bci.<\/p>\n<h2>Jest wi\u0119cej (ale nie tutaj)<\/h2>\n<p>Mo\u017ce to jest co\u015b, co nale\u017cy umie\u015bci\u0107 na pocz\u0105tku artyku\u0142u.<\/p>\n<p>Szczerze m\u00f3wi\u0105c, my\u015bl\u0119, \u017ce jest to jedna z tych rzeczy, w kt\u00f3rych niekt\u00f3rzy mog\u0105 uzna\u0107, \u017ce bardziej pomocne mo\u017ce by\u0107 zobaczenie tego od samego pocz\u0105tku (ale potem brak kontekstu kodu), a inni uznaj\u0105 to za bardziej przydatne na ko\u0144cu, poniewa\u017c widz\u0105, jak to wszystko pasuje razem.<\/p>\n<p>Niezale\u017cnie od tego mam nadziej\u0119, \u017ce ostatecznie wyja\u015bni to, jak to wszystko do siebie pasuje.<\/p>\n<p>Co wi\u0119cej, jest du\u017co miejsca na takie rzeczy, kt\u00f3re mo\u017cna dostosowa\u0107, takie jak:<\/p>\n<ul>\n<li>sprawdzenie, czy u\u017cytkownik ma uprawnienia do zapisywania,<\/li>\n<li>weryfikacja warto\u015bci nonce,<\/li>\n<li>sanityzacja i walidacja danych,<\/li>\n<li>okre\u015bli\u0107, co stanowi sukces, ostrze\u017cenia i b\u0142\u0119dy.<\/li>\n<\/ul>\n<p>Ale je\u015bli mam om\u00f3wi\u0107 wszystkie powy\u017csze, patrzymy na wyj\u0105tkowo d\u0142ugi post lub d\u0142ug\u0105 seri\u0119 post\u00f3w. To nie jest co\u015b, przeciwko czemu jestem przeciwny, ale jest to r\u00f3wnie\u017c co\u015b, czego teraz nie robi\u0119, jest warte wysi\u0142ku w tym momencie.<\/p>\n<p>Nigdy nie wahaj si\u0119 przekaza\u0107 opinii. Ale w mi\u0119dzyczasie mam nadziej\u0119, \u017ce to wszystko pomo\u017ce ci stworzy\u0107 fundament, na kt\u00f3rym mo\u017cesz budowa\u0107 podczas pracy nad nast\u0119pnym projektem.<\/p>\n<p><div id=\"PostUnique_PostSource\" style=\"padding-top: 50px\">\u0179r\u00f3d\u0142o nagrywania:  <a target=\"_blank\" rel=\"noopener nofollow\" href=\"\/\/tommcfarlin.com\" class=\"external external_icon\">tommcfarlin.com<\/a><\/div><\/p>\n","protected":false},"excerpt":{"rendered":"<p>W tym po\u015bcie rozbijam u\u017cycie klas, szablon\u00f3w i podszablon\u00f3w we wtyczkach WordPress na prostym przyk\u0142adzie.<\/p>\n","protected":false},"author":1,"featured_media":164763,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","_wp_rev_ctl_limit":""},"categories":[721,805,845,866],"tags":[1169],"class_list":["post-229568","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-deweloper","category-php-7","category-samouczki","category-wordpress-7","tag-affiai-pl"],"_links":{"self":[{"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/posts\/229568","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/comments?post=229568"}],"version-history":[{"count":0,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/posts\/229568\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/media\/164763"}],"wp:attachment":[{"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/media?parent=229568"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/categories?post=229568"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/tags?post=229568"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}