{"id":233480,"date":"2023-02-15T17:51:00","date_gmt":"2023-02-15T14:51:00","guid":{"rendered":"https:\/\/wordpress.mediadoma.com\/?p=233480"},"modified":"2022-11-10T23:55:34","modified_gmt":"2022-11-10T20:55:34","slug":"samouczek-tworzenie-zaawansowanego-niestandardowego-typu-pola-formularzy-grawitacyjnych-i-jak-obslugiwac-wiele-wartosci-wejsciowych","status":"publish","type":"post","link":"https:\/\/wordpress.mediadoma.com\/pl\/samouczek-tworzenie-zaawansowanego-niestandardowego-typu-pola-formularzy-grawitacyjnych-i-jak-obslugiwac-wiele-wartosci-wejsciowych\/","title":{"rendered":"Samouczek: Tworzenie zaawansowanego niestandardowego typu pola formularzy grawitacyjnych i jak obs\u0142ugiwa\u0107 wiele warto\u015bci wej\u015bciowych"},"content":{"rendered":"\n<p>W tym samouczku poka\u017c\u0119, jak stworzy\u0107 zaawansowany niestandardowy typ pola Gravity Forms. Pole b\u0119dzie zawiera\u0142o wiele danych wej\u015bciowych i b\u0119dzie wymaga\u0142o specjalnej obs\u0142ugi w celu przechowywania i wy\u015bwietlania przes\u0142anych warto\u015bci.<\/p>\n<h2>Co zrobimy<\/h2>\n<p>W tym przyk\u0142adzie przyjmuj\u0119 przyk\u0142ad w\u0142a\u015bciciela witryny WordPress, kt\u00f3ry zajmuje si\u0119 dostawami obiad\u00f3w w miejscu pracy. W\u0142a\u015bciciel ma formularz, w kt\u00f3rym ludzie mog\u0105 wype\u0142ni\u0107, jakiego rodzaju lunchu chc\u0105 i ile na ka\u017cdy dzie\u0144 tygodnia. Mo\u017cna to rozwi\u0105za\u0107 za pomoc\u0105 podobnej do tabeli metody wprowadzania liczby dla dowolnego kursu w dowolnym dniu, w kt\u00f3rym maj\u0105 by\u0107 dostarczane.<\/p>\n<p><a href=\"https:\/\/wordpress.mediadoma.com\/wp-content\/uploads\/2022\/01\/post-153179-61e509da5343d.png\" data-rel=\"lightbox\" ><img decoding=\"async\" class=\"SDStudio-light-box-enable SDStudio-editor-tools-md-imp\" src=\"https:\/\/wordpress.mediadoma.com\/wp-content\/uploads\/2022\/01\/post-153179-61e509da5343d.png\" alt=\"Samouczek: Tworzenie zaawansowanego niestandardowego typu pola formularzy grawitacyjnych i jak obs\u0142ugiwa\u0107 wiele warto\u015bci wej\u015bciowych\" ><\/a><\/p>\n<p>Kursy mo\u017cna edytowa\u0107 w ustawieniach pola w edytorze formularzy i mo\u017cna je zmieni\u0107 w dowolnym momencie. A przy ka\u017cdym przes\u0142aniu formularza w\u0142a\u015bciciel witryny otrzymuje pe\u0142ny przegl\u0105d przes\u0142anych warto\u015bci:<\/p>\n<p><a href=\"https:\/\/wordpress.mediadoma.com\/wp-content\/uploads\/2022\/01\/post-153179-61e509dbe8f8c.png\" data-rel=\"lightbox\"><img decoding=\"async\" class=\"SDStudio-light-box-enable SDStudio-editor-tools-md-imp\" src=\"https:\/\/wordpress.mediadoma.com\/wp-content\/uploads\/2022\/01\/post-153179-61e509dbe8f8c.png\" alt=\"Samouczek: Tworzenie zaawansowanego niestandardowego typu pola formularzy grawitacyjnych i jak obs\u0142ugiwa\u0107 wiele warto\u015bci wej\u015bciowych\" ><\/a><\/p>\n<p>Oczywi\u015bcie to tylko przyk\u0142ad i prawdopodobnie musisz to dostosowa\u0107 do swojego przypadku. Ale w tym przyk\u0142adzie mamy szans\u0119 nauczy\u0107 si\u0119 obs\u0142ugi wielu danych wej\u015bciowych w jednym polu. Powinien da\u0107 ci kilka pomys\u0142\u00f3w na to, jak radzi\u0107 sobie z w\u0142asnym typem pola niestandardowego.<\/p>\n<h2>Przed rozpocz\u0119ciem kodowania<\/h2>\n<p>Zanim zaczniemy potrzebujemy miejsca na dodanie naszego kodu. Mo\u017cesz doda\u0107 to do swojego motywu <code>functions.php<\/code>lub pliku wtyczki.<\/p>\n<p>Wybrana przeze mnie metoda jest zorientowana obiektowo, co oznacza stworzenie klasy, kt\u00f3ra rozszerza klas\u0119 Gravity Forms <code>GF_Field<\/code>. Polecam umie\u015bci\u0107 klas\u0119 w osobnym pliku w swoim projekcie. Powiniene\u015b r\u00f3wnie\u017c sprawdzi\u0107, czy wtyczka Gravity Forms istnieje przed w\u0142\u0105czeniem Twojej klasy, aby zapobiec awariom Twojej witryny.<\/p>\n<p>Je\u015bli jeste\u015b zainteresowany, mo\u017cesz zajrze\u0107 do <a href=\"https:\/\/docs.gravityforms.com\/gf_field\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">dokumentacji Gravity Forms na GF_Field<\/a>. Znajdziesz wi\u0119cej funkcji i zmiennych, kt\u00f3re mog\u0105 by\u0107 potrzebne dla Twojego typu pola.<\/p>\n<p>Rozszerzaj\u0105c <code>GF_Field<\/code>klas\u0119 mo\u017cemy po prostu wybra\u0107 nadpisanie funkcji, kt\u00f3re musimy zmieni\u0107. Je\u015bli chodzi o funkcje, kt\u00f3rych nie zast\u0119pujemy, Gravity Forms uruchomi domy\u015blnie zdefiniowane wewn\u0105trz <code>GF_Field<\/code>. W poni\u017cszym samouczku om\u00f3wimy kolejno ka\u017cd\u0105 funkcj\u0119, kt\u00f3r\u0105 musimy zast\u0105pi\u0107 dla naszego niestandardowego pola. Bez zb\u0119dnych ceregieli zacznijmy!<\/p>\n<h2>Tworzenie niestandardowego typu pola<\/h2>\n<p>Pierwszym krokiem jest zdefiniowanie niestandardowej klasy PHP, kt\u00f3ra rozszerza <code>GF_Field<\/code>. Nadaj klasie unikaln\u0105 nazw\u0119 i upewnij si\u0119, \u017ce jest ona uwzgl\u0119dniona w Twoim projekcie. Po definicji klasy uruchamiamy funkcj\u0119 <code>register()<\/code>statyczn\u0105 <code>GF_Field<\/code>przekazuj\u0105c instancj\u0119 naszej klasy jako parametr. To inicjuje nasz\u0105 klas\u0119 i rejestruje typ pola.<\/p>\n<p>Jedyn\u0105 wymagan\u0105 zmienn\u0105, kt\u00f3rej potrzebujesz w swojej klasie, jest <code>$type<\/code>. Zmienna klasy <code>$type<\/code>musi by\u0107 unikatowa i jest nazw\u0105 informacji o pracy typu pola. W moim przyk\u0142adzie nazwa\u0142em go \u201e <code>food_delivery<\/code>&quot;.<\/p>\n<pre><code>if (class_exists('GF_Field')) {\n    class FoodDelivery extends GF_Field {\n        public $type = 'food_delivery';\n\u00a0\n        \/\/ The rest of the code is added here...\n    }\n    GF_Fields::register(new FoodDelivery());\n}<\/code><\/pre>\n<p>Z tym ma\u0142ym fragmentem kodu, nasz niestandardowy typ pola powinien zosta\u0107 dodany jako dost\u0119pny wyb\u00f3r w edytorze Gravity Forms. Domy\u015blnie pojawia si\u0119 na ko\u0144cu pola \u201eStandardowe pola&#8221;. Poniewa\u017c nie nadali\u015bmy jeszcze naszemu polu w\u0142a\u015bciwej nazwy (kolejny krok), przycisk jest oznaczony jako warto\u015b\u0107 <code>$type<\/code>.<\/p>\n<p><a href=\"https:\/\/wordpress.mediadoma.com\/wp-content\/uploads\/2022\/01\/post-153179-61e509dd8f563.jpg\" data-rel=\"lightbox\"><img decoding=\"async\" class=\"SDStudio-light-box-enable SDStudio-editor-tools-md-imp\" src=\"https:\/\/wordpress.mediadoma.com\/wp-content\/uploads\/2022\/01\/post-153179-61e509dd8f563.jpg\" alt=\"Samouczek: Tworzenie zaawansowanego niestandardowego typu pola formularzy grawitacyjnych i jak obs\u0142ugiwa\u0107 wiele warto\u015bci wej\u015bciowych\" ><\/a><\/p>\n<h2>Definiowanie nazwy pola<\/h2>\n<p>Nast\u0119pny krok jest \u0142atwy; po prostu nadaj\u0105c naszej dziedzinie lepsz\u0105 nazw\u0119. W tym celu zast\u0119pujemy funkcj\u0119 <code>get_form_editor_field_title()<\/code>. Wszystko, co musimy zrobi\u0107, to zwr\u00f3ci\u0107 ci\u0105g z nazw\u0105 pola.<\/p>\n<pre><code>public function get_form_editor_field_title() {\n    return esc_attr__('Food Delivery', 'txtdomain');\n}<\/code><\/pre>\n<p>Dzi\u0119ki tej funkcji w naszej klasie przycisk dodawania pola jest aktualizowany o znacznie lepsz\u0105 etykiet\u0119.<\/p>\n<h2>Zmiana kategorii pola<\/h2>\n<p>Ten krok jest opcjonalny. Domy\u015blnie nasz niestandardowy typ pola pojawia si\u0119 w polu \u201eStandardowe pola&#8221;, ale mo\u017cemy to zmieni\u0107. Za\u0142\u00f3\u017cmy, \u017ce chcemy, aby zamiast tego pojawi\u0142 si\u0119 w polu \u201eZaawansowane pola&#8221;.<\/p>\n<p>Aby zmieni\u0107 kategori\u0119, w kt\u00f3rej ma si\u0119 pojawi\u0107 pole, nadpisujemy funkcj\u0119 <code>get_form_editor_button()<\/code>. Musimy zwr\u00f3ci\u0107 tablic\u0119 asocjacyjn\u0105 z dwoma elementami. Jako warto\u015b\u0107 klucza \u201e <code>group<\/code>&#8221; podajesz wewn\u0119trzn\u0105 nazw\u0119 kategorii, w kt\u00f3rej ma si\u0119 pojawia\u0107 przycisk. Dost\u0119pne opcje to \u201e <code>standard_fields<\/code>&#8222;, \u201e <code>advanced_fields<\/code>&#8222;, \u201e <code>post_fields<\/code>&#8221; lub \u201e <code>pricing_fields<\/code>&#8222;. (Mo\u017cesz tak\u017ce stworzy\u0107 w\u0142asn\u0105 kategori\u0119, ale nie jest to tutaj om\u00f3wione). Drugi element tablicy potrzebuje klucza &#8217; <code>text<\/code>&#8217; iw tym celu po prostu zwracamy nazw\u0119 pola wywo\u0142uj\u0105c <code>get_form_editor_field_title()<\/code>. Jest to funkcja, kt\u00f3r\u0105 w\u0142a\u015bnie stworzyli\u015bmy powy\u017cej.<\/p>\n<pre><code>public function get_form_editor_button() {\n    return [\n        'group' =&gt; 'advanced_fields',\n        'text'  =&gt; $this-&gt;get_form_editor_field_title(),\n    ];\n}<\/code><\/pre>\n<p>Teraz przycisk dodawania naszego niestandardowego typu pola zosta\u0142 przeniesiony do pola \u201eZaawansowane pola&#8221;.<\/p>\n<h2>Aktywacja ustawie\u0144 pola<\/h2>\n<p>Je\u015bli pr\u00f3bowa\u0142e\u015b doda\u0107 typ pola do formularza, mog\u0142e\u015b zauwa\u017cy\u0107, \u017ce nie ma \u017cadnych ustawie\u0144. Nie mo\u017cesz nawet edytowa\u0107 etykiety. Spos\u00f3b, w jaki to dzia\u0142a, polega na tym, \u017ce wszystkie typy ustawie\u0144 faktycznie tam s\u0105, po prostu wszystkie s\u0105 ukryte za pomoc\u0105 CSS przez Gravity Forms. Musimy indywidualnie okre\u015bli\u0107, kt\u00f3re ustawienia chcemy w\u0142\u0105czy\u0107, a Gravity Forms wy\u015bwietli dla nas wybrane ustawienia.<\/p>\n<p>Musimy zdefiniowa\u0107 funkcj\u0119 <code>get_form_editor_field_settings()<\/code>i zwr\u00f3ci\u0107 tablic\u0119 wszystkich ustawie\u0144, kt\u00f3rych nie chcemy ukrywa\u0107 dla naszego typu pola. To, kt\u00f3re ustawienia chcesz doda\u0107, zale\u017cy wy\u0142\u0105cznie od Ciebie i Twojego projektu. Pami\u0119taj, \u017ce Twoje pole powinno obs\u0142ugiwa\u0107 dowolne ustawienia, kt\u00f3re aktywujesz, w przeciwnym razie pokazywanie ustawie\u0144 dla niego nie ma sensu.<\/p>\n<p>Poni\u017cej utworzy\u0142em kr\u00f3tki przegl\u0105d nazw ustawie\u0144. To nie jest pe\u0142na lista \u2013 poniewa\u017c istnieje wiele ustawie\u0144, kt\u00f3re s\u0105 przydatne tylko dla bardzo specyficznych typ\u00f3w p\u00f3l. Na przyk\u0142ad format telefonu, format daty\/godziny i ca\u0142a masa ustawie\u0144 zwi\u0105zanych z polami postu i cenami.<\/p>\n<h4>Zak\u0142adka Og\u00f3lne<\/h4>\n<ul>\n<li>Etykieta pola:<code>label_setting<\/code><\/li>\n<li>Opis pola:<code>description_setting<\/code><\/li>\n<li>Wybory:<code>choices_setting<\/code><\/li>\n<li>Wymagany:<code>rules_setting<\/code><\/li>\n<li>Brak duplikat\u00f3w:<code>duplicate_setting<\/code><\/li>\n<li>W\u0142\u0105cz kolumny:<code>columns_setting<\/code><\/li>\n<li>W\u0142\u0105cz opcj\u0119 \u201ezaznacz wszystko&#8221;:<code>select_all_choices_setting<\/code><\/li>\n<li>W\u0142\u0105cz opcj\u0119 \u201einny&#8221;:<code>other_choice_setting<\/code><\/li>\n<\/ul>\n<h4>Zak\u0142adka Wygl\u0105d<\/h4>\n<ul>\n<li>Symbol zast\u0119pczy:<code>placeholder_setting<\/code><\/li>\n<li>Widoczno\u015b\u0107 etykiety pola i umieszczenie opisu:<code>label_placement_setting<\/code><\/li>\n<li>Niestandardowa wiadomo\u015b\u0107 weryfikacyjna:<code>error_message_setting<\/code><\/li>\n<li>Niestandardowa klasa CSS:<code>css_class_setting<\/code><\/li>\n<li>Rozmiar pola:<code>size_setting<\/code><\/li>\n<\/ul>\n<h4>Zak\u0142adka Zaawansowane<\/h4>\n<ul>\n<li>Etykieta pola administratora:<code>admin_label_setting<\/code><\/li>\n<li>Domy\u015blna warto\u015b\u0107:<code>default_value_setting<\/code><\/li>\n<li>W\u0142\u0105cz wprowadzanie has\u0142a:<code>password_field_setting<\/code><\/li>\n<li>Wymu\u015b SSL:<code>force_ssl_field_setting<\/code><\/li>\n<li>Widoczno\u015b\u0107:<code>visibility_setting<\/code><\/li>\n<li>Zezwalaj na dynamiczne wype\u0142nianie pola:<code>prepopulate_field_setting<\/code><\/li>\n<li>W\u0142\u0105cz logik\u0119 warunkow\u0105:<code>conditional_logic_field_setting<\/code><\/li>\n<li>W\u0142\u0105cz logik\u0119 warunkow\u0105 strony:<code>conditional_logic_page_setting<\/code><\/li>\n<\/ul>\n<p>W naszym przyk\u0142adzie najwa\u017cniejsze s\u0105 etykieta pola, opis, wybory i to, czy pole jest wymagane, czy nie. Zezwalamy r\u00f3wnie\u017c na ustawienia klasy CSS, niestandardowy komunikat walidacyjny i logik\u0119 warunkow\u0105.<\/p>\n<pre><code>public function get_form_editor_field_settings() {\n    return [\n        'label_setting',\n        'choices_setting',\n        'description_setting',\n        'rules_setting',\n        'error_message_setting',\n        'css_class_setting',\n        'conditional_logic_field_setting'\n    ];\n}<\/code><\/pre>\n<p>Od\u015bwie\u017c edytor formularzy i powiniene\u015b teraz zobaczy\u0107 wszystkie wybrane ustawienia i zak\u0142adki w naszym polu. Wszystkie ustawienia s\u0105 obs\u0142ugiwane i zapisywane automatycznie przez Gravity Forms.<\/p>\n<p>\u015amia\u0142o i dodaj kilka pozycji na li\u015bcie Wybory, aby\u015bmy mieli nad czym pracowa\u0107. Oto, co ustawi\u0142em jako przyk\u0142ad:<\/p>\n<p><a href=\"https:\/\/wordpress.mediadoma.com\/wp-content\/uploads\/2022\/01\/post-153179-61e509df36138.png\" data-rel=\"lightbox\"><img decoding=\"async\" class=\"SDStudio-light-box-enable SDStudio-editor-tools-md-imp\" src=\"https:\/\/wordpress.mediadoma.com\/wp-content\/uploads\/2022\/01\/post-153179-61e509df36138.png\" alt=\"Samouczek: Tworzenie zaawansowanego niestandardowego typu pola formularzy grawitacyjnych i jak obs\u0142ugiwa\u0107 wiele warto\u015bci wej\u015bciowych\" ><\/a><\/p>\n<h2>Definiowanie niestandardowych opcji domy\u015blnych<\/h2>\n<p>Je\u015bli jeste\u015b przyzwyczajony do u\u017cywania np. przycisk\u00f3w radiowych lub p\u00f3l wyboru w formularzach grawitacyjnych, prawdopodobnie zauwa\u017cy\u0142e\u015b, \u017ce s\u0105 one nap\u0119dzane opcjami takimi jak \u201ePierwszy wyb\u00f3r&#8221;, \u201eDrugi wyb\u00f3r&#8221;, \u201eTrzeci wyb\u00f3r&#8221;. Jest to domy\u015blne zachowanie z Gravity Forms, je\u015bli nie zapisano \u017cadnych wybor\u00f3w (wcze\u015bniej) i uruchamia si\u0119 to tylko w tych okre\u015blonych typach p\u00f3l. Ale w przypadku naszego niestandardowego typu pola nie zostan\u0105 wype\u0142nione \u017cadne opcje. To sprawia, \u017ce \u200b\u200bjest to troch\u0119 k\u0142opotliwe, poniewa\u017c nie dostaniesz przycisku \u201e+&#8221;, aby doda\u0107 kolejny wyb\u00f3r. Musisz u\u017cy\u0107 przycisku \u201eDodaj zbiorczo\/predefiniowane opcje&#8221;, doda\u0107 tam kilka opcji, a nast\u0119pnie uzyskasz dost\u0119p do przycisk\u00f3w \u201e+&#8221;, aby doda\u0107 opcje. Ale \u0142atwo jest zdefiniowa\u0107 niekt\u00f3re niestandardowe opcje \u2013 wystarczy zdefiniowa\u0107 zmienn\u0105 tablicow\u0105 klasy<code>public $choices<\/code>a Gravity Forms automatycznie wygeneruje wst\u0119pnie zdefiniowane wybory w twoim polu, gdy dodasz je do swoich formularzy.<\/p>\n<p>Uwaga: to jest zmienna klasy, kt\u00f3r\u0105 mo\u017cesz doda\u0107 u g\u00f3ry klasy, tu\u017c poni\u017cej <code>public $type<\/code>. Ka\u017cdy wyb\u00f3r musi by\u0107 tablic\u0105, a wyb\u00f3r jest warto\u015bci\u0105 klucza \u201e <code>text<\/code>&#8222;.<\/p>\n<pre><code>public $choices = [\n    [ 'text' =&gt; 'Food Choice 1' ],\n    [ 'text' =&gt; 'Food Choice 2' ],\n    [ 'text' =&gt; 'Food Choice 3' ],\n];<\/code><\/pre>\n<p>Pami\u0119taj, \u017ce je\u015bli ju\u017c doda\u0142e\u015b to pole do formularza, nie wype\u0142ni ono opcji z moc\u0105 wsteczn\u0105. Dzia\u0142a to tylko wtedy, gdy do formularza dodasz nowe pole.<\/p>\n<p><strong>Uwaga<\/strong>: W Gravity Forms wydaje si\u0119, \u017ce mo\u017cliwe jest r\u00f3wnie\u017c dodanie kluczy &#8217; <code>value<\/code>&#8217; do ka\u017cdego wyboru. Ale nie uda\u0142o mi si\u0119 to zadzia\u0142a\u0107 \u2013 warto\u015bci automatycznie stan\u0105 si\u0119 takie same jak tekst wyboru.<\/p>\n<h2>Definiowanie warto\u015bci pola jako tablicy<\/h2>\n<p>Nast\u0119pny krok jest do\u015b\u0107 prosty, ale konieczny. Domy\u015blnymi warto\u015bciami p\u00f3l w Gravity Forms s\u0105 \u0142a\u0144cuchy. Potrzebujemy, aby warto\u015b\u0107 by\u0142a tablic\u0105, poniewa\u017c pracujemy z wieloma danymi wej\u015bciowymi. W tym celu definiujemy funkcj\u0119 <code>is_value_submission_array()<\/code>i return <code>true<\/code>.<\/p>\n<pre><code>public function is_value_submission_array() {\n    return true;\n}<\/code><\/pre>\n<p>Gwarantuje to, \u017ce mo\u017cemy poprawnie pracowa\u0107 z wprowadzon\u0105 warto\u015bci\u0105 naszych wielu danych wej\u015bciowych.<\/p>\n<h2>Renderowanie danych wyj\u015bciowych pola<\/h2>\n<p>Je\u015bli chodzi o renderowanie danych wyj\u015bciowych pola, nale\u017cy pami\u0119ta\u0107 o kilku rzeczach.<\/p>\n<p>Po pierwsze, musisz wybra\u0107 mi\u0119dzy dwiema funkcjami; <code>get_field_input()<\/code>lub <code>get_field_content()<\/code>. W pierwszej metodzie Gravity Forms automatycznie renderuje element listy zawijania, etykiet\u0119, opis i pojemnik dla komunikatu o b\u0142\u0119dzie walidacji do twojego pola i kontrolujesz tylko wewn\u0119trzne wyj\u015bcie pola. W przypadku drugiej metody nic si\u0119 nie dzieje i masz wi\u0119ksz\u0105 kontrol\u0119 nad danymi wyj\u015bciowymi pola. Musisz jednak r\u0119cznie wyrenderowa\u0107 etykiet\u0119, opis i komunikaty o b\u0142\u0119dach. Pierwsza metoda, <code>get_field_input()<\/code>, jest w wi\u0119kszo\u015bci przypadk\u00f3w odpowiednia.<\/p>\n<p>Drug\u0105 rzecz\u0105, o kt\u00f3rej nale\u017cy pami\u0119ta\u0107, jest to, \u017ce funkcja renderowania pola wp\u0142ywa na trzy r\u00f3\u017cne lokalizacje. Te trzy to renderowanie danych wyj\u015bciowych pola w interfejsie u\u017cytkownika, podgl\u0105d pola w edytorze formularzy i wreszcie pole podczas edycji wpisu. Na szcz\u0119\u015bcie Gravity Forms oferuje funkcje, kt\u00f3re pozwalaj\u0105 \u0142atwo okre\u015bli\u0107, na jakim widoku si\u0119 znajdujemy. Zazwyczaj renderujesz pole w ten sam spos\u00f3b we wszystkich trzech przypadkach. Ale poniewa\u017c renderowanie du\u017cej tabeli z wieloma danymi wej\u015bciowymi staje si\u0119 niepotrzebne w edytorze formularzy, zdecydowa\u0142em si\u0119 renderowa\u0107 pole inaczej w edytorze formularzy.<\/p>\n<p>I na koniec musimy upewni\u0107 si\u0119, \u017ce wszelkie dane wej\u015bciowe otrzymaj\u0105 odpowiedni <code>name<\/code>atrybut, aby Gravity Forms m\u00f3g\u0142 zebra\u0107 jego warto\u015b\u0107 po przes\u0142aniu formularza. Wszystkie dane wej\u015bciowe w Gravity Forms wymagaj\u0105 <code>name<\/code>atrybut\u00f3w zgodnych z t\u0105 zasad\u0105: <code>name=\"input_{FIELD_ID}\"<\/code>(pola wielokrotnego wyboru u\u017cywaj\u0105 dodatkowego identyfikatora, ale nie musimy si\u0119 tym martwi\u0107 w naszym przypadku). Mamy dost\u0119p do identyfikatora pola, poniewa\u017c jest to zmienna klasy (z <code>GF_Field<\/code>). Ale w naszym przypadku powiedzieli\u015bmy Gravity Forms, \u017ce warto\u015b\u0107 jest tablic\u0105, a nie warto\u015bci\u0105 pojedyncz\u0105 (poprzedni krok), wi\u0119c dodajemy nawiasy kwadratowe po atrybucie name; <code>name=\"input_{FIELD_ID}[]\"<\/code>. Je\u015bli wi\u0119c pole ma ID 4 wewn\u0105trz formularza, atrybutem nazwy powinien by\u0107 \u201e <code>input_4[]<\/code>&#8222;.<\/p>\n<p>Zdecyduj\u0119 si\u0119 na u\u017cycie <code>get_field_input()<\/code>, kt\u00f3re ma trzy parametry. Pierwszym parametrem jest obiekt formularza, kt\u00f3rego tak naprawd\u0119 nie potrzebujemy w naszym przyk\u0142adzie. Drugi parametr to aktualna warto\u015b\u0107. Mo\u017ce to by\u0107 warto\u015b\u0107 pola z <code>$_POST<\/code>chwili, gdy pr\u00f3ba przes\u0142ania formularza zako\u0144czy\u0142a si\u0119 niepowodzeniem. Mo\u017cemy zachowa\u0107 poprzednio zg\u0142oszone warto\u015bci. Lub je\u015bli funkcja dzia\u0142a podczas edycji wpisu, warto\u015b\u0107 b\u0119dzie warto\u015bci\u0105 przechowywan\u0105 z przes\u0142anego zg\u0142oszenia. P\u00f3\u017aniej zajmiemy si\u0119 t\u0105 warto\u015bci\u0105. A trzeci parametr to obiekt wej\u015bciowy, kt\u00f3rego r\u00f3wnie\u017c nie b\u0119dziemy potrzebowa\u0107 w naszym przyk\u0142adzie.<\/p>\n<p>Zacznijmy od implementacji <code>get_field_input()<\/code>, kt\u00f3ra oczekuje ostatecznego renderowania jako ci\u0105gu. Prosto z nietoperza postanawiam zwr\u00f3ci\u0107 pusty ci\u0105g, je\u015bli jeste\u015bmy w edytorze formularzy \u2013 poniewa\u017c nie chc\u0119 renderowa\u0107 pe\u0142nej tabeli w tym widoku. Mo\u017cemy u\u017cy\u0107 tej metody, <code>$this-&gt;is_form_editor()<\/code>aby sprawdzi\u0107, czy jeste\u015bmy w edycji formularza. Mo\u017cesz to pomin\u0105\u0107 lub wyrenderowa\u0107 co\u015b innego, je\u015bli chcesz wy\u015bwietli\u0107 podgl\u0105d pola w edytorze formularzy.<\/p>\n<pre><code>public function get_field_input($form, $value = '', $entry = null) {\n    if ($this-&gt;is_form_editor()) {\n        return '';\n    }\n    \/\/ .. Rest of code for frontend and edit entry here...\n}<\/code><\/pre>\n<p>Nast\u0119pnym krokiem jest zbudowanie kodu HTML tabeli, kt\u00f3ra zap\u0119tla si\u0119 przez tablic\u0119 dni w celu wygenerowania kolumn i wierszy dla ka\u017cdego elementu kursu. Ale poniewa\u017c potrzebujemy dost\u0119pu do tablicy dni (kolumn tabeli) w wielu miejscach, powinni\u015bmy zdefiniowa\u0107 j\u0105 jako zmienn\u0105 klasy, dzi\u0119ki czemu jest dost\u0119pna z dowolnych funkcji w niej zawartych. Definiuj\u0119 zmienn\u0105 klasy <code>$delivery_days<\/code>z tablic\u0105 dni, na kt\u00f3re chc\u0119 zaoferowa\u0107 dostaw\u0119.<\/p>\n<pre><code>class FoodDelivery extends GF_Field {\n    public $type = 'food_delivery';\n\u00a0\n    private $delivery_days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'];\n\u00a0\n    public function get_form_editor_field_title() {\n        ...\n}<\/code><\/pre>\n<p>To tylko przyk\u0142ad! Mo\u017cesz chcie\u0107 pobra\u0107 tablic\u0119 dla kolumn z innego miejsca, kt\u00f3re nie jest zakodowane na sta\u0142e.<\/p>\n<p>Wr\u00f3\u0107my <code>get_field_input()<\/code>i zbudujmy nasz\u0105 tabel\u0119 z danymi wej\u015bciowymi. Najpierw zap\u0119tl\u0119 zmienn\u0105 klasy i wygeneruj\u0119 nag\u0142\u00f3wki tabeli. Nast\u0119pnie przegl\u0105dam opcje wprowadzone w ustawieniach pola dla opcji Wybory. Jest to dost\u0119pne ze zmiennej klasy (from <code>GF_Field<\/code>) <code>$this-&gt;choices<\/code>. Dla ka\u017cdego wyboru renderuj\u0119 dane wej\u015bciowe z odpowiednimi atrybutami nazwy. Mamy dost\u0119p do identyfikatora pola ze <code>GF_Field<\/code>zmiennej klasy <code>$this-&gt;id<\/code>.<\/p>\n<pre><code>public function get_field_input($form, $value = '', $entry = null) {\n    if ($this-&gt;is_form_editor()) {\n        return '';\n    }\n\u00a0\n    $id = (int) $this-&gt;id;\n    $table = '&lt;table class=\"delivery-table\"&gt;&lt;tbody&gt;&lt;tr&gt;';\n    $table .= '&lt;th&gt;'. __('Course', 'txtdomain'). '&lt;\/th&gt;';\n    foreach ($this-&gt;delivery_days as $day) {\n        $table .= '&lt;th&gt;'. $day. '&lt;\/th&gt;';\n    }\n    $table .= '&lt;\/tr&gt;';\n\u00a0\n    foreach ($this-&gt;choices as $course) {\n        $table .= '&lt;tr&gt;';\n        $table .= '&lt;td&gt;'. $course['text']. '&lt;\/td&gt;';\n        foreach ($this-&gt;delivery_days as $day) {\n            $table .= '&lt;td&gt;&lt;input type=\"number\" size=\"1\" name=\"input_'. $id. '[]\" \/&gt;&lt;\/td&gt;';\n        }\n        $table .= '&lt;\/tr&gt;';\n    }\n    $table .= '&lt;\/tbody&gt;&lt;\/table&gt;';\n\u00a0\n    return $table;\n}<\/code><\/pre>\n<p>Z tym kodem powinni\u015bmy otrzyma\u0107 \u0142adn\u0105 tabel\u0119 wyrenderowan\u0105 dla naszego typu pola w interfejsie u\u017cytkownika! Oczywi\u015bcie HTML zale\u017cy wy\u0142\u0105cznie od Ciebie, to tylko podstawowy przyk\u0142ad.<\/p>\n<p><strong>Na razie zostawiamy t\u0119 funkcj\u0119, ale wr\u00f3cimy do niej p\u00f3\u017aniej, aby obs\u0142u\u017cy\u0107 przes\u0142an\u0105 warto\u015b\u0107!<\/strong><\/p>\n<h2>Prawid\u0142owe przechowywanie warto\u015bci<\/h2>\n<p>W tej chwili Gravity Forms zapisze nasze pole jako jednowymiarow\u0105 tablic\u0119 wype\u0142nion\u0105 wprowadzonymi warto\u015bciami i pustymi ci\u0105gami, w kt\u00f3rych dane wej\u015bciowe by\u0142y puste. Poza indeksem nie ma informacji o dniu lub wyborze, do kt\u00f3rego nale\u017cy warto\u015b\u0107. Musimy przekszta\u0142ci\u0107 t\u0119 jednowymiarow\u0105 tablic\u0119 w wielowymiarow\u0105 tablic\u0119 asocjacyjn\u0105, w kt\u00f3rej przechowujemy dzie\u0144 i etykiet\u0119 wyboru. Mo\u017cemy wtedy \u0142atwo uzyska\u0107 dost\u0119p do zapisanej warto\u015bci liczbowej, np <code>$value['Ham sandwich']['Monday']<\/code>.. Po tej transformacji tablicy musimy r\u00f3wnie\u017c serializowa\u0107 tablic\u0119, aby Gravity Forms mog\u0142a prawid\u0142owo przechowywa\u0107 warto\u015b\u0107 w bazie danych.<\/p>\n<p>B\u0119dziemy musieli przekszta\u0142ci\u0107 t\u0119 tablic\u0119 warto\u015bci w wiele miejsc, wi\u0119c zdefiniuj\u0119 do tego osobn\u0105 funkcj\u0119. Funkcja akceptuje tablic\u0119 jednowymiarow\u0105 i przekszta\u0142ca j\u0105 w tablic\u0119 wielowymiarow\u0105 z przechowywanymi warto\u015bciami dla dni i wybor\u00f3w:<\/p>\n<pre><code>private function translateValueArray($value) {\n    if (empty($value)) {\n        return [];\n    }\n    $table_value = [];\n    $counter = 0;\n    foreach ($this-&gt;choices as $course) {\n        foreach ($this-&gt;delivery_days as $day) {\n            $table_value[$course['text']][$day] = $value[$counter++];\n        }\n    }\n    return $table_value;\n}<\/code><\/pre>\n<p>Spowoduje to zapisanie nazw dni i wybor\u00f3w bezpo\u015brednio w warto\u015bci pola. Robienie tego w ten spos\u00f3b umo\u017cliwia p\u00f3\u017aniejsz\u0105 zmian\u0119 wybor\u00f3w bez naruszania starych wpis\u00f3w.<\/p>\n<p>Przejd\u017amy teraz do nadpisania funkcji obs\u0142uguj\u0105cej przechowywanie przes\u0142anej warto\u015bci; <code>get_value_save_entry()<\/code>. Ma pi\u0119\u0107 parametr\u00f3w, ale potrzebujemy tylko pierwszego, kt\u00f3ry jest przes\u0142an\u0105 warto\u015bci\u0105. Wewn\u0105trz funkcji przekazujemy warto\u015b\u0107 do naszej funkcji niestandardowej powy\u017cej, serializujemy jej zwrot i ostatecznie zwracamy now\u0105 warto\u015b\u0107.<\/p>\n<pre><code>public function get_value_save_entry($value, $form, $input_name, $lead_id, $lead) {\n    if (empty($value)) {\n        $value = '';\n    } else {\n        $table_value = $this-&gt;translateValueArray($value);\n        $value = serialize($table_value);\n    }\n    return $value;\n}<\/code><\/pre>\n<p>W tym momencie Gravity Forms z powodzeniem przechowa nasze warto\u015bci tak, jak tego chcemy! Jednak przechowywana warto\u015b\u0107 jest teraz zserializowan\u0105 tablic\u0105, kt\u00f3r\u0105 Gravity Forms z rado\u015bci\u0105 odezwie si\u0119 wprost. Musimy zaimplementowa\u0107 funkcje, aby przekszta\u0142ci\u0107 go z brzydkiej zserializowanej tablicy w jakie\u015b \u0142adne wyj\u015bcie, gdziekolwiek tego potrzebujemy.<\/p>\n<h2>Wy\u015bwietlanie przes\u0142anej warto\u015bci<\/h2>\n<p>S\u0105 trzy miejsca, w kt\u00f3rych musimy zmieni\u0107 wyj\u015bcie warto\u015bci naszego pola; list\u0119 wpis\u00f3w, patrz\u0105c na pojedynczy wpis i w obr\u0119bie znacznik\u00f3w scalania Gravity Forms. Tagi scalania s\u0105 najcz\u0119\u015bciej u\u017cywane w powiadomieniach e-mail. Przyk\u0142adem <code>{all_fields}<\/code>mo\u017ce by\u0107 znacznik scalania, kt\u00f3ry wy\u015bwietla pe\u0142ne warto\u015bci przes\u0142anego formularza w wiadomo\u015bciach e-mail.<\/p>\n<p>Poniewa\u017c renderujemy to samo wyj\u015bcie w trzech r\u00f3\u017cnych przypadkach, sensowne jest utworzenie dla niego oddzielnej funkcji. Zdefiniowa\u0142em funkcj\u0119 niestandardow\u0105, kt\u00f3ra akceptuje warto\u015b\u0107; nieserializowana tablica wielowymiarowa jako parametr. Funkcja nast\u0119pnie buduje kod HTML, kt\u00f3ry wy\u015bwietla tablic\u0119 w \u0142adny spos\u00f3b i zwraca ci\u0105g. Zdecydowa\u0142em si\u0119 na <code>&lt;ul&gt;<\/code>list\u0119 zagnie\u017cd\u017con\u0105, ale mo\u017cesz zmieni\u0107 wynik w dowolny spos\u00f3b.<\/p>\n<pre><code>private function prettyListOutput($value) {\n    $str = '&lt;ul&gt;';\n    foreach ($value as $course =&gt; $days) {\n        $week = '';\n        foreach ($days as $day =&gt; $delivery_number) {\n            if (!empty($delivery_number)) {\n                $week .= '&lt;li&gt;'. $day. ': '. $delivery_number. '&lt;\/li&gt;';\n            }\n        }\n        \/\/ Only add week if there were any requests at all\n        if (!empty($week)) {\n            $str .= '&lt;li&gt;&lt;h3&gt;'. $course. '&lt;\/h3&gt;&lt;ul class=\"days\"&gt;'. $week. '&lt;\/ul&gt;&lt;\/li&gt;';\n        }\n    }\n    $str .= '&lt;\/ul&gt;';\n    return $str;\n}<\/code><\/pre>\n<p>\u015awietnie, zacznijmy od pierwszego: listy wpis\u00f3w: <code>get_value_entry_list()<\/code>. Mo\u017cesz wybra\u0107, aby wy\u015bwietli\u0107 pe\u0142ne dane wyj\u015bciowe tutaj, ale widok listy mo\u017ce by\u0107 do\u015b\u0107 niezgrabny i d\u0142ugi, wi\u0119c zdecydowa\u0142em si\u0119 po prostu zwr\u00f3ci\u0107 sta\u0142y ci\u0105g, kt\u00f3ry wyja\u015bnia, \u017ce \u200b\u200bu\u017cytkownik musi przej\u015b\u0107 do szczeg\u00f3\u0142\u00f3w wpisu, aby zobaczy\u0107 pe\u0142ny przegl\u0105d.<\/p>\n<pre><code>public function get_value_entry_list($value, $entry, $field_id, $columns, $form) {\n    return __('Enter details to see delivery details', 'txtdomain');\n}<\/code><\/pre>\n<p>To oczywi\u015bcie zale\u017cy wy\u0142\u0105cznie od Ciebie, mo\u017cesz na przyk\u0142ad wybra\u0107 wy\u015bwietlanie tylko pierwszej liczby x znak\u00f3w.<\/p>\n<p>Druga funkcja to ta, kt\u00f3ra wp\u0142ywa na widok pojedynczego wpisu: <code>get_value_entry_detail()<\/code>:<\/p>\n<pre><code>public function get_value_entry_detail($value, $currency = '', $use_text = false, $format = 'html', $media = 'screen') {\n    $value = maybe_unserialize($value);     \n    if (empty($value)) {\n        return '';\n    }\n    $str = $this-&gt;prettyListOutput($value);\n    return $str;\n}<\/code><\/pre>\n<p>Po prostu usuwamy numer seryjny tablicy za pomoc\u0105 funkcji WordPressa <code>[maybe_unserialize](https:\/\/developer.wordpress.org\/reference\/functions\/maybe_unserialize\/)()<\/code>i zwracamy wynik ci\u0105gu z naszej niestandardowej funkcji.<\/p>\n<p>Ostatnia funkcja wp\u0142ywa na znaczniki scalania i zapewnia, \u017ce \u200b\u200bwarto\u015b\u0107 naszego pola wygl\u0105da dobrze r\u00f3wnie\u017c w wiadomo\u015bciach e-mail: <code>get_value_merge_tag()<\/code>.<\/p>\n<pre><code>public function get_value_merge_tag($value, $input_id, $entry, $form, $modifier, $raw_value, $url_encode, $esc_html, $format, $nl2br) {\n    return $this-&gt;prettyListOutput($value);\n}<\/code><\/pre>\n<p>Zwr\u00f3\u0107 uwag\u0119, \u017ce nie b\u0119dziemy musieli usuwa\u0107 numeru seryjnego warto\u015bci wewn\u0105trz tej funkcji.<\/p>\n<p>Dzi\u0119ki tym trzem funkcjom wszystkie przes\u0142ane warto\u015bci powinny wsz\u0119dzie wygl\u0105da\u0107 ca\u0142kiem dobrze! Na przyk\u0142ad podczas przegl\u0105dania przes\u0142anego wpisu:<\/p>\n<p><a href=\"https:\/\/wordpress.mediadoma.com\/wp-content\/uploads\/2022\/01\/post-153179-61e509dbe8f8c.png\" data-rel=\"lightbox\"><img decoding=\"async\" class=\"SDStudio-light-box-enable SDStudio-editor-tools-md-imp\" src=\"https:\/\/wordpress.mediadoma.com\/wp-content\/uploads\/2022\/01\/post-153179-61e509dbe8f8c.png\" alt=\"Samouczek: Tworzenie zaawansowanego niestandardowego typu pola formularzy grawitacyjnych i jak obs\u0142ugiwa\u0107 wiele warto\u015bci wej\u015bciowych\" ><\/a><\/p>\n<p>Brakuje jednak jednej wa\u017cnej rzeczy! W tym momencie nasze dane wej\u015bciowe nie zachowuj\u0105 wcze\u015bniej przes\u0142anych warto\u015bci, a to jest do\u015b\u0107 z\u0142e.<\/p>\n<h2>Spraw, aby nasze dane wej\u015bciowe zachowa\u0142y wcze\u015bniej przes\u0142an\u0105 warto\u015b\u0107<\/h2>\n<p>Istniej\u0105 g\u0142\u00f3wnie dwa przypadki, w kt\u00f3rych musimy upewni\u0107 si\u0119, \u017ce dane wej\u015bciowe zachowuj\u0105 wcze\u015bniej przes\u0142ane warto\u015bci. Pierwszy przypadek ma miejsce, gdy przes\u0142anie formularza nie powiod\u0142o si\u0119 (na przyk\u0142ad u\u017cytkownik zapomnia\u0142 wymaganego pola). W tej chwili wszystkie nasze dane wej\u015bciowe trac\u0105 wszystkie wcze\u015bniej wprowadzone warto\u015bci, a u\u017cytkownik musi ponownie wprowadzi\u0107 wszystkie warto\u015bci. Po drugie, gdy w\u0142a\u015bciciel witryny edytuje wpis, dane wej\u015bciowe nie s\u0105 wype\u0142niane przes\u0142anymi warto\u015bciami ze zg\u0142oszenia \u2013 co uniemo\u017cliwia prawid\u0142ow\u0105 edycj\u0119 warto\u015bci.<\/p>\n<p>Aby to naprawi\u0107, wracamy do funkcji <code>get_field_input()<\/code>. Drugim parametrem tej funkcji jest warto\u015b\u0107. Pami\u0119taj jednak, \u017ce ta funkcja wp\u0142ywa zar\u00f3wno na renderowanie frontendu, jak i edycj\u0119 wpis\u00f3w. Jest to wa\u017cne, poniewa\u017c przechowywana warto\u015b\u0107 jest r\u00f3\u017cna w tych dw\u00f3ch przypadkach. Je\u015bli jeste\u015bmy na froncie i obs\u0142ugujemy przesy\u0142anie formularzy, warto\u015b\u0107 jest w formacie tablicy jednowymiarowej, o kt\u00f3rej mowa wcze\u015bniej. A je\u015bli edytujemy wpis, warto\u015b\u0107 jest w formacie szeregowanej tablicy wielowymiarowej. Musimy wi\u0119c odpowiednio przet\u0142umaczy\u0107 podan\u0105 warto\u015b\u0107, <code>get_field_input()<\/code>aby \u0142atwo uzyska\u0107 dost\u0119p do rzeczywistych warto\u015bci.<\/p>\n<pre><code>public function get_field_input($form, $value = '', $entry = null) {\n    if ($this-&gt;is_form_editor()) {\n        return '';\n    }\n\u00a0\n    $id = (int) $this-&gt;id;\n    if ($this-&gt;is_entry_detail()) {\n        $table_value = maybe_unserialize($value);\n    } else {\n        $table_value = $this-&gt;translateValueArray($value);\n    }\n\u00a0\n    $table = '&lt;table class=\"delivery-table\"&gt;&lt;tbody&gt;&lt;tr&gt;';\n    ...\n}<\/code><\/pre>\n<p>W powy\u017cszym kodzie, zanim zaczniemy tworzy\u0107 kod HTML dla wyj\u015bcia pola, tworzymy zmienn\u0105 <code>$table_value<\/code>zawieraj\u0105c\u0105 poprawnie przet\u0142umaczon\u0105 warto\u015b\u0107. U\u017cywamy <code>GF_Field<\/code>funkcji, <code>is_entry_detail()<\/code>aby sprawdzi\u0107, czy edytujemy wpis, czy nie. A nast\u0119pnie dla naszych danych wej\u015bciowych \u0142atwo jest uzyska\u0107 dost\u0119p do odpowiednich warto\u015bci i ustawi\u0107 je jako <code>value<\/code>atrybuty danych wej\u015bciowych:<\/p>\n<pre><code>...\nforeach ($this-&gt;delivery_days as $day) {\n    $table .= '&lt;td&gt;&lt;input type=\"number\" size=\"1\" name=\"input_'. $id. '[]\" value=\"'. $table_value[$course['text']][$day]. '\" \/&gt;&lt;\/td&gt;';\n}\n...<\/code><\/pre>\n<p>Po zaktualizowaniu powy\u017cszego <code>get_field_input()<\/code>wszystkie nasze niestandardowe dane wej\u015bciowe powinny zawsze by\u0107 wype\u0142nione poprzedni\u0105 warto\u015bci\u0105; bez wzgl\u0119du na to, czy edytujesz wpis, czy ponawiasz pr\u00f3b\u0119 przes\u0142ania formularza.<\/p>\n<p>W tym momencie wszystko, co dotyczy renderowania i przechowywania naszych warto\u015bci, jest ju\u017c gotowe i w pe\u0142ni dzia\u0142a. Ale jest jeszcze jedna rzecz, kt\u00f3r\u0105 zdecydowanie musimy naprawi\u0107.<\/p>\n<h2>Spraw, aby nasza przepustka terenowa by\u0142a \u201ewymagana&#8221; walidacja<\/h2>\n<p>Formy grawitacyjne maj\u0105 kontrole, aby sprawdzi\u0107, czy warto\u015b\u0107 pola jest pusta, czy nie. Jest to cz\u0119sto konieczne, gdy pole jest ustawione zgodnie z wymaganiami. Gdy pole jest wymagane, nie mo\u017cesz przes\u0142a\u0107 formularza, je\u015bli jest puste, prawda? Problemem jest dla nas to, \u017ce mamy wiele wej\u015b\u0107 i chcemy, aby niekt\u00f3re z nich by\u0142y puste. Staje si\u0119 to problemem, je\u015bli nasze pole jest ustawione na wymagane. Gravity Forms niestety \u017ale interpretuje \u201eczy to jest puste&#8221; i wymaga wype\u0142nienia wszystkich danych wej\u015bciowych. Musimy wi\u0119c doda\u0107 regu\u0142\u0119, kt\u00f3ra m\u00f3wi, \u017ce je\u015bli przynajmniej jedno z wielu danych wej\u015bciowych jest wype\u0142nione, ca\u0142kowita warto\u015b\u0107 pola nie jest pusta.<\/p>\n<p>Ostatni\u0105 funkcj\u0105, kt\u00f3r\u0105 musimy przes\u0142oni\u0107 w naszej klasie, jest <code>is_value_submission_empty()<\/code>. Jako parametr tej funkcji otrzymujemy tylko identyfikator formularza, wi\u0119c musimy wyodr\u0119bni\u0107 warto\u015b\u0107 pola za pomoc\u0105 funkcji Gravity Forms, aby pobra\u0107 j\u0105 z <code>$_POST<\/code>tablicy: <code>rgpost('input_&lt;FIELD ID&gt;')<\/code>. Zwrot powinien by\u0107 jednowymiarow\u0105 tablic\u0105, kt\u00f3r\u0105 widzieli\u015bmy wcze\u015bniej. Wszystko, co musimy zrobi\u0107, to przej\u015b\u0107 przez tablic\u0119 i wr\u00f3ci\u0107 <code>false<\/code>, je\u015bli gdzie\u015b znajdziemy warto\u015b\u0107. W przeciwnym razie zwracamy, <code>true<\/code>poniewa\u017c warto\u015b\u0107 pola jest rzeczywi\u015bcie ca\u0142kowicie pusta.<\/p>\n<pre><code>public function is_value_submission_empty($form_id) {\n    $value = rgpost('input_'. $this-&gt;id);\n    foreach ($value as $input) {\n        if (strlen(trim($input)) &gt; 0) {\n            return false;\n        }\n    }\n    return true;\n}<\/code><\/pre>\n<p>Z powy\u017csz\u0105 funkcj\u0105 w miejscu, nasze pole nie zawiedzie, je\u015bli jest ustawione na wymagane i co najmniej jedno wej\u015bcie jest wype\u0142nione.<\/p>\n<h2>Wniosek i kod ko\u0144cowy<\/h2>\n<p>Ten samouczek pokaza\u0142 ci szczeg\u00f3\u0142owo, jak stworzy\u0107 w\u0142asny niestandardowy zaawansowany typ pola dla Gravity Forms. Nawet je\u015bli tw\u00f3j projekt jest inny ni\u017c m\u00f3j przyk\u0142ad, mam nadziej\u0119, \u017ce masz kilka wskaz\u00f3wek i a-ha po drodze. W niekt\u00f3rych przypadkach brakuje mi dokumentacji Gravity Forms, co jest wynikiem wielu pr\u00f3b i b\u0142\u0119d\u00f3w! W ka\u017cdym razie, miejmy nadziej\u0119, \u017ce przyda\u0142o ci si\u0119 to!<\/p>\n<p>Dla odniesienia, oto kompletny kod w ca\u0142o\u015bci:<\/p>\n<pre><code>if (class_exists('GF_Field')) {\n    class FoodDelivery extends GF_Field {\n        public $type = 'food_delivery';\n\u00a0\n        public $choices = [\n            [ 'text' =&gt; 'Food Choice 1' ],\n            [ 'text' =&gt; 'Food Choice 2' ],\n            [ 'text' =&gt; 'Food Choice 3' ],\n        ];\n\u00a0\n        private $delivery_days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'];\n\u00a0\n        public function get_form_editor_field_title() {\n            return esc_attr__('Food Delivery', 'txtdomain');\n        }\n\u00a0\n        public function get_form_editor_button() {\n            return [\n                'group' =&gt; 'advanced_fields',\n                'text'  =&gt; $this-&gt;get_form_editor_field_title(),\n            ];\n        }\n\u00a0\n        public function get_form_editor_field_settings() {\n            return [\n                'label_setting',\n                'choices_setting',\n                'description_setting',\n                'rules_setting',\n                'error_message_setting',\n                'css_class_setting',\n                'conditional_logic_field_setting',\n            ];\n        }\n\u00a0\n        public function is_value_submission_array() {\n            return true;\n        }\n\u00a0\n        public function get_field_input($form, $value = '', $entry = null) {\n            if ($this-&gt;is_form_editor()) {\n                return '';\n            }\n\u00a0\n            $id = (int) $this-&gt;id;\n            if ($this-&gt;is_entry_detail()) {\n                $table_value = maybe_unserialize($value);\n            } else {\n                $table_value = $this-&gt;translateValueArray($value);\n            }\n\u00a0\n            $table = '&lt;table class=\"delivery-table\"&gt;&lt;tbody&gt;&lt;tr&gt;';\n            $table .= '&lt;th&gt;'. __('Course', 'txtdomain'). '&lt;\/th&gt;';\n            foreach ($this-&gt;delivery_days as $day) {\n                $table .= '&lt;th&gt;'. $day. '&lt;\/th&gt;';\n            }\n            $table .= '&lt;\/tr&gt;';\n\u00a0\n            foreach ($this-&gt;choices as $course) {\n                $table .= '&lt;tr&gt;';\n                $table .= '&lt;td&gt;'. $course['text']. '&lt;\/td&gt;';\n                foreach ($this-&gt;delivery_days as $day) {\n                    $table .= '&lt;td&gt;&lt;input type=\"number\" size=\"1\" name=\"input_'. $id. '[]\" value=\"'. $table_value[$course['text']][$day]. '\" \/&gt;&lt;\/td&gt;';\n                }\n                $table .= '&lt;\/tr&gt;';\n            }\n\u00a0\n            $table .= '&lt;\/tbody&gt;&lt;\/table&gt;';\n\u00a0\n            return $table;\n        }\n\u00a0\n        private function translateValueArray($value) {\n            if (empty($value)) {\n                return [];\n            }\n            $table_value = [];\n            $counter = 0;\n            foreach ($this-&gt;choices as $course) {\n                foreach ($this-&gt;delivery_days as $day) {\n                    $table_value[$course['text']][$day] = $value[$counter++];\n                }\n            }\n            return $table_value;\n        }\n\u00a0\n        public function get_value_save_entry($value, $form, $input_name, $lead_id, $lead) {\n            if (empty($value)) {\n                $value = '';\n            } else {\n                $table_value = $this-&gt;translateValueArray($value);\n                $value = serialize($table_value);\n            }\n            return $value;\n        }\n\u00a0\n        private function prettyListOutput($value) {\n            $str = '&lt;ul&gt;';\n            foreach ($value as $course =&gt; $days) {\n                $week = '';\n                foreach ($days as $day =&gt; $delivery_number) {\n                    if (!empty($delivery_number)) {\n                        $week .= '&lt;li&gt;'. $day. ': '. $delivery_number. '&lt;\/li&gt;';\n                    }\n                }\n                \/\/ Only add week if there were any requests at all\n                if (!empty($week)) {\n                    $str .= '&lt;li&gt;&lt;h3&gt;'. $course. '&lt;\/h3&gt;&lt;ul class=\"days\"&gt;'. $week. '&lt;\/ul&gt;&lt;\/li&gt;';\n                }\n            }\n            $str .= '&lt;\/ul&gt;';\n            return $str;\n        }\n\u00a0\n        public function get_value_entry_list($value, $entry, $field_id, $columns, $form) {\n            return __('Enter details to see delivery details', 'txtdomain');\n        }\n\u00a0\n        public function get_value_entry_detail($value, $currency = '', $use_text = false, $format = 'html', $media = 'screen') {\n            $value = maybe_unserialize($value);     \n            if (empty($value)) {\n                return $value;\n            }\n            $str = $this-&gt;prettyListOutput($value);\n            return $str;\n        }\n\u00a0\n        public function get_value_merge_tag($value, $input_id, $entry, $form, $modifier, $raw_value, $url_encode, $esc_html, $format, $nl2br) {\n            return $this-&gt;prettyListOutput($value);\n        }\n\u00a0\n        public function is_value_submission_empty($form_id) {\n            $value = rgpost('input_'. $this-&gt;id);\n            foreach ($value as $input) {\n                if (strlen(trim($input)) &gt; 0) {\n                    return false;\n                }\n            }\n            return true;\n        }\n    }\n    GF_Fields::register(new FoodDelivery());\n}<\/code><\/pre>\n<p><div id=\"PostUnique_PostSource\" style=\"padding-top: 50px\">\u0179r\u00f3d\u0142o nagrywania:  <a target=\"_blank\" rel=\"noopener nofollow\" href=\"\/\/awhitepixel.com\" class=\"external external_icon\">awhitepixel.com<\/a><\/div><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Samouczek pokazuj\u0105cy, jak utworzy\u0107 zaawansowany niestandardowy typ pola Gravity Forms z wieloma danymi wej\u015bciowymi ze specjaln\u0105 obs\u0142ug\u0105 do przechowywania i wy\u015bwietlania warto\u015bci.<\/p>\n","protected":false},"author":1,"featured_media":153180,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","_wp_rev_ctl_limit":""},"categories":[897,897,1110,805,805,815,845,845,866,866,815],"tags":[1169],"class_list":{"0":"post-233480","1":"post","2":"type-post","3":"status-publish","4":"format-standard","5":"has-post-thumbnail","6":"hentry","7":"category-kod","9":"category-n-a","10":"category-php-7","12":"category-wtyczki","13":"category-samouczki","15":"category-wordpress-7","18":"tag-affiai-pl"},"_links":{"self":[{"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/posts\/233480","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=233480"}],"version-history":[{"count":0,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/posts\/233480\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/media\/153180"}],"wp:attachment":[{"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/media?parent=233480"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/categories?post=233480"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/tags?post=233480"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}