# Como integrar validação de CPF em WordPress com Elementor e AJAX

> Tutorial completo para integrar validação de CPF em formulários WordPress com Elementor usando AJAX e a API da CPFHub.

**Publicado:** 30/07/2026
**Autor:** Redação CPFHub.io
**URL:** https://cpfhub.io/blog/como-integrar-validacao-de-cpf-em-wordpress-com-elementor-e-ajax

---


Para integrar validação de CPF em WordPress com Elementor e AJAX, crie um plugin que registra um handler no `admin-ajax.php`, faz a chamada server-side para `https://api.cpfhub.io/cpf/{CPF}` com o header `x-api-key` e retorna o resultado ao JavaScript do formulário. Essa arquitetura mantém a chave de API protegida no servidor e entrega feedback visual ao usuário sem recarregar a página. A latência média da API é de ~900ms, então um indicador de carregamento melhora a percepção de velocidade. A [documentação do WordPress para requisições HTTP](https://developer.wordpress.org/plugins/http-api/) explica como usar `wp_remote_get` de forma correta e segura.

---

## Arquitetura da solução

A integração segue o padrão WordPress para requisições AJAX:

1. O usuário digita o CPF no campo do formulário Elementor.
2. Um script JavaScript captura o evento e envia uma requisição AJAX para o `admin-ajax.php`.
3. O PHP no servidor recebe a requisição, consulta a API da CPFHub e retorna o resultado.
4. O JavaScript atualiza o formulário com os dados recebidos.

Essa abordagem mantém a chave de API protegida no servidor, seguindo as boas práticas de segurança do WordPress.

---

## Criando o plugin de validação

Crie um plugin WordPress dedicado para manter o código organizado e facilitar atualizações:

```php
<?php
/**
 * Plugin Name: CPFHub Validator
 * Description: Validação de CPF em tempo real com a API CPFHub.io
 * Version: 1.0.0
 * Author: Sua Empresa
 */

defined('ABSPATH') || exit;

class CPFHub_Validator {

 private $api_key;

 public function __construct() {
 $this->api_key = get_option('cpfhub_api_key', '');

 add_action('wp_enqueue_scripts', [$this, 'enqueue_scripts']);
 add_action('wp_ajax_cpfhub_validate', [$this, 'ajax_validate']);
 add_action('wp_ajax_nopriv_cpfhub_validate', [$this, 'ajax_validate']);
 add_action('admin_menu', [$this, 'add_settings_page']);
 add_action('admin_init', [$this, 'register_settings']);
 }

 public function enqueue_scripts() {
 if ($this->should_load_scripts()) {
 wp_enqueue_script(
 'cpfhub-validator',
 plugin_dir_url(__FILE__) . 'js/cpfhub-validator.js',
 [],
 '1.0.0',
 true
 );

 wp_localize_script('cpfhub-validator', 'cpfhubConfig', [
 'ajaxUrl' => admin_url('admin-ajax.php'),
 'nonce' => wp_create_nonce('cpfhub_validate'),
 ]);

 wp_enqueue_style(
 'cpfhub-validator',
 plugin_dir_url(__FILE__) . 'css/cpfhub-validator.css',
 [],
 '1.0.0'
 );
 }
 }

 public function ajax_validate() {
 check_ajax_referer('cpfhub_validate', 'nonce');

 $cpf = preg_replace('/\D/', '', sanitize_text_field($_POST['cpf'] ?? ''));

 if (strlen($cpf) !== 11) {
 wp_send_json_error(['message' => 'CPF deve conter 11 dígitos.']);
 }

 $response = wp_remote_get(
 "https://api.cpfhub.io/cpf/{$cpf}",
 [
 'headers' => [
 'x-api-key' => $this->api_key,
 'Accept' => 'application/json',
 ],
 'timeout' => 10,
 ]
 );

 if (is_wp_error($response)) {
 wp_send_json_error([
 'message' => 'Erro na comunicação com a API. Tente novamente.'
 ]);
 }

 $body = json_decode(wp_remote_retrieve_body($response), true);

 if (!empty($body['success']) && $body['success'] === true) {
 wp_send_json_success($body['data']);
 } else {
 wp_send_json_error([
 'message' => 'CPF não encontrado na base de dados.'
 ]);
 }
 }

 private function should_load_scripts() {
 return !empty($this->api_key);
 }

 public function add_settings_page() {
 add_options_page(
 'CPFHub Validator',
 'CPFHub Validator',
 'manage_options',
 'cpfhub-validator',
 [$this, 'render_settings_page']
 );
 }

 public function register_settings() {
 register_setting('cpfhub_settings', 'cpfhub_api_key');
 }

 public function render_settings_page() {
 ?>
 <div class="wrap">
 <h1>CPFHub Validator</h1>
 <form method="post" action="options.php">
 <?php settings_fields('cpfhub_settings'); ?>
 <table class="form-table">
 <tr>
 <th>Chave de API</th>
 <td>
 <input type="text"
 name="cpfhub_api_key"
 value="<?php echo esc_attr(get_option('cpfhub_api_key')); ?>"
 class="regular-text" />
 <p class="description">
 Obtenha sua chave em
 <a href="https://www.cpfhub.io/" target="_blank">cpfhub.io</a>
 </p>
 </td>
 </tr>
 </table>
 <?php submit_button(); ?>
 </form>
 </div>
 <?php
 }
}

new CPFHub_Validator();
```

---

## Criando o JavaScript para AJAX

Crie o arquivo `js/cpfhub-validator.js` dentro do diretório do plugin:

```javascript
// js/cpfhub-validator.js
(function () {
 "use strict";

 let debounceTimer = null;

 function init() {
 const cpfFields = document.querySelectorAll(
 'input[name="form_fields[cpf]"], input[data-cpfhub="true"], .cpfhub-field input'
 );

 cpfFields.forEach(function (field) {
 field.setAttribute("inputmode", "numeric");
 field.setAttribute("maxlength", "14");

 const feedbackEl = document.createElement("div");
 feedbackEl.className = "cpfhub-feedback";
 field.parentNode.appendChild(feedbackEl);

 field.addEventListener("input", function () {
 formatCpf(field);
 debouncedValidate(field, feedbackEl);
 });
 });
 }

 function formatCpf(field) {
 let value = field.value.replace(/\D/g, "");
 if (value.length > 11) value = value.slice(0, 11);

 if (value.length > 9) {
 value = value.replace(/(\d{3})(\d{3})(\d{3})(\d{1,2})/, "$1.$2.$3-$4");
 } else if (value.length > 6) {
 value = value.replace(/(\d{3})(\d{3})(\d{1,3})/, "$1.$2.$3");
 } else if (value.length > 3) {
 value = value.replace(/(\d{3})(\d{1,3})/, "$1.$2");
 }

 field.value = value;
 }

 function debouncedValidate(field, feedbackEl) {
 if (debounceTimer) clearTimeout(debounceTimer);

 debounceTimer = setTimeout(function () {
 const cpf = field.value.replace(/\D/g, "");

 if (cpf.length !== 11) {
 feedbackEl.textContent = "";
 feedbackEl.className = "cpfhub-feedback";
 return;
 }

 validateCpf(cpf, field, feedbackEl);
 }, 600);
 }

 function validateCpf(cpf, field, feedbackEl) {
 feedbackEl.textContent = "Validando CPF...";
 feedbackEl.className = "cpfhub-feedback cpfhub-loading";

 const formData = new FormData();
 formData.append("action", "cpfhub_validate");
 formData.append("nonce", cpfhubConfig.nonce);
 formData.append("cpf", cpf);

 const controller = new AbortController();
 const timeoutId = setTimeout(function () {
 controller.abort();
 }, 15000);

 fetch(cpfhubConfig.ajaxUrl, {
 method: "POST",
 body: formData,
 signal: controller.signal,
 })
 .then(function (response) {
 clearTimeout(timeoutId);
 return response.json();
 })
 .then(function (result) {
 if (result.success) {
 feedbackEl.textContent = "CPF válido - " + result.data.name;
 feedbackEl.className = "cpfhub-feedback cpfhub-success";
 fillFormFields(result.data);
 } else {
 feedbackEl.textContent =
 result.data?.message || "CPF não encontrado.";
 feedbackEl.className = "cpfhub-feedback cpfhub-error";
 }
 })
 .catch(function (error) {
 clearTimeout(timeoutId);
 if (error.name === "AbortError") {
 feedbackEl.textContent = "Tempo excedido. Tente novamente.";
 } else {
 feedbackEl.textContent = "Erro na validação. Tente novamente.";
 }
 feedbackEl.className = "cpfhub-feedback cpfhub-error";
 });
 }

 function fillFormFields(data) {
 const nameFields = document.querySelectorAll(
 'input[name="form_fields[name]"], input[data-cpfhub-fill="name"]'
 );
 nameFields.forEach(function (f) {
 f.value = data.name || "";
 });

 const birthFields = document.querySelectorAll(
 'input[name="form_fields[birth_date]"], input[data-cpfhub-fill="birthDate"]'
 );
 birthFields.forEach(function (f) {
 f.value = data.birthDate || "";
 });
 }

 if (document.readyState === "loading") {
 document.addEventListener("DOMContentLoaded", init);
 } else {
 init();
 }
})();
```

---

## Configurando o formulário no Elementor

### Com Elementor Pro (Form Widget)

1. Adicione um widget **Form** na página.
2. Adicione um campo de texto com ID `cpf`.
3. Adicione campos para `name` e `birth_date` que serão preenchidos automaticamente.
4. No campo de CPF, adicione a classe CSS `cpfhub-field` em **Advanced > CSS Classes**.

### Com Elementor Free (HTML Widget)

Se você usa a versão gratuita, insira o formulário via widget HTML:

```html
<form id="cpfhub-registration" class="cpfhub-form">
 <div class="cpfhub-form-group">
 <label for="cpf-field">CPF</label>
 <input
 type="text"
 id="cpf-field"
 data-cpfhub="true"
 placeholder="000.000.000-00"
 inputmode="numeric"
 required
 />
 </div>

 <div class="cpfhub-form-group">
 <label for="name-field">Nome Completo</label>
 <input
 type="text"
 id="name-field"
 data-cpfhub-fill="name"
 readonly
 />
 </div>

 <div class="cpfhub-form-group">
 <label for="birth-field">Data de Nascimento</label>
 <input
 type="text"
 id="birth-field"
 data-cpfhub-fill="birthDate"
 readonly
 />
 </div>

 <button type="submit" class="cpfhub-submit">Cadastrar</button>
</form>
```

---

## Estilos CSS para feedback visual

Crie o arquivo `css/cpfhub-validator.css`:

```css
/* css/cpfhub-validator.css */
.cpfhub-feedback {
 margin-top: 4px;
 font-size: 13px;
 min-height: 20px;
 transition: all 0.3s ease;
}

.cpfhub-loading {
 color: #6b7280;
}

.cpfhub-loading::before {
 content: "";
 display: inline-block;
 width: 12px;
 height: 12px;
 border: 2px solid #6b7280;
 border-top-color: transparent;
 border-radius: 50%;
 animation: cpfhub-spin 0.6s linear infinite;
 margin-right: 6px;
 vertical-align: middle;
}

.cpfhub-success {
 color: #059669;
 font-weight: 500;
}

.cpfhub-error {
 color: #dc2626;
}

@keyframes cpfhub-spin {
 to {
 transform: rotate(360deg);
 }
}

.cpfhub-form-group {
 margin-bottom: 16px;
}

.cpfhub-form-group label {
 display: block;
 margin-bottom: 4px;
 font-weight: 600;
}

.cpfhub-form-group input {
 width: 100%;
 padding: 10px 12px;
 border: 1px solid #d1d5db;
 border-radius: 6px;
 font-size: 16px;
}

.cpfhub-form-group input:focus {
 outline: none;
 border-color: #3b82f6;
 box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
}

.cpfhub-form-group input[readonly] {
 background-color: #f9fafb;
 cursor: not-allowed;
}
```

---

## Segurança e boas práticas

### Proteção com nonce

O WordPress usa nonces para proteger requisições AJAX contra CSRF. Nosso plugin já implementa isso com `wp_create_nonce` e `check_ajax_referer`.

### Rate limiting no servidor

Adicione proteção contra abusos:

```php
public function ajax_validate() {
 check_ajax_referer('cpfhub_validate', 'nonce');

 $ip = $_SERVER['REMOTE_ADDR'];
 $transient_key = 'cpfhub_rate_' . md5($ip);
 $count = (int) get_transient($transient_key);

 if ($count >= 10) {
 wp_send_json_error([
 'message' => 'Muitas tentativas. Aguarde um minuto.'
 ]);
 }

 set_transient($transient_key, $count + 1, 60);

 // ... restante da validação
}
```

---

## Perguntas frequentes

### Como a chave de API da CPFHub.io é protegida nessa integração com WordPress?

A chave de API fica armazenada na tabela de opções do WordPress, acessada via `get_option('cpfhub_api_key')`, e nunca é exposta no frontend. Todo o tráfego com a API passa pelo `admin-ajax.php` no servidor, de modo que o JavaScript do navegador jamais vê a chave diretamente. Isso segue o padrão recomendado pela [documentação de segurança do WordPress](https://developer.wordpress.org/plugins/security/).

### A API CPFHub.io bloqueia requisições quando o limite do plano é atingido?

Não. Quando o limite mensal de consultas é ultrapassado, a API continua respondendo normalmente e cobra R$0,15 por consulta adicional — sem retornar erro 429 nem interromper o serviço. O plano gratuito inclui 50 consultas por mês; o plano Pro oferece 1.000 consultas mensais por R$149, com o mesmo modelo de excedente.

### O plugin funciona com o Elementor Free ou apenas com o Pro?

O plugin funciona com ambas as versões. Com o Elementor Pro, basta adicionar a classe `cpfhub-field` no campo de CPF do Form Widget. Com o Elementor Free, use o HTML Widget para inserir o formulário diretamente com os atributos `data-cpfhub="true"` nos campos adequados — o JavaScript do plugin detecta e inicializa automaticamente.

### Qual o tempo de resposta esperado da API e como configurar o timeout corretamente?

A latência média da API CPFHub.io é de aproximadamente 900ms. Por isso, o plugin configura `'timeout' => 10` na chamada via `wp_remote_get` e 15 segundos de timeout no `AbortController` do JavaScript — margem suficiente para a grande maioria das conexões. O indicador de carregamento exibido durante a validação evita que o usuário submeta o formulário antes da resposta chegar.

### Leia também

- [Como validar CPF no frontend com React e API REST](https://cpfhub.io/blog/como-validar-cpf-no-frontend-com-react-e-api-rest)
- [Como consumir API de CPF em WordPress com WP_Http](https://cpfhub.io/blog/como-consumir-api-de-cpf-em-wordpress-com-wp-http)
- [Como integrar a API de CPF ao WordPress com PHP](https://cpfhub.io/blog/como-integrar-api-cpf-wordpress-php)
- [Boas práticas para consumir APIs de CPF de forma segura](https://cpfhub.io/blog/boas-praticas-consumir-apis-cpf-segura)

---

## Conclusão

Integrar validação de CPF em WordPress com Elementor e AJAX é uma solução prática e segura que beneficia sites de e-commerce, landing pages e portais de cadastro. O plugin que construímos mantém a chave de API protegida no servidor, usa nonces para segurança e oferece feedback visual instantâneo ao usuário.

A API do [**CPFHub.io**](https://www.cpfhub.io/)

Cadastre-se em [cpfhub.io](https://www.cpfhub.io/)

