{"id":228106,"date":"2022-10-13T20:35:00","date_gmt":"2022-10-13T17:35:00","guid":{"rendered":"https:\/\/wordpress.mediadoma.com\/?p=228106"},"modified":"2022-11-09T00:45:02","modified_gmt":"2022-11-08T21:45:02","slug":"tworzenie-niestandardowej-kontroli-selektora-laczy-cmb2-dla-wordpress","status":"publish","type":"post","link":"https:\/\/wordpress.mediadoma.com\/pl\/tworzenie-niestandardowej-kontroli-selektora-laczy-cmb2-dla-wordpress\/","title":{"rendered":"Tworzenie niestandardowej kontroli selektora \u0142\u0105czy CMB2 dla WordPress"},"content":{"rendered":"\n<p>W tym samouczku przyjrz\u0119 si\u0119, jak utworzy\u0107 niestandardow\u0105 kontrolk\u0119, aby rozszerzy\u0107 funkcjonalno\u015b\u0107 <a href=\"https:\/\/wordpress.org\/plugins\/cmb2\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">CMB2<\/a> (Custom Meta Boxes 2) przez <a href=\"https:\/\/webdevstudios.com\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">WebDevStudios<\/a>.<\/p>\n<p>Tworz\u0119 strony internetowe (i aplikacje internetowe) za pomoc\u0105 CMS <a href=\"https:\/\/wordpress.org\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">WordPress<\/a> (system zarz\u0105dzania tre\u015bci\u0105), a kiedy trafi nowy projekt, mo\u017cesz zagwarantowa\u0107, \u017ce b\u0119dzie wymaga\u0142 ode mnie opracowania \u201eNiestandardowych skrzynek meta&quot;, aby umo\u017cliwi\u0107 u\u017cytkownikowi pe\u0142n\u0105 kontrol\u0119 nad zawarto\u015bci\u0105 i uk\u0142adem witryn.<\/p>\n<p>Opisz\u0119 szczeg\u00f3\u0142owo, w jaki spos\u00f3b zbudowa\u0142em kontrolk\u0119 CMB2 <a href=\"https:\/\/en-gb.wordpress.org\/plugins\/link-picker-for-cmb2\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">Link Picker dla CMB2<\/a> (dost\u0119pn\u0105 we wszystkich dobrych repozytoriach wtyczek WordPress). Zrzut ekranu mo\u017cna zobaczy\u0107 poni\u017cej.<\/p>\n<p>Sterowanie CMB2 \u201eLink Picker&#8221; w akcji<\/p>\n<p>Selektor link\u00f3w uruchamia wbudowane okno dialogowe \u201eWstaw\/edytuj link&#8221; WordPress po klikni\u0119ciu przycisku \u201eWybierz&#8221;. Wida\u0107 to na poni\u017cszym zrzucie ekranu:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/wordpress.mediadoma.com\/wp-content\/uploads\/2022\/01\/post-169316-61e80b39277e2.png\" alt=\"Tworzenie niestandardowej kontroli selektora \u0142\u0105czy CMB2 dla WordPress\" \/>Naci\u015bni\u0119cie przycisku pozwala wybra\u0107 link (lub doda\u0107 w\u0142asny)<\/p>\n<p>Jestem pewien, \u017ce zgodzisz si\u0119, \u017ce taka kontrola jest niezwykle przydatna, je\u015bli chcesz da\u0107 redaktorom swojej witryny mo\u017cliwo\u015b\u0107 dodawania link\u00f3w, a tak\u017ce przeszukiwania WordPress pod k\u0105tem wewn\u0119trznych link\u00f3w, zamiast wycinania i wklejania link\u00f3w do linku pole.<\/p>\n<h2>Wst\u0119p \/ Historia<\/h2>\n<p>Dla tych, kt\u00f3rzy nie wiedz\u0105, metabox znajduje si\u0119 na ekranie edytora posta WordPress i prawdopodobnie b\u0119dzie zawiera\u0142 r\u00f3\u017cne kontrolki formularzy (pola tekstowe, listy rozwijane, pola wyboru itp.). Te kontrolki umo\u017cliwiaj\u0105 u\u017cytkownikom Twojej witryny \u0142atw\u0105 zmian\u0119 niestandardowego fragmentu tekstu lub funkcji w witrynie.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/wordpress.mediadoma.com\/wp-content\/uploads\/2022\/01\/post-169316-61e80b39277e2.png\" alt=\"Tworzenie niestandardowej kontroli selektora \u0142\u0105czy CMB2 dla WordPress\" \/><img decoding=\"async\" src=\"https:\/\/wordpress.mediadoma.com\/wp-content\/uploads\/2022\/01\/post-169316-61e80b3a6c2f7.png\" alt=\"Tworzenie niestandardowej kontroli selektora \u0142\u0105czy CMB2 dla WordPress\" \/>Przyk\u0142ad meta pola z r\u00f3\u017cnymi kontrolkami formularza<\/p>\n<p>WordPress pozwala tworzy\u0107 metaboxy za pomoc\u0105 funkcji (takich jak <code>[add_meta_box](https:\/\/developer.wordpress.org\/reference\/functions\/add_meta_box\/)<\/code>), ale tworzenie metabox\u00f3w w ten spos\u00f3b mo\u017ce by\u0107 d\u0142ugotrwa\u0142ym procesem z du\u017c\u0105 ilo\u015bci\u0105 powt\u00f3rze\u0144 kodu (zw\u0142aszcza je\u015bli chcesz u\u017cywa\u0107 tych samych kontrolek formularza w wielu projektach).<\/p>\n<h2>Dlaczego CMB2?<\/h2>\n<p>Niekt\u00f3rzy z was mogli s\u0142ysze\u0107 o <a href=\"https:\/\/www.advancedcustomfields.com\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">zaawansowanych polach niestandardowych<\/a> (ACF), kt\u00f3re zapewniaj\u0105 GUI (graficzny interfejs u\u017cytkownika), kt\u00f3ry pozwala tworzy\u0107 meta pola bezpo\u015brednio za pomoc\u0105 WordPressa.<\/p>\n<p>ACF moim zdaniem <strong>nie jest \u015bwietnym narz\u0119dziem<\/strong> do skalowania jakiegokolwiek rozwi\u0105zania webowego. Wtyczka zbytnio polega na danych przechowywanych w bazie danych. Powoduje to b\u00f3l podczas wdra\u017cania zmian w witrynie, poniewa\u017c nie mo\u017cna po prostu przes\u0142a\u0107 kodu i natychmiast zobaczy\u0107 zmiany. Zamiast tego musisz ponownie wykona\u0107 prac\u0119 w r\u00f3\u017cnych \u015brodowiskach wdro\u017ceniowych (staging, live itp.). Potrzebowali\u015bmy wi\u0119c rozwi\u0105zania, kt\u00f3re pozwoli nam programowo tworzy\u0107 metaboxy. Wpisz CMB2.<\/p>\n<p>Zanim przyj\u0119li\u015bmy CMB2, wcze\u015bniej u\u017cywali\u015bmy <a href=\"https:\/\/github.com\/humanmade\/Custom-Meta-Boxes\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">HM Custom Meta Boxes<\/a> od tych uroczych ludzi z <a href=\"https:\/\/hmn.md\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">Human Made<\/a> (kt\u00f3ra zacz\u0119\u0142a si\u0119 jako rozwidlenie poprzednika WebDevStudio do CMB2, \u201eCustom Meta Boxes&#8221;).<\/p>\n<p>Uwielbiali\u015bmy HM Custom Meta Boxes, a dzi\u0119ki najprostszym fragmentom kodu mogli\u015bmy szybko stworzy\u0107 niestandardowe Meta Boxy, aby zrobi\u0107 prawie wszystko!<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/wordpress.mediadoma.com\/wp-content\/uploads\/2022\/01\/post-169316-61e80b3c08039.png\" alt=\"Tworzenie niestandardowej kontroli selektora \u0142\u0105czy CMB2 dla WordPress\" \/>Przyk\u0142ad HM Custom Meta Boxes Markup (to jest oznaczenie dla Instagram Meta Box na pierwszym zrzucie ekranu)<\/p>\n<p>Dlaczego wi\u0119c przej\u015bcie na CMB2? C\u00f3\u017c, HM Custom Meta Boxes niestety nie cieszy\u0142 si\u0119 zbytni\u0105 sympati\u0105 (rozmawia\u0142em z jego g\u0142\u00f3wnym deweloperem i jest on bardzo zaj\u0119tym cz\u0142owiekiem), podczas gdy CMB2 posuwa\u0142 si\u0119 naprz\u00f3d z nowymi funkcjami, nowymi kontrolkami i zyska\u0142 na popularno\u015bci w spo\u0142eczno\u015bci WordPress z wieloma osobami, kt\u00f3re j\u0105 adoptuj\u0105 i wydaj\u0105 wtyczki, aby j\u0105 rozszerzy\u0107 (w tym kilka naszych agencji partnerskich).<\/p>\n<p>Wreszcie, jak mo\u017cna si\u0119 domy\u015bli\u0107, praca z CMB2 jest tak niewiarygodnie prosta, jak do tego przywykli\u015bmy, poniewa\u017c obie platformy maj\u0105 wsp\u00f3lnego przodka.<\/p>\n<h2>Instrukta\u017c<\/h2>\n<p>Zanim zaczniemy, ka\u017cdy ma sw\u00f3j w\u0142asny zestaw idea\u0142\u00f3w dotycz\u0105cych tworzenia wtyczki WordPress, a ja wypr\u00f3bowa\u0142em sporo, jednak samouczek na temat \u201e <a href=\"https:\/\/tomjn.com\/2015\/06\/24\/root-composition-in-wordpress-plugins\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">Kompozycja korzenia w WordPressie<\/a> &#8221; autorstwa Toma J Nowella ca\u0142kowicie zmieni\u0142 spos\u00f3b, w jaki pracuj\u0119. Uwa\u017cam, \u017ce jego podej\u015bcie jest czyste, proste i sprawia, \u017ce \u200b\u200b\u200b\u200bprzysz\u0142a konserwacja dowolnej wtyczki jest \u0142atwa. Je\u015bli <a href=\"https:\/\/wordpress.org\/plugins\/link-picker-for-cmb2\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">pobierzesz \u017ar\u00f3d\u0142o wtyczki Link Picker for CMB2<\/a>, mo\u017cesz zobaczy\u0107 metody, kt\u00f3rych naucza w praktyce.<\/p>\n<h3>Budowanie formy<\/h3>\n<p>Aby zbudowa\u0107 formularz, kt\u00f3ry renderuje selektor link\u00f3w, pierwsz\u0105 rzecz\u0105, kt\u00f3r\u0105 musimy zrobi\u0107, jest zaczepienie si\u0119 o <code>cmb2_render_[control_name]<\/code>akcj\u0119. Jak nazwa\u0142em t\u0119 kontrolk\u0119 \u201elink_picker&#8221;, mo\u017cemy uzupe\u0142ni\u0107 podpi\u0119cie w nast\u0119puj\u0105cy spos\u00f3b:<\/p>\n<pre><code>&lt;?php\nadd_action( 'cmb2_render_link_picker', array( $this, 'cmb2_render_link_picker' ), 10, 5 );\n`\n<\/code><\/pre>\n<p>Dla tych z Was, kt\u00f3rzy tak naprawd\u0119 nie rozumiej\u0105 <code>add_action<\/code>haka, dzia\u0142a to w nast\u0119puj\u0105cy spos\u00f3b:<\/p>\n<ol>\n<li>Pierwszym argumentem <code>cmb2_render_link_picker<\/code>jest nazwa haka, do kt\u00f3rego chcemy si\u0119 pod\u0142\u0105czy\u0107.<\/li>\n<li>Drugim argumentem <code>array( $this, 'cmb2_render_link_picker' )<\/code>jest funkcja, kt\u00f3r\u0105 chcemy wywo\u0142a\u0107 po uruchomieniu tego podpi\u0119cia. Zauwa\u017c, \u017ce zawijam to w tablic\u0119, z <code>$this<\/code>pierwszym parametrem, poniewa\u017c wywo\u0142uj\u0119 funkcj\u0119 wewn\u0105trz klasy. Je\u015bli nie pracujesz z klasami, mo\u017cesz po prostu u\u017cy\u0107 nazwy funkcji <code>cmb2_render_link_picker<\/code>.<br \/>\n3., <code>10<\/code>to kolejno\u015b\u0107, w jakiej chcemy uruchomi\u0107 funkcj\u0119 (im ni\u017csza liczba, tym szybciej uruchamia si\u0119 po wywo\u0142aniu akcji).<\/li>\n<li>Jest <code>5<\/code>to ilo\u015b\u0107 parametr\u00f3w, kt\u00f3re zostan\u0105 przekazane do wywo\u0142ywanej funkcji (wkr\u00f3tce stanie si\u0119 to jasne).<\/li>\n<\/ol>\n<p>Nast\u0119pnie tworzymy funkcj\u0119, kt\u00f3ra wyrenderuje formularz:<\/p>\n<pre><code>&lt;?php\n\npublic function cmb2_render_link_picker( $field, $value, $object_id, $object_type, $field_type_object) {\n\u2026\n}\n`\n<\/code><\/pre>\n<p>Zostawi\u0142em \u201eDocBlock&#8221; w powy\u017cszym kodzie, kt\u00f3ry opisuje, co robi ka\u017cdy z parametr\u00f3w przekazanych do <code>cmb2_render_link_picker()<\/code>funkcji.<\/p>\n<p>Zauwa\u017c, \u017ce moja funkcja zaczyna si\u0119 od <code>public<\/code>deklaracji. To znowu dlatego, \u017ce pracuj\u0119 w klasie. Je\u015bli nie pracujesz z klasami, mo\u017cesz to pomin\u0105\u0107.<\/p>\n<p>Warto\u015b\u0107 tego pola jest przekazywana do funkcji poprzez <code>$value<\/code>parametr. W przypadku tego pola b\u0119dziemy przechodzi\u0107 przez tablic\u0119, poniewa\u017c nasza kontrolka ma do niej trzy oddzielne elementy:<\/p>\n<ul>\n<li>Tekst<\/li>\n<li>Adres URL<\/li>\n<li>Je\u015bli link otwiera si\u0119 w nowym oknie (lub nie)<\/li>\n<\/ul>\n<p>Poniewa\u017c <code>$value<\/code>nie zawsze jest ustawiony (na przyk\u0142ad przy pierwszym renderowaniu kontrolki), musimy zainicjowa\u0107 go z pewnymi warto\u015bciami domy\u015blnymi. Robimy to za pomoc\u0105 nast\u0119puj\u0105cego fragmentu kodu:<\/p>\n<pre><code>&lt;?php\n$value = wp_parse_args( \n    $value, \n    array(\n        'text'  =&gt; '',\n        'url'   =&gt; '',\n        'blank' =&gt; 'false',) );\n<\/code><\/pre>\n<p>Mo\u017cemy wtedy zabra\u0107 si\u0119 do renderowania formularza. Oto przyk\u0142ad pierwszej kontrolki wprowadzania tekstu:<\/p>\n<pre><code>&lt;p&gt;\n    &lt;label for=\"&lt;?php echo $field_type_object-&gt;_id( '_text' ); ?&gt;'\"&gt;\n        &lt;?php echo esc_html( $field_type_object-&gt;_text( 'link_picker_text', 'Text') ); ?&gt;\n    &lt;\/label&gt;\n&lt;\/p&gt;\n&lt;?php \n    echo $field_type_object-&gt;input( \n            array(\n            'class' =&gt; 'cmb_text',\n            'name'  =&gt; $field_type_object-&gt;_name( '[text]' ),\n            'id'    =&gt; $field_type_object-&gt;_id( '_text' ),\n            'value' =&gt; $value['text'],) ); \n?&gt;\n<\/code><\/pre>\n<p>Uff! To wygl\u0105da troch\u0119 niechlujnie, prawda? Roz\u0142\u00f3\u017cmy to, linia po linii:<\/p>\n<ol>\n<li>Znacznik otwieraj\u0105cego akapitu.<\/li>\n<li>Znacznik etykiety otwieraj\u0105cej dla kontrolki, ale z <code>for<\/code>atrybutem automatycznie ustawionym przez <code>$field_type_object<\/code> <code>_id<\/code>parametr. Spowoduje to automatyczne wygenerowanie identyfikatora kontrolki podczas jej renderowania.<\/li>\n<li>Tekst naszej etykiety, zbudowany przy u\u017cyciu tekstu z tablicy opcji kontroli (lub powraca do s\u0142owa \u201eTekst&#8221;).<\/li>\n<li>Znacznik etykiety zamykaj\u0105cej<\/li>\n<li>Znacznik zamykaj\u0105cego akapitu.<\/li>\n<li>Rozpocznij deklaracj\u0119 PHP<\/li>\n<li>U\u017cyj kontrolki wej\u015bciowej (cz\u0119\u015b\u0107, <code>$field_type_object<\/code>aby utworzy\u0107 dane wej\u015bciowe formularza (domy\u015blnym typem b\u0119dzie tekst).<\/li>\n<li>Uruchom tablic\u0119 parametr\u00f3w<\/li>\n<li>Ustaw klas\u0119 danych wej\u015bciowych.<\/li>\n<li>Ustaw nazw\u0119 wej\u015bcia, ponownie u\u017cywaj\u0105c <code>$field_type_object<\/code>helpera.<\/li>\n<li>Ustaw identyfikator wej\u015bcia na ten sam identyfikator, kt\u00f3ry zosta\u0142 ustawiony na etykiecie.<\/li>\n<li>Pobierz warto\u015b\u0107 z <code>$value<\/code>, poniewa\u017c jest to tablica, potrzebujemy klucza 'text&#8217; dla tej kontrolki.<\/li>\n<li>Zamknij tablic\u0119.<\/li>\n<li>Zamknij funkcj\u0119 wprowadzania.<\/li>\n<li>Zamknij deklaracj\u0119 PHP.<\/li>\n<\/ol>\n<p>Znaczniki pola formularza adresu URL s\u0105 bardzo podobne, tylko aby u\u017cywa\u0107 typ\u00f3w wej\u015bciowych HTML5, mo\u017cemy ustawi\u0107 dodatkowy parametr \u201etype&#8221; na \u201eurl&#8221;:<\/p>\n<pre><code>&lt;?php \n\u2026\n'type'  =&gt; 'url',\n\u2026\n<\/code><\/pre>\n<p>Na koniec chcemy zaimplementowa\u0107 list\u0119 rozwijan\u0105. Znacznik jest bardzo znajomy:<\/p>\n<pre><code>&lt;?php\necho $field_type_object-&gt;select( \n    array(\n        'class'   =&gt; 'cmb_dropdown',\n        'name'    =&gt; $field_type_object-&gt;_name( '[blank]' ),\n        'id'      =&gt; $field_type_object-&gt;_id( '_blank' ),\n        'options' =&gt; $blank_options,) );\n<\/code><\/pre>\n<p>Zauwa\u017c, \u017ce <code>$field_type_object<\/code>funkcja, kt\u00f3rej u\u017cywamy, to <code>select<\/code>generowanie listy rozwijanej. Zauwa\u017c te\u017c, \u017ce w linii 6 mamy nowy atrybut <code>options<\/code>. Do tego przekazujemy ci\u0105g \u201eopcji&#8221;. Jest to generowane przed t\u0105 kontrolk\u0105, tak jak:<\/p>\n<pre><code>&lt;?php \n$blank_options = '';\n$blank_options .= '&lt;option value=\"false\" '. selected( $value['blank'], 'false', false) .'&gt;Opens in same&lt;\/option&gt;';\n$blank_options .= '&lt;option value=\"true\" '. selected( $value['blank'], 'true', false) .'&gt;Opens in new&lt;\/option&gt;';\n<\/code><\/pre>\n<p>Nast\u0119pnie wszystko, co musimy zrobi\u0107, to zawin\u0105\u0107 go w kilka <code>&lt;div&gt;<\/code>i mamy w pe\u0142ni renderowan\u0105 kontrol\u0119:<\/p>\n<pre><code>&lt;?php\npublic function cmb2_render_link_picker( $field, $value, $object_id, $object_type, $field_type_object) {\n    $value = wp_parse_args( $value, array(\n        'text'  =&gt; '',\n        'url'   =&gt; '',\n        'blank' =&gt; 'false',) );\n    $blank_options = '';\n    $blank_options .= '&lt;option value=\"false\" '. selected( $value['blank'], 'false', false) .'&gt;Opens in same&lt;\/option&gt;';\n    $blank_options .= '&lt;option value=\"true\" '. selected( $value['blank'], 'true', false) .'&gt;Opens in new&lt;\/option&gt;';\n    ?&gt;\n    &lt;div class=\"link-picker\"&gt;\n        &lt;div class=\"text\"&gt;\n            &lt;p&gt;\n                &lt;label for=\"&lt;?php echo $field_type_object-&gt;_id( '_text' ); ?&gt;'\"&gt;\n                    &lt;?php echo esc_html( $field_type_object-&gt;_text( 'link_picker_text', 'Text') ); ?&gt;\n                &lt;\/label&gt;\n            &lt;\/p&gt;\n            &lt;?php \n                echo $field_type_object-&gt;input( \n                    array(\n                        'class' =&gt; 'cmb_text',\n                        'name'  =&gt; $field_type_object-&gt;_name( '[text]' ),\n                        'id'    =&gt; $field_type_object-&gt;_id( '_text' ),\n                        'value' =&gt; $value['text'],\n                        'desc'  =&gt; '',) ); \n            ?&gt;\n        &lt;\/div&gt;\n        &lt;div class=\"url\"&gt;\n            &lt;p&gt;\n                &lt;label for=\"&lt;?php echo $field_type_object-&gt;_id( '_url' ); ?&gt;'\"&gt;\n                    &lt;?php echo esc_html( $field_type_object-&gt;_text( 'link_picker_url', 'URL') ); ?&gt;\n                &lt;\/label&gt;\n            &lt;\/p&gt;\n            &lt;?php \n                echo $field_type_object-&gt;input( \n                    array(\n                        'class' =&gt; 'cmb_text_url',\n                        'name'  =&gt; $field_type_object-&gt;_name( '[url]' ),\n                        'id'    =&gt; $field_type_object-&gt;_id( '_url' ),\n                        'value' =&gt; $value['url'],\n                        'type'  =&gt; 'url',\n                        'desc'  =&gt; '',) ); \n            ?&gt;\n        &lt;\/div&gt;\n        &lt;div class=\"blank\"&gt;\n            &lt;p&gt;\n                &lt;label for=\"&lt;?php echo $field_type_object-&gt;_id( '_blank' ); ?&gt;'\"&gt;\n                    &lt;?php echo esc_html( $field_type_object-&gt;_text( 'link_picker_blank', 'Window') ); ?&gt;\n                &lt;\/label&gt;\n            &lt;\/p&gt;\n            &lt;?php \n                echo $field_type_object-&gt;select( \n                    array(\n                        'class'   =&gt; 'cmb_checkbox',\n                        'name'    =&gt; $field_type_object-&gt;_name( '[blank]' ),\n                        'id'      =&gt; $field_type_object-&gt;_id( '_blank' ),\n                        'options' =&gt; $blank_options,\n                        'desc'    =&gt; '',) ); \n            ?&gt;\n        &lt;\/div&gt;\n        &lt;div class=\"choose\"&gt;\n            &lt;p&gt;\n                &lt;label&gt;Choose&lt;\/label&gt;\n            &lt;\/p&gt;\n            &lt;button class=\"dashicons dashicons-admin-links js-insert-link button button-primary\" title=\"&lt;?php esc_html_e( 'Insert Link', 'cmb' ); ?&gt;\"&gt;\n                 &lt;span class=\"screen-reader-text\"&gt;&lt;?php esc_html_e( 'Choose Link', 'cmb' ); ?&gt;&lt;\/span&gt;\n             &lt;\/button&gt;\n        &lt;\/div&gt;\n    &lt;\/div&gt;\n    &lt;p class=\"clear\"&gt;\n        &lt;?php echo $field_type_object-&gt;_desc();?&gt;\n    &lt;\/p&gt;\n&lt;?php\n}\n<\/code><\/pre>\n<p>I to wszystko! Przej\u0119li\u015bmy kontrol\u0119! CMB2 automatycznie obs\u0142uguje wszystkie dane, kt\u00f3re chcemy zapisa\u0107, wi\u0119c nic tam nie robimy.<\/p>\n<h3>Style<\/h3>\n<p>Zrzut ekranu kontrolki, kt\u00f3r\u0105 tworzymy (w g\u00f3rnej cz\u0119\u015bci tego posta) ma kilka niestandardowych styl\u00f3w zastosowanych do niego, wi\u0119c renderuje si\u0119 w tek\u015bcie. Nie b\u0119d\u0119 dzisiaj zag\u0142\u0119bia\u0142 si\u0119 w stylizacj\u0119 formularza, ale je\u015bli jeste\u015b ciekawy, mo\u017cesz <a href=\"https:\/\/en-gb.wordpress.org\/plugins\/link-picker-for-cmb2\/developers\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">pobra\u0107 wtyczk\u0119 i zobaczy\u0107 \u017ar\u00f3d\u0142o<\/a>.<\/p>\n<h3>Zapewnienie powtarzalno\u015bci kontroli<\/h3>\n<p>Dla tych, kt\u00f3rzy chc\u0105 by\u0107 troch\u0119 bardziej zaawansowani, mo\u017cesz sprawi\u0107, by sterowanie dzia\u0142a\u0142o z powtarzalnymi regionami CMB2. Aby to zrobi\u0107, musisz zrobi\u0107 troch\u0119 mapowania tablic. Aby to zrobi\u0107, u\u017cyj poni\u017cszego kodu:<\/p>\n<pre><code>&lt;?php\n\npublic function cmb2_sanitize_link_picker( $check, $meta_value, $object_id, $field_args, $sanitize_object) {\n\n    if (! is_array( $meta_value) ||! $field_args['repeatable']) {\n        return $check;\n    }\n    foreach ($meta_value as $key =&gt; $val) {\n        $meta_value[ $key ] =  null;\n        if(! empty( $val['url'])) {\n            $meta_value[ $key ] = array_map( 'sanitize_text_field', $val );\n        }\n    }\n    return $meta_value;\n}\npublic function cmb2_types_esc_link_picker( $check, $meta_value, $field_args, $field_object) {\n\n    if (! is_array( $meta_value) ||! $field_args['repeatable']) {\n        return $check;\n    }\n    foreach ($meta_value as $key =&gt; $val) {\n        $meta_value[ $key ] =  null;\n        if(! empty( $val['url'])) {\n            $meta_value[ $key ] = array_map( 'esc_attr', $val );\n        }\n    }\n    return $meta_value;\n}\n<\/code><\/pre>\n<h2>Wyb\u00f3r \u0142\u0105cza<\/h2>\n<p>Oczywi\u015bcie celem selektora link\u00f3w jest integracja z w\u0142asn\u0105 funkcjonalno\u015bci\u0105 wyboru link\u00f3w WordPressa, dzi\u0119ki czemu po klikni\u0119ciu przycisku \u201eWybierz&#8221; pojawi si\u0119 okno dialogowe \u201eWstaw\/edytuj link&#8221;.<\/p>\n<p>Aby tak si\u0119 sta\u0142o, w du\u017cym stopniu polegamy na JavaScript. W szczeg\u00f3lno\u015bci u\u017cywam <a href=\"https:\/\/jquery.com\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">jQuery<\/a>, aby co\u015b si\u0119 wydarzy\u0142o.<\/p>\n<p>Zanim poka\u017c\u0119 Ci JavaScript, kt\u00f3ry uruchamia to okno dialogowe, musimy najpierw umie\u015bci\u0107 w kolejce w\u0142asny wewn\u0119trzny JavaScript WordPressa, kt\u00f3ry wst\u0119pnie za\u0142aduje modalne i biblioteki, od kt\u00f3rych zale\u017cy nasz kod. To wygl\u0105da troch\u0119 mniej wi\u0119cej tak:<\/p>\n<pre><code>&lt;?php\nglobal $post_id;\n\nif (isset( $post_id)) {\n    wp_enqueue_media( array( 'post' =&gt; $post_id) );\n}\n\n$plugin_js_url  = plugins_url( 'js\/plugin.js', ROOT );\nwp_enqueue_script( 'wholesomecode', $plugin_js_url, array( 'jquery', 'jquery-ui-core', 'jquery-ui-draggable', 'jquery-ui-droppable', 'thickbox', 'wpdialogs' ), '1.0.0', true );\n<\/code><\/pre>\n<p>Jak wida\u0107, wiele wewn\u0119trznych bibliotek WordPressa korzysta z jQuery do \u0142adowania wyskakuj\u0105cych okienek, wi\u0119c sensowne jest, aby nasz wyzwalacz wyskakuj\u0105cych okien robi\u0142 to samo. Odbywa si\u0119 to za pomoc\u0105 programu <code>\/js\/plugin.js<\/code>, kt\u00f3ry jest \u0142adowany w wierszu 10 powy\u017cszego przyk\u0142adu.<\/p>\n<pre><code>jQuery(document).ready(function($) {\n\n    var url   = $('body');\n    var text = $('body');\n    var blank = $('body');\n\n    $('body').on('click', '.js-insert-link', function(event) {\n\n        event.preventDefault? event.preventDefault(): event.returnValue = false;\n        event.stopPropagation();\n\n        url            = $(this).closest('.link-picker').find('input.cmb_text_url ');\n        text           = $(this).closest('.link-picker').find('input.cmb_text ');\n        blank          = $(this).closest('.link-picker').find('input.cmb_checkbox ');\n\n        wpActiveEditor = true;\n        wpLink.open();\n        wpLink.textarea = url;\n\n        return false;\n    });\n\n    $('body').on('click', '#wp-link-cancel, #wp-link-backdrop, #wp-link-close', function(event) {\n\n        wpLink.textarea = url;\n        wpLink.close();\n        event.preventDefault? event.preventDefault(): event.returnValue = false;\n        event.stopPropagation();\n        return false;\n    });\n\n    $('body').on('click', '#wp-link-submit', function(event) {\n        console.log(text)\n        var linkAtts = wpLink.getAttrs();\n\n        linkAtts.text = $('#wp-link-text').val();\n\n        url.val(linkAtts.href);\n\n        if( linkAtts.text != '') {\n            text.val(linkAtts.text);\n        }\n\n        if (linkAtts.target == '_blank') {\n            blank.prop('checked', true);\n        } else {\n            blank.prop('checked', false);\n        }\n\n        wpLink.textarea = url;\n        wpLink.close();\n        event.preventDefault? event.preventDefault(): event.returnValue = false;\n        event.stopPropagation();\n        return false;\n    });\n});\n<\/code><\/pre>\n<p>U\u017cywaj\u0105c klas, kt\u00f3re otoczyli\u015bmy wok\u00f3\u0142 naszych kontrolek formularza, JavaScript kieruje swoje kontrolki i wypycha wybrany wynik z wyskakuj\u0105cego okienka selektora link\u00f3w do odpowiednich p\u00f3l kontrolnych.<\/p>\n<h2>Korzystanie z Kontroli<\/h2>\n<p>Tak wi\u0119c, po przejrzeniu powy\u017cszego samouczka i by\u0107 mo\u017ce po <a href=\"https:\/\/en-gb.wordpress.org\/plugins\/link-picker-for-cmb2\/developers\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">przejrzeniu kodu \u017ar\u00f3d\u0142owego<\/a> wtyczki <a href=\"https:\/\/en-gb.wordpress.org\/plugins\/link-picker-for-cmb2\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">Link Picker dla CMB2<\/a> lub po prostu pobraniu mojej wersji, mo\u017cesz teraz zastanawia\u0107 si\u0119, jak u\u017cywa\u0107 tego z CMB2. C\u00f3\u017c, \u0142atwiej by\u0107 nie mo\u017ce:<\/p>\n<pre><code>&lt;?php\nfunction wholesomecode_create_meta_boxes() {\n  $prefix = '_profile_';\n\n    $cmb = new_cmb2_box(\n        array(\n            'id'            =&gt; 'cta',\n            'title'         =&gt; __( 'Call to Action', 'cmb2' ),\n            'object_types'  =&gt; array( 'profile' ),\n            'context'       =&gt; 'normal',\n            'priority'      =&gt; 'low',\n            'show_names'    =&gt; true,) );\n\n    $field1 = $cmb-&gt;add_field( \n        array(\n            'name' =&gt; __( 'Link Picker', 'cmb2' ),\n            'id'   =&gt; $prefix. 'cta_link',\n            'type' =&gt; 'link_picker',) );\n}\nadd_action( 'cmb2_admin_init', 'wholesomecode_create_meta_boxes' );\n<\/code><\/pre>\n<p><div id=\"PostUnique_PostSource\" style=\"padding-top: 50px\">\u0179r\u00f3d\u0142o nagrywania:  <a target=\"_blank\" rel=\"noopener nofollow\" href=\"\/\/wholesomecode.ltd\" class=\"external external_icon\">wholesomecode.ltd<\/a><\/div><\/p>\n","protected":false},"excerpt":{"rendered":"<p>W tym samouczku przyjrz\u0119 si\u0119, jak stworzy\u0107 niestandardow\u0105 kontrolk\u0119, aby rozszerzy\u0107 funkcjonalno\u015b\u0107 CMB2 (Custom Meta Boxes 2) przez WebDevStudios. Tworz\u0119 strony internetowe (i aplikacje webowe)&#8230;<\/p>\n","protected":false},"author":1,"featured_media":224127,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","_wp_rev_ctl_limit":""},"categories":[721,897,845,866],"tags":[1169],"class_list":["post-228106","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-deweloper","category-kod","category-samouczki","category-wordpress-7","tag-affiai-pl"],"_links":{"self":[{"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/posts\/228106","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=228106"}],"version-history":[{"count":0,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/posts\/228106\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/media\/224127"}],"wp:attachment":[{"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/media?parent=228106"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/categories?post=228106"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/tags?post=228106"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}