Controles do Theme Customizer

Controles do Theme Customizer

Na lição passada, nós aprendemos o que é o Theme Customizer, e como ele pode facilitar a vida dos usuários do seu tema.

Hoje, nós iremos aprender um pouco mais sobre as diversos tipos de controles que podemos implementar, são eles:

  • Radio Box;
  • CheckBox;
  • Select;
  • Text; (Já vimos na lição passada)
  • Textarea;
  • Email;
  • URL;
  • Number;
  • Dropdown;
  • File Input;
  • HTML Color & Code;
  • Javascript Code;

Pronto para começar?

Radio Box

Também conhecido como radio button, são elementos de formulário presentes em páginas da web e aplicativos mobile, que permitem que os usuários selecionem uma única opção, dentro de um conjunto predefinido de opções.

Acredito que você já tenha visto um radio button em HTML por aí, eles são praticamente iguais a ilustração abaixo:

Para criar este tipo de controle, basta adicionar os seguintes comandos dentro da função micilini_customizer():

//Adiciona uma configuração de Radio Button
 
 $wp_customize->add_setting(
 'setting_radio_button', 
 array(
 'type' => 'theme_mod',
 'default' => 'opcao_um',
 'sanitize_callback' => 'sanitize_key'
 ));

 $wp_customize->add_control(
 new WP_Customize_Control(
 $wp_customize, 
 'setting_radio_button',
 array(
 'label' => 'Escolha uma opção abaixo',
 'section' => 'section_titulo',
 'settings' => 'setting_radio_button',
 'type' => 'radio',
 'choices' => array(
 'opcao_um' => 'Gato'
 'opcao_dois' => 'Cachorro',
 'opcao_tres' => 'Passaro'
 ),
 )
 )
 );

A começar pela função add_setting(), temos dois novos parâmetros que ainda não foram discutidos anteriormente:

'default': refere-se a opção que estará marcada por padrão, aqui informamos o identificador do radio button que declaramos dentro da função add_control(). No nosso caso, a opção 'Gato' cujo identificador é 'opcao_um' estará marcado por padrão.

'sanitize_key': essa função é útil quando você precisa garantir que uma string seja usada como uma chave segura em situações onde espaços, caracteres especiais ou letras maiúsculas podem causar problemas.

  • Ela remove todos os caracteres que não são alfanuméricos, sublinhados (_) ou hífens (-).
  • Ela mantém apenas a primeira ocorrência contínua de sublinhados (_) e hífens (-).
  • Por fim, ela converte todas as strings para o formato minúsculo.

Com relação ao add_control(), nós temos:

new WP_Customize_Control(): criamos uma nova instância da classe WP_Customize_Control para criar um radio button personalizado.

$wp_customize: o primeiro argumento passado dentro da instância do controle é o objeto $wp_customize, que como sabemos, contém a instância do WP_Customize_Manager, que por sua vez, é capaz de gerenciar todas as configurações e controles no Customizer.

'minha_opcao_radio': é o identificador único e exclusivo para o grupo de radio buttons que vamos criar.

Em seguida, temos o terceiro argumento, que nada mais é do que um array que contém todas as configurações destinada a este controle:

'label': será o título ligado ao grupo de radio buttons. No nosso caso será "Escolha uma opção abaixo".

'section': é o ID da seção à qual este controle pertence. No nosso caso é 'section_titulo'.

'settings': é o nome da configuração associada a este controle, aqui nos informamos o identificador da setting.

'type': é o tipo de controle que será criado, neste caso é 'radio', indicando que este controle é um conjunto de botões de rádio.

'choices': criamos um array que representa a quantidade de botões de rádio que serão criados, eles seguem a estrutura de chave e valor, onde a chave representa o identificador único do rádio, e o valor o texto que aparece ao usuário.

Veja como ficou o resultado final:

Conectando seu radio button com seu tema

Para recuperar a opção selecionada dentro de um arquivo do seu tema, você pode usar o seguinte comando abaixo:

$opcao_escolhida = get_theme_mod('setting_radio_button', 'opcao_um');

É importante ressaltar que a variável $opcao_escolhida vai armazenar o identificador de uma das três opções que definimos na função add_control().

Para mais informações sobre o comando get_theme_mod() consulte a lição anterior.

Checkbox

Um checkbox, nada mais é do que uma caixa de seleção, onde você pode marcar quantas caixas de seleção desejar.

Para criar este tipo de controle, basta adicionar os seguintes comandos dentro da função micilini_customizer():  

$wp_customize->add_setting(
 'setting_checkbox_mostrar_nome',
 array(
 'type' => 'theme_mod',
 'default' => false,
 'sanitize_callback' => 'sanitize_checkbox',
 ) 
 );

 $wp_customize->add_control(
 new WP_Customize_Control(
 $wp_customize,
 'setting_checkbox_mostrar_nome',
 array(
 'label' => 'Deseja mostrar seu nome para os visitantes?',
 'section' => 'section_titulo',
 'settings' => 'setting_checkbox_mostrar_nome',
 'type' => 'checkbox',
 )
 )
 );

Já fora da função micilini_customizer(), vamos precisar criar uma função própria capaz de sanitizar nosso checkbox:

function sanitize_checkbox( $input ) {
 return (bool) $input;
}

Feito isso, vamos detalhar algumas coisas, começando pela função add_setting():

'default': define se o checkbox estará marcado (true), ou desmarcado (false) por padrão.

'sanitize_checkbox': como o WordPress ainda não dispõe de uma função capaz de sanitizar um checkbox, estamos passando a função que criamos, chamada de 'sanitize_checkbox'.

Com relação a função add_control(), nós temos:

new WP_Customize_Control(): precisamos instanciar a classe WP_Customize_Control para criar um checkbox personalizado.

$wp_customize: o primeiro argumento passado dentro da instância do controle é o objeto $wp_customize, que como sabemos, contém a instância do WP_Customize_Manager, que por sua vez, é capaz de gerenciar todas as configurações e controles no Customizer.

'setting_checkbox_mostrar_nome': é o ID exclusivo para este controle.

O terceiro parâmetro é um array que contém várias configurações para o controle:

'label': é o título exibido para o checkbox, no nosso caso é "Deseja mostrar seu nome para os visitantes?".

'section': é o ID da seção à qual este controle pertence. No noss caso é 'section_titulo'.

'settings': é o ID da setting associada ao controle. No nosso caso, é 'setting_checkbox_mostrar_nome'.

'type': é o tipo de controle que será criado, neste caso é 'checkbox'.

Veja como ficou o resultado final:

Conectando seu checkbox com seu tema

Para validar se a sua opção está selecionada dentro de um arquivo do seu tema, você pode usar o seguinte comando abaixo:

$opcao_mostrar_nome = get_theme_mod('setting_checkbox_mostrar_nome', false);

É importante ressaltar que a variável $opcao_mostra_nome retorna um valor booleano (true ou false).

Para mais informações sobre o comando get_theme_mod() consulte a lição anterior.  

Select

Conhecido popularmente como caixa de seleção ou dropdown, é um conjunto de opções que existem dentro de um agrupamento, por exemplo:

Para criar este tipo de controle, basta adicionar os seguintes comandos dentro da função micilini_customizer():

 $wp_customize->add_setting(
 'setting_meu_select',
 array(
 'type' => 'theme_mod',
 'default' => 'opcao_um',
 'sanitize_callback' => 'sanitize_key'
 )
 );

 $wp_customize->add_control(
 'setting_meu_select',
 array(
 'label' => "Escolha alguma opção:",
 'section' => 'section_titulo',
 'type' => 'select',
 'choices' => array(
 '' => 'Escolha um animal abaixo:',
 'opcao_um' => 'Águia',
 'opcao_dois' => 'Lagarto',
 'opcao_tres' => 'Zebra'
 ),
 )
 );

Como podemos perceber, ela se comporta de maneira muito parecida com o controle radio button.

A diferença é o 'type' que está setado como um 'select', indicando que o controle a ser criado será um select, e uma opção com identificador vazio dentro do argumento 'choices', que diz a respeito que a primeira opção não é selecionável.

Veja como ficou o resultado final:

Conectando seu select com seu tema

Para validar se a sua opção está selecionada dentro de um arquivo do seu tema, você pode usar o seguinte comando abaixo:

$opcao_selecionada = get_theme_mod('setting_meu_select', 'opcao_um');

É importante ressaltar que a variável $opcao_selecionada vai armazenar o identificador de uma das três opções que definimos na função add_control().

Para mais informações sobre o comando get_theme_mod() consulte a lição anterior.

TextArea

Conhecido popularmente como área de texto, ela é representada por um campo de texto largo, permitindo que seu usuário informe um texto mais extenso com quebras de linha.

Para criar este tipo de controle, basta adicionar os seguintes comandos dentro da função micilini_customizer():

 $wp_customize->add_setting(
 'setting_textarea', 
 array(
 'type' => 'theme_mod',
 'default' => '',
 'sanitize_callback' => 'wp_kses_post',
 )
 );

 $wp_customize->add_control(
 'setting_textarea',
 array(
 'label' => 'Área de Texto Personalizada',
 'section' => 'section_titulo',
 'settings' => 'setting_textarea',
 'type' => 'textarea',
 )
 );

Como vimos anteriormente, o controle textarea segue a mesma estrutura de funções e argumentos dos controles anteriores, com exceção de alguns parâmetros que não vimos ainda:

'wp_kses_post': é uma função do WordPress, que foi projetada para validar e limpar conteúdo digitado pelo usuário, antes de ser exibido na página.

Quando me refiro ao termo "limpar" estou dizendo que apenas as tags HTML seguras são permitidas.

Isso evita que ataques do tipo XSS (Cross-Site Scripting) aconteçam na sua página.

Veja como ficou o resultado final:

Conectando seu textarea com seu tema

Para conectar a sua área de texto com algum arquivo do seu tema, basta seguir a lógica abaixo:

$custom_textarea_value = get_theme_mod('setting_textarea', '');

echo wp_kses_post($custom_textarea_value);

Observe que estamos usando novamente a função wp_kses_post(), por questões de segurança da nossa aplicação.

Para mais informações sobre o comando get_theme_mod() consulte a lição anterior.

Email

Um campo do tipo e-mail, nada mais é do que um campo de texto (text), voltado para o recebimento de e-mail, por exemplo:

  • hey@gmail.com
  • micilini@micilini.com

Para criar este tipo de controle, basta adicionar os seguintes comandos dentro da função micilini_customizer():

$wp_customize->add_setting(
 'setting_email',
 array(
 'type' => 'theme_mod',
 'default' => '',
 'sanitize_callback' => 'sanitize_email'
 )
 );

 $wp_customize->add_control(
 'setting_email',
 array(
 'label' => 'Digite seu E-mail',
 'section' => 'section_titulo',
 'settings' => 'setting_email',
 'type' => 'email'
 )
 );

A única diferença é que estamos usando um novo sanitize novo chamado de 'sanitize_email', que é uma função do WordPress responsável por limpar um endereço de e-mail com o objetivo de remover caracteres e outros formatos inválidos.

No caso do 'sanitize_email', ele remove todos os caracteres inválidos do e-mail digitado, por exemplo:

  • hey!"@gmail.com = hey!@gmail.com

Conectando seu email com seu tema

Para conectar o seu campo de texto do tipo email com algum arquivo do seu tema, basta seguir a lógica abaixo:

$custom_email_value = get_theme_mod('setting_email', '');

echo esc_html($custom_email_value);

Usamos a função esc_html() para escapar blocos html quando formos mostrar o email na tela.

Mas se preferir, você pode remover o uso dessa função tanto no código acima, quanto no argumento 'sanitize_callback', isso fará com que o texto digitado pelo usuário seja interpretado pelo navegador como um código HTML.

Para mais informações sobre o comando get_theme_mod() consulte a lição anterior.  

URL

Um campo do tipo URL, como o nome já diz, nada mais é do que um campo de texto (text), voltado para o recebimento de URLs (links da internet), por exemplo:

  • micilini.com
  • google.com.br

Para criar este tipo de controle, basta adicionar os seguintes comandos dentro da função micilini_customizer():  

 $wp_customize->add_setting(
 'setting_url',
 array(
 'type' => 'theme_mod',
 'default' => '',
 'sanitize_callback' => 'esc_url'
 )
 );

 $wp_customize->add_control(
 'setting_url',
 array(
 'label' => 'Digite sua URL',
 'section' => 'section_titulo',
 'settings' => 'setting_url',
 'type' => 'url'
 )
 );

A única diferença é que estamos usando um novo comando de sanitize chamado de 'esc_url', que é uma função do WordPress responsável por limpar a sua URL, a fim de remover caracteres e outros formatos inválidos.

No caso do 'esc_url', ele remove todos os caracteres inválidos da URL digitada, por exemplo:

  • https://micilini.com" = https://micilini.com

Conectando sua URL com seu tema

Para conectar o seu campo de texto do tipo url com algum arquivo do seu tema, basta seguir a lógica abaixo:

$custom_url_value = esc_url(get_theme_mod('setting_url', ''));

echo $custom_url_value;

Veja que estamos usando novamente a função esc_url() para limpar a URL.

Para mais informações sobre o comando get_theme_mod() consulte a lição anterior.

Number

Um campo do tipo number, como o nome já diz, nada mais é do que um campo de texto (text), voltado para o recebimento de valores numéricos.

Para criar este tipo de controle, basta adicionar os seguintes comandos dentro da função micilini_customizer():  

 $wp_customize->add_setting(
 'setting_number',
 array(
 'type' => 'theme_mod',
 'default' => '',
 'sanitize_callback' => 'absint'
 )
 );

 $wp_customize->add_control(
 'setting_number',
 array(
 'label' => 'Digite um número',
 'section' => 'section_titulo',
 'settings' => 'setting_number',
 'type' => 'number'
 )
 );

A única diferença é que estamos usando um sanitizador novo chamado de 'absint', que é uma função do WordPress que limpa os caracteres digitados, de modo a retornar somente os valores numéricos.

Veja como ficou o resultado final:

Conectando seu Number com seu tema

Para conectar o seu campo de texto do tipo number com algum arquivo do seu tema, basta seguir a lógica abaixo:

$custom_number_value = absint(get_theme_mod('setting_number', 0)); // Utilize absint para garantir que seja um número inteiro positivo

echo $custom_number_value;

Observe que também estamos fazendo o uso da função absint().

Para mais informações sobre o comando get_theme_mod() consulte a lição anterior.  

File Input

O controle file input, possibilita que o seu usuário faça o upload de um arquivo, para que ele seja usado no seu tema.

Neste primeiro momento, vamos nos atentar em criar um upload de arquivos, que aceite qualquer tipo de arquivo, seja ele imagem, vídeo ou documento.

Para criar este tipo de controle, basta adicionar os seguintes comandos dentro da função micilini_customizer():

 $wp_customize->add_setting(
 'setting_file',
 array(
 'type' => 'theme_mod',
 'default' => '',
 'sanitize_callback' => 'esc_url_raw'//ou use absint caso não funcionar
 )
 );

 $wp_customize->add_control(
 new WP_Customize_Media_Control(
 $wp_customize, 
 'setting_file', 
 array(
 'label' => 'Upload de Arquivo Personalizado',
 'section' => 'section_titulo',
 'settings' => 'setting_file',
 )
 )
 );

Como podemos perceber, existem dois novos argumentos que ainda não aprendemos nessa jornada:

'esc_url_raw': é uma função do WordPress usada para limpar e retornar uma URL bruta.

WP_Customize_Media_Control(): é a classe do WordPress usada para lidar com o upload de mídia.

Veja como ficou o resultado final:

Restringindo o upload, para um tipo de arquivo específico

Caso você queira restringir o upload para um tipo de arquivo específico, você pode declarar o argumento 'mime_type' dentro do array da seguinte forma:

 $wp_customize->add_setting(
 'setting_file',
 array(
 'type' => 'theme_mod',
 'default' => '',
 'sanitize_callback' => 'esc_url_raw'//ou use absint caso não funcionar
 )
 );

 $wp_customize->add_control(
 new WP_Customize_Media_Control(
 $wp_customize, 
 'setting_file', 
 array(
 'label' => 'Upload de Arquivo Personalizado',
 'section' => 'section_titulo',
 'settings' => 'setting_file',
 'mime_type' => 'image'
 )
 )
 );

No exemplo acima, estamos aceitando somente imagens ('image').

Caso você queria personalizar ainda mais, e permitir somente alguns tipos específicos de imagens, você pode criar uma nova função de sanitize para isso:

function custom_sanitize_image($image_url) {
 // Verifique se a URL é uma URL de imagem
 $allowed_mime_types = array('jpg|jpeg|png|gif');
 $file_type = wp_check_filetype($image_url, $allowed_mime_types);
 
 // Se for uma imagem válida, retorne a URL
 if ($file_type['ext']) {
 return esc_url_raw($image_url);
 } else {
 return ''; // Se não for uma imagem válida, retorne uma string vazia
 }
}

Observe que a função que criamos acima, permite somente o envio de imagens do tipo jpg, jpeg, png e gif.

Não se esqueça que essa função deve ser inserida fora da função principal micilini_customizer().

E por fim, altere o 'sanitize_callback' do setting passando o nome da função que acabamos de criar:

$wp_customize->add_setting(
 'setting_file',
 array(
 'type' => 'theme_mod',
 'default' => '',
 'sanitize_callback' => 'custom_sanitize_image'
 )
 );

Conectando o seu file upload com seu tema

Para conectar o seu campo de upload com algum arquivo do seu tema, basta seguir a lógica abaixo:

$custom_file_value = esc_url_raw(get_theme_mod('setting_file', ''));

echo $custom_file_value;

Caso você tenha usado o sanitize absint, você deveria recuperar a imagem da seguinte forma:

$customLogoID = get_theme_mod('setting_customlogo', 0);

if($customLogoID != 0){
 echo $customLogoURL = esc_url(wp_get_attachment_image_src($customLogoID, 'full')[0]);
}else{
 echo 'Arquivo não encontrado!';
}

Lembrando que a variável $custom_file_value irá retornar a URL absoluta do local onde o arquivo está hospedado.

HTML Color

Você sabia que o WordPress possui suporte a seleção de cores (color picker) no Theme Customizer?

Não, então vamos aprender agora mesmo como fazer isso 🤩

Para criar este tipo de controle, basta adicionar os seguintes comandos dentro da função micilini_customizer():

 $wp_customize->add_setting(
 'setting_color',
 array(
 'type' => 'theme_mod',
 'default' => '#ffffff',
 'sanitize_callback' => 'sanitize_hex_color'
 )
 );

 $wp_customize->add_control(
 new WP_Customize_Color_Control(
 $wp_customize,
 'setting_color', 
 array(
 'label' => 'Escolha uma Cor',
 'section' => 'section_titulo',
 'settings' => 'setting_color'
 )
 )
 );

Como podemos perceber, existem dois novos argumentos que ainda não aprendemos nessa jornada:

'sanitize_hex_color': função do WordPress usada para sanitizar uma cor do tipo HEX.

WP_Customize_Color_Control(): é a classe do WordPress usada para lidar com cores.

Veja como ficou o resultado final:

Conectando o seu HTML Color com seu tema

Para conectar a sua seleção de cores (color picker) com os arquivos do seu tema, basta seguir a lógica abaixo:

$custom_color_value = sanitize_hex_color(get_theme_mod('setting_color', '#ffffff'));

echo $custom_color_value;

Perceba que estamos fazendo novamente o uso do sanitize_hex_color().

Apesar disso, podemos também atribuir nossas cores em um arquivo CSS ou dentro da tag style do HTML:

/* No seu arquivo de estilo (style.css) */
.elemento_html {
 color: <?php echo esc_attr($custom_color_value); ?>;
}

<!-- No seu arquivo de template -->
<div style="color: <?php echo esc_attr($custom_color_value); ?>;">Olá Mundooo!</div>

Code

Também é possível fazer com que o usuário do seu tema adicione trechos de códigos HTML, CSS e Javascript

Para criar este tipo de controle, basta adicionar os seguintes comandos dentro da função micilini_customizer():

 $wp_customize->add_setting(
 'setting_code',
 array(
 'type' => 'theme_mod',
 'default' => '',
 'sanitize_callback' => 'wp_kses'
 )
 );

 $wp_customize->add_control(
 new WP_Customize_Code_Editor_Control(
 $wp_customize,
 'setting_code',
 array(
 'label' => 'Insira um código personalizado',
 'section' => 'section_titulo',
 'settings' => 'setting_code',
 'code_type' => 'text/html'
 )
 )
 );

Como podemos perceber, existem três novos argumentos que ainda não aprendemos nessa jornada:

'wp_kses': função do WordPress que é usada para permitir um conjunto controlado de tags HTML enquanto remove aquelas que podem representar um risco de segurança. Também podemos fazer o uso do 'wp_kses_post'.

WP_Customize_Code_Editor_Control(): é a classe do WordPress usada para lidar com códigos HTML, CSS e Javascript.

'code_type': é o tipo de código que será inserido pelo usuário, no momento temos três tipos 'text/html' que aceita HTML'text/css' que aceita CSS, 'application/javascript' que aceita Javascript.

Veja como ficou o resultado final:

Conectando o seu Code com seu tema

Para conectar o campo de código com os arquivos do seu tema, basta seguir a lógica abaixo:

$custom_code_value = wp_kses(get_theme_mod('setting_code', ''));

<!-- Exemplo de como mostrar um bloco HTML -->
<div><?php echo esc_html($custom_code_value); ?></div>

<!-- Exemplo de como mostrar um bloco CSS -->
$custom_css = wp_filter_nohtml_kses(get_theme_mod('setting_code', ''));
echo '<style type="text/css">' . $custom_css . '</style>';

<!-- Exemplo de como mostrar um bloco Javascript -->
$custom_js = wp_filter_nohtml_kses(get_theme_mod('setting_code', ''));
echo '<script>' . $custom_js . '</script>';

Veja que estamos usando a função 'wp_kses' novamente, e fazendo o uso de um novo sanitizer chamado de 'wp_filter_nohtml_kses' que remove possíveis tags HTML.

Caso existam tags HTML dentro do seu código Javascript é recomendado usar o sanitizador 'wp_kses'.

Conectando os controles do Theme Customizer com o Style.css

Você sabia que é possível conectar os valores retornados do banco de dados dentro do style.css?

Isso é uma ótima alternativa quando queremos controle a cor de um elemento, onde o mesmo se encontra declarado dentro do style.css, ao mesmo tempo que não queremos ficar digitando css inline por aí.

Supondo que você tenha 3 controles diferentes ('setting_custompagbackgroundcolor', 'setting_custompagcolor', 'setting_custompagbackgroundcolorselected') e queria conecta-los a algum estilo existente dentro do style.css, você pode fazer isso da seguinte forma:

//Configurações de Estilos CSS que são adicionados a página
function wpmicilini_styles() {
 $paginationBackgroundColor = get_theme_mod('setting_custompagbackgroundcolor');
 $paginationColorText = get_theme_mod('setting_custompagcolor');
 $paginationBackgroundColorSelected = get_theme_mod('setting_custompagbackgroundcolorselected');

 $custom_css = "
 .pagination span, .pagination a{
 background-color: ".$paginationBackgroundColor." !important;
 color: ".$paginationColorText." !important;
 }
 .pagination .current{
 background-color: ".$paginationBackgroundColorSelected." !important;
 color: ".$paginationColorText." !important;
 }
 ";

 wp_add_inline_style('wpmicilini-style', $custom_css); 
}

add_action('wp_enqueue_scripts', 'wpmicilini_styles');

O comando acima, deve ser inserido dentro do functions.php.

Observe que estamos replicando o add_action() para o wp_enqueue_scripts, e sim, você pode replicar isso quantas vezes forem necessárias.

Perceba que o comando responsável por fazer essa troca de estilos é o wp_add_inline_style(), que é uma função no WordPress usada para adicionar estilos CSS diretamente no cabeçalho de uma página.

Perceba que o primeiro parâmetro faz referencia ao identificador wpmicilini-style que foi declarado dentro da função wpmicilini_load_scripts(), se lembra?

Isso significa que os estilos declarados dentro da variável $custom_css, serão dedicados ao style.css do seu tema.

Essa é uma forma melhor e mais inteligente do que ficar declarando css inline dentro dos seus modelos de temas, como por exemplo:

//Supondo que você esteja dentro do page.php

<style>
.pagination span, .pagination a{
 background-color: ".$paginationBackgroundColor." !important;
 color: ".$paginationColorText." !important;
}
.pagination .current{
 background-color: ".$paginationBackgroundColorSelected." !important;
 color: ".$paginationColorText." !important;
}
</style>

//Restante do seu código

Conclusão

Chegamos a mais um final de lição, e acredito que você tenha aprendido bastante com os conteúdos vistos aqui.

A partir de agora você já é quase um mestre no Theme Customizer, só falta uma única coisa: Aprender a criar campos personalizados!

Até a próxima lição 🤓

Criadores de Conteúdo

Foto do William Lima
William Lima
Fundador da Micilini

Inventor nato, escreve conteudos de programação para o portal da micilini.

Torne-se um MIC 🤖

Mais de 100 mic's já estão conectados na plataforma.