{"id":233507,"date":"2023-02-15T17:22:00","date_gmt":"2023-02-15T14:22:00","guid":{"rendered":"https:\/\/wordpress.mediadoma.com\/?p=233507"},"modified":"2022-11-11T00:04:09","modified_gmt":"2022-11-10T21:04:09","slug":"tutorial-criar-um-tipo-de-campo-de-formularios-de-gravidade-personalizados-avancados-e-como-lidar-com-varios-valores-de-entrada","status":"publish","type":"post","link":"https:\/\/wordpress.mediadoma.com\/pt-pt\/tutorial-criar-um-tipo-de-campo-de-formularios-de-gravidade-personalizados-avancados-e-como-lidar-com-varios-valores-de-entrada\/","title":{"rendered":"Tutorial: Criar um tipo de campo de formul\u00e1rios de gravidade personalizados avan\u00e7ados e como lidar com v\u00e1rios valores de entrada"},"content":{"rendered":"\n<p>Neste tutorial, mostrarei como criar um tipo de campo personalizado avan\u00e7ado Gravity Forms. O campo ter\u00e1 v\u00e1rias entradas e precisar\u00e1 de tratamento especial para armazenar e exibir os valores enviados.<\/p>\n<h2>O que vamos fazer<\/h2>\n<p>Neste exemplo, estou assumindo um exemplo de propriet\u00e1rio de um site WordPress que lida com entregas de almo\u00e7o em um local de trabalho. O propriet\u00e1rio tem um formul\u00e1rio para as pessoas preencherem o tipo de almo\u00e7o que desejam e quantos para cada dia da semana. Isso pode ser resolvido como um m\u00e9todo semelhante a uma tabela de inserir um n\u00famero para qualquer curso em qualquer dia que eles desejem entregar.<\/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=\"Tutorial: Criar um tipo de campo de formul\u00e1rios de gravidade personalizados avan\u00e7ados e como lidar com v\u00e1rios valores de entrada\" ><\/a><\/p>\n<p>Os cursos s\u00e3o edit\u00e1veis \u200b\u200bnas configura\u00e7\u00f5es do campo no editor de formul\u00e1rios e podem ser alterados a qualquer momento. E para cada envio de formul\u00e1rio, o propriet\u00e1rio do site obt\u00e9m uma vis\u00e3o geral completa dos valores enviados:<\/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=\"Tutorial: Criar um tipo de campo de formul\u00e1rios de gravidade personalizados avan\u00e7ados e como lidar com v\u00e1rios valores de entrada\" ><\/a><\/p>\n<p>Obviamente, este \u00e9 apenas um exemplo e voc\u00ea provavelmente precisar\u00e1 ajustar isso ao seu caso. Mas com este caso de exemplo, temos a chance de aprender a lidar com v\u00e1rias entradas em um \u00fanico campo. Ele deve fornecer algumas ideias sobre como lidar com seu pr\u00f3prio tipo de campo personalizado.<\/p>\n<h2>Antes de come\u00e7ar a codificar<\/h2>\n<p>Antes de come\u00e7armos, precisamos de um lugar para adicionar nosso c\u00f3digo. Voc\u00ea pode adicionar isso no seu tema <code>functions.php<\/code>ou no seu arquivo de plugin.<\/p>\n<p>O m\u00e9todo que escolhi \u00e9 orientado a objetos, o que significa criar uma classe que estende a <code>GF_Field<\/code>classe do Gravity Forms. Eu recomendo colocar a classe em um arquivo separado em seu projeto. Voc\u00ea tamb\u00e9m deve verificar se o plug-in Gravity Forms existe antes de incluir sua classe para evitar travar seu site.<\/p>\n<p>Se voc\u00ea estiver interessado, pode dar uma olhada na <a href=\"https:\/\/docs.gravityforms.com\/gf_field\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">documenta\u00e7\u00e3o do Gravity Forms no GF_Field<\/a>. Voc\u00ea encontrar\u00e1 mais fun\u00e7\u00f5es e vari\u00e1veis \u200b\u200bque podem ser necess\u00e1rias para seu tipo de campo.<\/p>\n<p>Ao estender a <code>GF_Field<\/code>classe, podemos simplesmente optar por substituir as fun\u00e7\u00f5es que precisamos alterar. Quanto \u00e0s fun\u00e7\u00f5es que n\u00e3o substitu\u00edmos, o Gravity Forms executar\u00e1 o padr\u00e3o definido dentro do <code>GF_Field<\/code>. No tutorial abaixo, veremos cada fun\u00e7\u00e3o que precisamos substituir para nosso campo personalizado, uma por uma. Sem mais delongas, vamos come\u00e7ar!<\/p>\n<h2>Criando um tipo de campo personalizado<\/h2>\n<p>A primeira etapa \u00e9 definir uma classe PHP personalizada que estende arquivos <code>GF_Field<\/code>. D\u00ea um nome exclusivo \u00e0 classe e certifique-se de que ela esteja inclu\u00edda em seu projeto. Ap\u00f3s a defini\u00e7\u00e3o da classe, executamos a <code>register()<\/code>fun\u00e7\u00e3o est\u00e1tica <code>GF_Field<\/code>passando uma inst\u00e2ncia de nossa classe como par\u00e2metro. Isso inicializa nossa classe e registra o tipo de campo.<\/p>\n<p>A \u00fanica vari\u00e1vel necess\u00e1ria que voc\u00ea precisa dentro de sua classe \u00e9 <code>$type<\/code>. A vari\u00e1vel de classe <code>$type<\/code>deve ser exclusiva e \u00e9 um nome de slug do seu tipo de campo. No meu exemplo eu dei o nome de &#8216; <code>food_delivery<\/code>&#8216;.<\/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>Com este pequeno peda\u00e7o de c\u00f3digo, nosso tipo de campo personalizado deve ser adicionado como uma op\u00e7\u00e3o dispon\u00edvel no editor Gravity Forms. Por padr\u00e3o, ele aparece no final da caixa &quot;Campos padr\u00e3o&quot;. Como ainda n\u00e3o demos um nome pr\u00f3prio ao nosso campo (essa \u00e9 a pr\u00f3xima etapa), o bot\u00e3o \u00e9 rotulado como o valor de <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=\"Tutorial: Criar um tipo de campo de formul\u00e1rios de gravidade personalizados avan\u00e7ados e como lidar com v\u00e1rios valores de entrada\" ><\/a><\/p>\n<h2>Definindo o nome do campo<\/h2>\n<p>O pr\u00f3ximo passo \u00e9 f\u00e1cil; simplesmente dando ao nosso campo um nome melhor. Para fazer isso, sobrescrevemos a fun\u00e7\u00e3o <code>get_form_editor_field_title()<\/code>. Tudo o que precisamos fazer \u00e9 retornar uma string com o nome do campo.<\/p>\n<pre><code>public function get_form_editor_field_title() {\n    return esc_attr__('Food Delivery', 'txtdomain');\n}<\/code><\/pre>\n<p>Com esta fun\u00e7\u00e3o em nossa classe o bot\u00e3o para adicionar o campo \u00e9 atualizado com um r\u00f3tulo muito melhor.<\/p>\n<h2>Alterando a categoria do campo<\/h2>\n<p>Esta etapa \u00e9 opcional. Como padr\u00e3o, nosso tipo de campo personalizado aparece na caixa &quot;Campos padr\u00e3o&quot;, mas podemos alterar isso. Vamos supor que queremos que apare\u00e7a dentro da caixa &#8220;Advanced Fields&quot;.<\/p>\n<p>Para alterar a categoria em que queremos que o campo apare\u00e7a, sobrescrevemos a fun\u00e7\u00e3o <code>get_form_editor_button()<\/code>. Precisamos retornar um array associativo com dois elementos. Como valor para a chave &#8216; <code>group<\/code>&#8216; voc\u00ea fornece o nome interno da categoria na qual deseja que o bot\u00e3o apare\u00e7a. As op\u00e7\u00f5es dispon\u00edveis aqui s\u00e3o &#8216; <code>standard_fields<\/code>&#8216;, &#8216; <code>advanced_fields<\/code>&#8216;, &#8216; <code>post_fields<\/code>&#8216; ou &#8216; <code>pricing_fields<\/code>&#8216;. (Voc\u00ea tamb\u00e9m pode criar sua pr\u00f3pria categoria, mas isso n\u00e3o \u00e9 abordado aqui). O segundo elemento do array precisa da chave &#8216; <code>text<\/code>&#8216; e para isso simplesmente retornamos o nome do campo chamando <code>get_form_editor_field_title()<\/code>. Esta \u00e9 a fun\u00e7\u00e3o que acabamos de criar acima.<\/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>Agora o bot\u00e3o para adicionar nosso tipo de campo personalizado \u00e9 movido para a caixa &#8220;Campos Avan\u00e7ados&#8221;.<\/p>\n<h2>Ativando as configura\u00e7\u00f5es de campo<\/h2>\n<p>Se voc\u00ea tentou adicionar o tipo de campo em um formul\u00e1rio, deve ter notado que n\u00e3o h\u00e1 nenhuma configura\u00e7\u00e3o. Voc\u00ea n\u00e3o pode nem editar o r\u00f3tulo. A maneira como isso funciona \u00e9 que todos os tipos de configura\u00e7\u00f5es realmente est\u00e3o l\u00e1, eles est\u00e3o simplesmente todos ocultos com CSS por Gravity Forms. Precisamos definir individualmente quais configura\u00e7\u00f5es queremos habilitar, e o Gravity Forms exibir\u00e1 as configura\u00e7\u00f5es escolhidas para n\u00f3s.<\/p>\n<p>Precisamos definir a fun\u00e7\u00e3o <code>get_form_editor_field_settings()<\/code>e retornar um array de todas as configura\u00e7\u00f5es que n\u00e3o queremos ocultar para nosso tipo de campo. Quais configura\u00e7\u00f5es voc\u00ea deseja adicionar depende inteiramente de voc\u00ea e do seu projeto. Lembre-se de que seu campo deve oferecer suporte a quaisquer configura\u00e7\u00f5es que voc\u00ea ativar, caso contr\u00e1rio, n\u00e3o faz sentido mostrar uma configura\u00e7\u00e3o para ele.<\/p>\n<p>Eu criei uma vis\u00e3o geral r\u00e1pida dos nomes das configura\u00e7\u00f5es abaixo. Isso est\u00e1 longe de ser uma lista completa &#8211; porque h\u00e1 muitas configura\u00e7\u00f5es que s\u00e3o \u00fateis apenas para tipos de campo muito espec\u00edficos. Por exemplo, formato de telefone, formato de data\/hora e v\u00e1rias configura\u00e7\u00f5es relacionadas a campos de postagem e campos de pre\u00e7os.<\/p>\n<h4>Guia geral<\/h4>\n<ul>\n<li>Legenda do campo:<code>label_setting<\/code><\/li>\n<li>Descri\u00e7\u00e3o do campo:<code>description_setting<\/code><\/li>\n<li>Escolhas:<code>choices_setting<\/code><\/li>\n<li>Requeridos:<code>rules_setting<\/code><\/li>\n<li>Sem duplicatas:<code>duplicate_setting<\/code><\/li>\n<li>Ativar colunas:<code>columns_setting<\/code><\/li>\n<li>Habilite a op\u00e7\u00e3o &#8220;selecionar tudo&#8221;:<code>select_all_choices_setting<\/code><\/li>\n<li>Habilite a op\u00e7\u00e3o &#8220;outro&#8221;:<code>other_choice_setting<\/code><\/li>\n<\/ul>\n<h4>Aba Apar\u00eancia<\/h4>\n<ul>\n<li>Espa\u00e7o reservado:<code>placeholder_setting<\/code><\/li>\n<li>Visibilidade do r\u00f3tulo do campo e posicionamento da descri\u00e7\u00e3o:<code>label_placement_setting<\/code><\/li>\n<li>Mensagem de valida\u00e7\u00e3o personalizada:<code>error_message_setting<\/code><\/li>\n<li>Classe CSS personalizada:<code>css_class_setting<\/code><\/li>\n<li>Tamanho do campo:<code>size_setting<\/code><\/li>\n<\/ul>\n<h4>Guia Avan\u00e7ado<\/h4>\n<ul>\n<li>R\u00f3tulo do campo de administrador:<code>admin_label_setting<\/code><\/li>\n<li>Valor padr\u00e3o:<code>default_value_setting<\/code><\/li>\n<li>Habilitar entrada de senha:<code>password_field_setting<\/code><\/li>\n<li>For\u00e7a SSL:<code>force_ssl_field_setting<\/code><\/li>\n<li>Visibilidade:<code>visibility_setting<\/code><\/li>\n<li>Permitir que o campo seja preenchido dinamicamente:<code>prepopulate_field_setting<\/code><\/li>\n<li>Habilite a l\u00f3gica condicional:<code>conditional_logic_field_setting<\/code><\/li>\n<li>Ative a l\u00f3gica condicional da p\u00e1gina:<code>conditional_logic_page_setting<\/code><\/li>\n<\/ul>\n<p>Quanto ao nosso exemplo, os mais importantes s\u00e3o o r\u00f3tulo do campo, descri\u00e7\u00e3o, op\u00e7\u00f5es e se o campo \u00e9 obrigat\u00f3rio ou n\u00e3o. Tamb\u00e9m permitimos configura\u00e7\u00f5es para classe CSS, mensagem de valida\u00e7\u00e3o personalizada e l\u00f3gica condicional.<\/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>Atualize o editor de formul\u00e1rios e agora voc\u00ea deve ver todas as configura\u00e7\u00f5es e guias escolhidas aparecerem dentro do nosso campo. Todas as configura\u00e7\u00f5es s\u00e3o tratadas e salvas automaticamente pelo Gravity Forms.<\/p>\n<p>V\u00e1 em frente e adicione alguns itens na lista de op\u00e7\u00f5es para que tenhamos algo para trabalhar. Aqui est\u00e1 o que eu configurei como exemplo:<\/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=\"Tutorial: Criar um tipo de campo de formul\u00e1rios de gravidade personalizados avan\u00e7ados e como lidar com v\u00e1rios valores de entrada\" ><\/a><\/p>\n<h2>Definindo op\u00e7\u00f5es padr\u00e3o personalizadas<\/h2>\n<p>Se voc\u00ea est\u00e1 acostumado a usar, por exemplo, bot\u00f5es de r\u00e1dio ou caixas de sele\u00e7\u00e3o em Gravity Forms, voc\u00ea provavelmente notou que eles v\u00eam com op\u00e7\u00f5es como &#8220;Primeira Escolha&#8221;, &#8220;Segunda Escolha&#8221;, &#8220;Terceira Escolha&#8221;. Este \u00e9 o comportamento padr\u00e3o do Gravity Forms se nenhuma escolha tiver sido salva (antes) e isso \u00e9 acionado apenas nesses tipos de campo espec\u00edficos. Mas para nosso tipo de campo personalizado, nenhuma op\u00e7\u00e3o ser\u00e1 preenchida. Isso o torna um pouco complicado, porque voc\u00ea n\u00e3o receber\u00e1 o bot\u00e3o &#8220;+&#8221; para adicionar outra op\u00e7\u00e3o. Voc\u00ea teria que usar o bot\u00e3o &#8220;Adicionar em massa\/Escolhas predefinidas&#8221;, adicionar algumas op\u00e7\u00f5es l\u00e1, e depois disso, voc\u00ea ter\u00e1 acesso aos bot\u00f5es &#8220;+&#8221; para adicionar op\u00e7\u00f5es. Mas \u00e9 f\u00e1cil definir algumas escolhas personalizadas \u2013 tudo que voc\u00ea precisa \u00e9 definir uma vari\u00e1vel de array de classe<code>public $choices<\/code>e o Gravity Forms gerar\u00e1 automaticamente op\u00e7\u00f5es predefinidas em seu campo quando voc\u00ea o adicionar aos seus formul\u00e1rios.<\/p>\n<p>Nota: Esta \u00e9 uma vari\u00e1vel de classe, que voc\u00ea pode adicionar no topo da classe, logo abaixo de <code>public $type<\/code>. Cada escolha precisa ser um array, com a escolha como valor para a chave &#8216; <code>text<\/code>&#8216;.<\/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>Lembre-se de que, se voc\u00ea j\u00e1 adicionou o campo ao formul\u00e1rio, ele n\u00e3o preencher\u00e1 retroativamente as op\u00e7\u00f5es. Isso s\u00f3 entra em vigor quando voc\u00ea adiciona um novo campo ao formul\u00e1rio.<\/p>\n<p><strong>Nota<\/strong>: Em Gravity Forms parece ser poss\u00edvel tamb\u00e9m adicionar chaves &#8216; <code>value<\/code>&#8216; a cada escolha. Mas n\u00e3o consegui fazer isso funcionar \u2013 os valores se tornar\u00e3o automaticamente os mesmos que o texto de escolha.<\/p>\n<h2>Definindo o valor do campo como array<\/h2>\n<p>O pr\u00f3ximo passo \u00e9 bem simples, mas necess\u00e1rio. Como valores padr\u00e3o para campos em Gravity Forms s\u00e3o strings. Precisamos que o valor seja um array porque trabalhamos com v\u00e1rias entradas. Para fazer isso, definimos a fun\u00e7\u00e3o <code>is_value_submission_array()<\/code>e retornamos <code>true<\/code>.<\/p>\n<pre><code>public function is_value_submission_array() {\n    return true;\n}<\/code><\/pre>\n<p>Isso garante que possamos trabalhar corretamente com o valor inserido de nossas m\u00faltiplas entradas.<\/p>\n<h2>Renderizando a sa\u00edda de campo<\/h2>\n<p>Quando se trata de renderizar a sa\u00edda do campo, h\u00e1 algumas coisas a serem observadas.<\/p>\n<p>Primeiro \u00e9 que voc\u00ea precisa escolher entre duas fun\u00e7\u00f5es; <code>get_field_input()<\/code>ou <code>get_field_content()<\/code>. No primeiro m\u00e9todo, o Gravity Forms renderiza automaticamente o elemento da lista de encapsulamento, o r\u00f3tulo, a descri\u00e7\u00e3o e o cont\u00eainer para a mensagem de erro de valida\u00e7\u00e3o para seu campo e voc\u00ea controla apenas a sa\u00edda do campo interno. Com o segundo m\u00e9todo, nada disso acontece e voc\u00ea tem mais controle sobre a sa\u00edda do campo. No entanto, voc\u00ea precisa renderizar manualmente o r\u00f3tulo, a descri\u00e7\u00e3o e as mensagens de erro. O primeiro m\u00e9todo, <code>get_field_input()<\/code>, \u00e9 perfeitamente adequado para a maioria dos casos.<\/p>\n<p>A segunda coisa a ser observada \u00e9 que a fun\u00e7\u00e3o de renderiza\u00e7\u00e3o do campo afeta tr\u00eas locais diferentes. Os tr\u00eas s\u00e3o a renderiza\u00e7\u00e3o da sa\u00edda do campo no frontend, a visualiza\u00e7\u00e3o do campo dentro do editor de formul\u00e1rios e, finalmente, tamb\u00e9m o campo ao editar uma entrada. Felizmente, o Gravity Forms oferece fun\u00e7\u00f5es para determinar facilmente em qual visualiza\u00e7\u00e3o estamos. Normalmente, voc\u00ea renderizaria o campo da mesma maneira nos tr\u00eas casos. Mas como renderizar uma tabela grande com muitas entradas fica desnecessariamente desajeitado dentro do editor de formul\u00e1rios, optei por renderizar o campo de maneira diferente dentro do editor de formul\u00e1rios.<\/p>\n<p>E, finalmente, precisamos garantir que todas as entradas recebam um <code>name<\/code>atributo adequado para que o Gravity Forms possa coletar seu valor no envio do formul\u00e1rio. Todas as entradas no Gravity Forms precisam de <code>name<\/code>atributos que seguem esta regra: <code>name=\"input_{FIELD_ID}\"<\/code>(campos de sele\u00e7\u00e3o m\u00faltipla usam um ID adicional, mas n\u00e3o precisamos nos preocupar com isso para o nosso caso). Temos acesso ao ID do campo, pois \u00e9 uma vari\u00e1vel de classe (de <code>GF_Field<\/code>). Mas no nosso caso dissemos ao Gravity Forms que o valor \u00e9 um array e n\u00e3o um valor singular (passo anterior), ent\u00e3o adicionamos colchetes ap\u00f3s o atributo name; <code>name=\"input_{FIELD_ID}[]\"<\/code>. Portanto, se o campo tiver o ID 4 dentro de um formul\u00e1rio, o atributo name deve ser &#8221; <code>input_4[]<\/code>&#8220;.<\/p>\n<p>Estou optando por usar <code>get_field_input()<\/code>que vem com tr\u00eas par\u00e2metros. O primeiro par\u00e2metro \u00e9 o objeto de formul\u00e1rio, que realmente n\u00e3o precisamos para nosso exemplo. O segundo par\u00e2metro \u00e9 o valor atual. Este pode ser o valor do campo de <code>$_POST<\/code>quando o formul\u00e1rio foi tentado, mas sem sucesso. Podemos reter os valores enviados anteriormente. Ou se a fun\u00e7\u00e3o estiver sendo executada na edi\u00e7\u00e3o de uma entrada, o valor ser\u00e1 o valor armazenado do envio. Vamos lidar com o valor mais de perto mais tarde. E o terceiro par\u00e2metro \u00e9 o objeto de entrada, que tamb\u00e9m n\u00e3o precisaremos para nosso exemplo.<\/p>\n<p>Vamos come\u00e7ar a implementar <code>get_field_input()<\/code>o que espera a renderiza\u00e7\u00e3o final como uma string. Logo de cara eu decido retornar uma string vazia se estivermos dentro do editor de formul\u00e1rios \u2013 porque n\u00e3o quero renderizar a tabela completa nesta view. Podemos usar o m\u00e9todo <code>$this-&gt;is_form_editor()<\/code>para verificar se estamos ou n\u00e3o dentro do form edit. Voc\u00ea pode optar por ignorar isso ou renderizar outra coisa se quiser uma visualiza\u00e7\u00e3o do campo dentro do editor de formul\u00e1rios.<\/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>O pr\u00f3ximo passo \u00e9 construir o HTML para uma tabela que faz um loop em uma matriz de dias para gerar as colunas e as linhas para cada item do curso. Mas como precisamos acessar a matriz de dias (colunas da tabela) em v\u00e1rios lugares, devemos defini-la como uma vari\u00e1vel de classe, tornando-a acess\u00edvel a partir de qualquer fun\u00e7\u00e3o dentro dela. Eu defino uma vari\u00e1vel de classe <code>$delivery_days<\/code>com uma matriz dos dias para os quais quero oferecer entrega.<\/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>Este \u00e9 apenas um exemplo! Voc\u00ea pode querer buscar a matriz para as colunas de outro lugar que n\u00e3o seja codificado.<\/p>\n<p>Vamos voltar <code>get_field_input()<\/code>e construir nossa tabela com entradas. Primeiro, fa\u00e7o um loop sobre a vari\u00e1vel de classe e gero os cabe\u00e7alhos da tabela. Em seguida, fa\u00e7o um loop sobre as op\u00e7\u00f5es inseridas na configura\u00e7\u00e3o de campo para Op\u00e7\u00f5es. Isso \u00e9 acess\u00edvel a partir da vari\u00e1vel de classe (de <code>GF_Field<\/code>) <code>$this-&gt;choices<\/code>. Para cada escolha eu renderizo uma entrada com os atributos de nome apropriados. Temos acesso ao ID do campo a partir <code>GF_Field<\/code>da vari\u00e1vel de classe de <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>Com este c\u00f3digo em vigor, devemos obter uma boa tabela renderizada para nosso tipo de campo no frontend! Obviamente, o HTML depende inteiramente de voc\u00ea, este \u00e9 apenas um exemplo b\u00e1sico.<\/p>\n<p><strong>Deixamos esta fun\u00e7\u00e3o por enquanto, mas voltaremos a ela mais tarde para lidar com o valor enviado!<\/strong><\/p>\n<h2>Armazenando o valor corretamente<\/h2>\n<p>A partir de agora, o Gravity Forms salvar\u00e1 nosso campo como um array unidimensional preenchido com os valores inseridos e strings vazias onde a entrada estava vazia. N\u00e3o h\u00e1 informa\u00e7\u00f5es sobre a qual dia ou escolha o valor pertence, exceto o \u00edndice. Precisamos transformar esse array unidimensional em um array associativo multidimensional onde armazenamos o dia e o r\u00f3tulo de escolha. Podemos ent\u00e3o acessar facilmente o valor num\u00e9rico armazenado para, por exemplo, <code>$value['Ham sandwich']['Monday']<\/code>. Ap\u00f3s essa transforma\u00e7\u00e3o de array, tamb\u00e9m precisamos serializar o array para que o Gravity Forms possa armazenar o valor corretamente no banco de dados.<\/p>\n<p>Precisaremos transformar essa matriz de valores em v\u00e1rios lugares, ent\u00e3o definirei uma fun\u00e7\u00e3o separada para isso. A fun\u00e7\u00e3o aceita o array unidimensional e o transforma em um array multidimensional com os valores armazenados para dias e op\u00e7\u00f5es:<\/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>Isso armazenar\u00e1 os nomes dos dias e as op\u00e7\u00f5es diretamente dentro do valor do campo. Fazendo isso, \u00e9 poss\u00edvel alterar as op\u00e7\u00f5es posteriormente sem quebrar as entradas antigas.<\/p>\n<p>Agora vamos sobrescrever a fun\u00e7\u00e3o que manipula o armazenamento do valor enviado; <code>get_value_save_entry()<\/code>. Ele vem com cinco par\u00e2metros, mas s\u00f3 precisamos do primeiro que \u00e9 o valor enviado. Dentro da fun\u00e7\u00e3o passamos o valor para nossa fun\u00e7\u00e3o customizada acima, serializamos seu retorno e finalmente retornamos o novo valor.<\/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>Neste ponto, o Gravity Forms armazenar\u00e1 com sucesso nossos valores da maneira que queremos! No entanto, o valor armazenado agora \u00e9 uma matriz serializada que o Gravity Forms ecoar\u00e1 com prazer. Precisamos implementar fun\u00e7\u00f5es para transform\u00e1-lo de um array serializado feio em uma sa\u00edda bonita onde quer que precisemos.<\/p>\n<h2>Exibindo o valor enviado<\/h2>\n<p>H\u00e1 tr\u00eas lugares que precisamos alterar a sa\u00edda do valor do nosso campo; a lista de entradas, olhando para uma \u00fanica entrada e dentro das etiquetas de mesclagem do Gravity Forms. As etiquetas de mesclagem s\u00e3o usadas com mais frequ\u00eancia em notifica\u00e7\u00f5es por e-mail. Por exemplo <code>{all_fields}<\/code>, \u00e9 uma tag de mesclagem que exibe os valores completos do formul\u00e1rio enviado em e-mails.<\/p>\n<p>Como estamos renderizando a mesma sa\u00edda em tr\u00eas casos diferentes, faz sentido criar uma fun\u00e7\u00e3o separada para ela. Defini uma fun\u00e7\u00e3o personalizada que aceita o valor; o array multidimensional n\u00e3o serializado, como par\u00e2metro. A fun\u00e7\u00e3o ent\u00e3o cria algum HTML que exibe o array de uma maneira bonita e retorna a string. Optei por uma <code>&lt;ul&gt;<\/code>lista aninhada, mas voc\u00ea pode alterar a sa\u00edda como quiser.<\/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>\u00d3timo, vamos come\u00e7ar com o primeiro: a lista de entradas: <code>get_value_entry_list()<\/code>. Voc\u00ea pode optar por gerar a sa\u00edda completa aqui, mas pode ficar muito desajeitado e longo para o modo de exibi\u00e7\u00e3o de lista, ent\u00e3o optei por simplesmente retornar uma string fixa que explica que o usu\u00e1rio precisa entrar nos detalhes da entrada para ver a vis\u00e3o geral completa.<\/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>Obviamente, isso depende inteiramente de voc\u00ea, voc\u00ea pode optar por exibir apenas o primeiro n\u00famero x de caracteres, por exemplo.<\/p>\n<p>A segunda fun\u00e7\u00e3o \u00e9 a que afeta a visualiza\u00e7\u00e3o de uma \u00fanica entrada: <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>N\u00f3s simplesmente deserializamos a matriz com a fun\u00e7\u00e3o do WordPress <code>[maybe_unserialize](https:\/\/developer.wordpress.org\/reference\/functions\/maybe_unserialize\/)()<\/code>e retornamos a sa\u00edda da string de nossa fun\u00e7\u00e3o personalizada.<\/p>\n<p>A fun\u00e7\u00e3o final afeta as tags de mesclagem e garante que o valor do nosso campo fique bem dentro dos emails: <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>Observe que n\u00e3o precisaremos desserializar o valor dentro desta fun\u00e7\u00e3o.<\/p>\n<p>Com essas tr\u00eas fun\u00e7\u00f5es em vigor, todos os valores enviados devem parecer muito bons em todos os lugares! Por exemplo, ao visualizar uma entrada enviada:<\/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=\"Tutorial: Criar um tipo de campo de formul\u00e1rios de gravidade personalizados avan\u00e7ados e como lidar com v\u00e1rios valores de entrada\" ><\/a><\/p>\n<p>No entanto, h\u00e1 uma coisa importante faltando! Neste ponto, nossas entradas n\u00e3o ret\u00eam os valores enviados anteriormente e isso \u00e9 muito ruim.<\/p>\n<h2>Fa\u00e7a com que nossos insumos mantenham o valor enviado anteriormente<\/h2>\n<p>Existem principalmente dois casos em que precisamos garantir que as entradas mantenham os valores enviados anteriormente. O primeiro caso \u00e9 quando o envio de um formul\u00e1rio falhou (por exemplo, o usu\u00e1rio esqueceu um campo obrigat\u00f3rio). Neste momento, todas as nossas entradas perdem todos os valores inseridos anteriormente e o usu\u00e1rio precisa reinserir todos os valores novamente. Em segundo lugar, quando o propriet\u00e1rio do site edita uma entrada, as entradas n\u00e3o s\u00e3o preenchidas com os valores enviados do envio \u2013 o que torna praticamente imposs\u00edvel editar os valores corretamente.<\/p>\n<p>Para corrigir isso, voltamos \u00e0 fun\u00e7\u00e3o <code>get_field_input()<\/code>. O segundo par\u00e2metro para esta fun\u00e7\u00e3o \u00e9 o valor. Mas lembre-se de que esta fun\u00e7\u00e3o afeta a renderiza\u00e7\u00e3o do frontend e a edi\u00e7\u00e3o de entrada. Isso \u00e9 importante porque o valor armazenado \u00e9 diferente nesses dois casos. Se estivermos no frontend e manipulando o envio do formul\u00e1rio, o valor estar\u00e1 no formato do array unidimensional mencionado anteriormente. E se estivermos editando uma entrada, o valor estar\u00e1 no formato de um array multidimensional serializado. Portanto, precisamos traduzir adequadamente o valor fornecido <code>get_field_input()<\/code>para acessar facilmente os valores reais.<\/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>No c\u00f3digo acima, antes de come\u00e7armos a criar o HTML para a sa\u00edda do campo, criamos uma vari\u00e1vel <code>$table_value<\/code>que cont\u00e9m o valor traduzido corretamente. Usamos <code>GF_Field<\/code>a fun\u00e7\u00e3o &#8216;s <code>is_entry_detail()<\/code>para verificar se estamos editando ou n\u00e3o uma entrada. E ent\u00e3o para nossas entradas \u00e9 f\u00e1cil acessar os valores apropriados e defini-los como <code>value<\/code>atributos das entradas:<\/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>Com o acima atualizado <code>get_field_input()<\/code>, todas as nossas entradas personalizadas devem sempre ser preenchidas com o valor anterior; n\u00e3o importa se est\u00e1 editando uma entrada ou tentando novamente um envio de formul\u00e1rio.<\/p>\n<p>Neste ponto, tudo sobre renderiza\u00e7\u00e3o e armazenamento de nossos valores est\u00e1 pronto e funcionando perfeitamente. Mas h\u00e1 mais uma coisa que definitivamente precisamos consertar.<\/p>\n<h2>Fa\u00e7a nosso campo passar a valida\u00e7\u00e3o &#8220;obrigat\u00f3ria&#8221;<\/h2>\n<p>Gravity Forms tem verifica\u00e7\u00f5es para ver se o valor de um campo est\u00e1 vazio ou n\u00e3o. Isso geralmente \u00e9 necess\u00e1rio quando o campo \u00e9 definido como obrigat\u00f3rio. Quando um campo \u00e9 obrigat\u00f3rio, voc\u00ea n\u00e3o pode enviar o formul\u00e1rio se estiver vazio, certo? O problema para n\u00f3s \u00e9 que temos v\u00e1rias entradas e queremos permitir que algumas delas fiquem vazias. Isso se torna um problema se nosso campo estiver definido como obrigat\u00f3rio. Infelizmente, o Gravity Forms interpreta &quot;est\u00e1 vazio&quot; errado e exige que todas as entradas sejam preenchidas. Portanto, precisamos adicionar uma regra que diga que, se pelo menos uma de nossas muitas entradas for preenchida, o valor total do campo n\u00e3o ficar\u00e1 vazio.<\/p>\n<p>A fun\u00e7\u00e3o final que precisamos substituir em nossa classe \u00e9 <code>is_value_submission_empty()<\/code>. Obtemos apenas o ID do formul\u00e1rio como par\u00e2metro para esta fun\u00e7\u00e3o, portanto, precisamos extrair o valor do campo usando a fun\u00e7\u00e3o Gravity Forms para busc\u00e1-lo no <code>$_POST<\/code>array: <code>rgpost('input_&lt;FIELD ID&gt;')<\/code>. O retorno deve ser o array unidimensional que vimos antes. Tudo o que precisamos fazer \u00e9 percorrer o array e retornar <code>false<\/code>se encontrarmos um valor em algum lugar. Caso contr\u00e1rio, retornamos, <code>true<\/code>pois o valor do campo est\u00e1 de fato completamente vazio.<\/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>Com a fun\u00e7\u00e3o acima em vigor, nosso campo n\u00e3o falhar\u00e1 no envio se estiver definido como obrigat\u00f3rio e pelo menos uma entrada estiver preenchida.<\/p>\n<h2>Conclus\u00e3o e c\u00f3digo final<\/h2>\n<p>Este tutorial mostrou em detalhes como criar seu pr\u00f3prio tipo de campo avan\u00e7ado personalizado para Gravity Forms. Mesmo que seu projeto seja diferente do meu exemplo, espero que voc\u00ea tenha algumas dicas e a-ha&#8217;s ao longo do caminho. Acho a documenta\u00e7\u00e3o do Gravity Forms bastante carente em alguns casos, e isso \u00e9 resultado de muita tentativa e erro! Enfim, espero que isso tenha sido de alguma utilidade para voc\u00ea!<\/p>\n<p>Para refer\u00eancia, aqui est\u00e1 o c\u00f3digo completo em sua totalidade:<\/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\">Fonte de grava\u00e7\u00e3o:  <a target=\"_blank\" rel=\"noopener nofollow\" href=\"\/\/awhitepixel.com\" class=\"external external_icon\">awhitepixel.com<\/a><\/div><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Um tutorial mostrando como criar um tipo de campo Gravity Forms personalizado avan\u00e7ado com v\u00e1rias entradas com tratamento especial para armazenar e exibir os valores.<\/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":[898,898,1110,806,806,816,816,846,846,867,867],"tags":[1170],"class_list":{"0":"post-233507","1":"post","2":"type-post","3":"status-publish","4":"format-standard","5":"has-post-thumbnail","6":"hentry","7":"category-codigo-2","9":"category-n-a","10":"category-php-8","12":"category-plug-ins","14":"category-tutoriais","16":"category-wordpress-8","18":"tag-affiai-pt-pt"},"_links":{"self":[{"href":"https:\/\/wordpress.mediadoma.com\/pt-pt\/wp-json\/wp\/v2\/posts\/233507","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wordpress.mediadoma.com\/pt-pt\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wordpress.mediadoma.com\/pt-pt\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pt-pt\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pt-pt\/wp-json\/wp\/v2\/comments?post=233507"}],"version-history":[{"count":0,"href":"https:\/\/wordpress.mediadoma.com\/pt-pt\/wp-json\/wp\/v2\/posts\/233507\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pt-pt\/wp-json\/wp\/v2\/media\/153180"}],"wp:attachment":[{"href":"https:\/\/wordpress.mediadoma.com\/pt-pt\/wp-json\/wp\/v2\/media?parent=233507"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pt-pt\/wp-json\/wp\/v2\/categories?post=233507"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pt-pt\/wp-json\/wp\/v2\/tags?post=233507"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}