/**
* Firma Real Estate - Theme Functions
* Updated: 2026-03 - Added Supabase integration to hero form,
* admin dashboard AJAX endpoints, improved emails.
*/
require_once get_template_directory() . '/gallery_functions.php';
if (!function_exists('firma_re_setup')):
function firma_re_setup()
{
add_theme_support('title-tag');
add_theme_support('post-thumbnails');
add_theme_support('html5', array(
'search-form',
'comment-form',
'comment-list',
'gallery',
'caption',
));
register_nav_menus(array(
'menu-1' => esc_html__('Primary', 'firma-re'),
));
}
endif;
add_action('after_setup_theme', 'firma_re_setup');
/**
* Enqueue scripts and styles.
*/
function firma_re_scripts()
{
// Theme stylesheet
wp_enqueue_style('firma-re-style', get_stylesheet_uri(), array(), wp_get_theme()->get('Version'));
// Google Fonts
wp_enqueue_style('firma-re-fonts', 'https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Playfair+Display:wght@700;800;900&display=swap', array(), null);
// JavaScript
wp_enqueue_script('firma-re-main', get_template_directory_uri() . '/js/main.js', array(), wp_get_theme()->get('Version'), true);
// Localize for AJAX
wp_localize_script('firma-re-main', 'firmaAjax', array(
'ajaxurl' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('firma_form_nonce')
));
}
add_action('wp_enqueue_scripts', 'firma_re_scripts');
/**
* Register Leads Custom Post Type
*/
function firma_re_register_leads_cpt()
{
register_post_type('lead', array(
'labels' => array(
'name' => 'Leads',
'singular_name' => 'Lead'
),
'public' => false,
'show_ui' => true,
'menu_icon'=> 'dashicons-email-alt',
'supports' => array('title', 'editor', 'custom-fields')
));
}
add_action('init', 'firma_re_register_leads_cpt');
/**
* Add custom columns to Leads list in Admin
*/
function firma_re_set_lead_columns($columns)
{
return array(
'cb' => $columns['cb'],
'title' => 'Nombre / Lead',
'phone' => 'Teléfono / WhatsApp',
'location' => 'Ubicación',
'date' => $columns['date'],
);
}
add_filter('manage_lead_posts_columns', 'firma_re_set_lead_columns');
function firma_re_fill_lead_columns($column, $post_id)
{
switch ($column) {
case 'phone':
echo esc_html(get_post_meta($post_id, '_lead_phone', true));
break;
case 'location':
echo esc_html(get_post_meta($post_id, '_lead_location', true));
break;
}
}
add_action('manage_lead_posts_custom_column', 'firma_re_fill_lead_columns', 10, 2);
/**
* MLS Import theme compatibility
*/
add_filter('mlsi_theme_name', function () {
return 'WpResidence';
});
add_filter('pre_option_template', function ($value) {
if (isset($_REQUEST['page']) && strpos($_REQUEST['page'], 'mlsimport') !== false) {
return 'wpresidence';
}
return $value;
});
add_filter('single_template', function ($template) {
global $post;
$mls_post_types = array('listing', 'property', 'mlslisting', 'estate_property');
if (in_array($post->post_type, $mls_post_types)) {
$custom = get_template_directory() . '/single-listing.php';
if (file_exists($custom)) {
return $custom;
}
}
return $template;
});
add_filter('http_request_timeout', function () {
return 120;
});
/* =========================================================
* SHARED HELPER — SUPABASE PROXY
* Sends lead data to Supabase REST API (server-side only).
* The service key never touches the browser.
* ========================================================= */
function firma_re_send_to_supabase($payload)
{
if (!defined('SUPABASE_URL') || !defined('SUPABASE_SERVICE_KEY') || empty(SUPABASE_URL)) {
error_log('[Firma] Supabase: credenciales no configuradas en wp-config.php');
return false;
}
$url = rtrim(SUPABASE_URL, '/') . '/rest/v1/leads';
$args = array(
'headers' => array(
'apikey' => SUPABASE_SERVICE_KEY,
'Authorization' => 'Bearer ' . SUPABASE_SERVICE_KEY,
'Content-Type' => 'application/json',
'Prefer' => 'return=minimal',
),
'body' => wp_json_encode($payload),
'method' => 'POST',
'timeout' => 15,
'data_format' => 'body',
);
$response = wp_remote_post($url, $args);
if (is_wp_error($response)) {
error_log('[Firma] Supabase WP_Error: ' . $response->get_error_message());
return false;
}
$code = wp_remote_retrieve_response_code($response);
if ($code >= 200 && $code < 300) {
return true;
}
error_log('[Firma] Supabase API error (' . $code . '): ' . wp_remote_retrieve_body($response));
return false;
}
/* =========================================================
* SHARED HELPER — EMAIL NOTIFICATION
* Sends a formatted email to the admin for every new lead.
* ========================================================= */
function firma_re_send_lead_email($data)
{
$to = defined('FIRMA_ADMIN_EMAIL') ? FIRMA_ADMIN_EMAIL : 'jlayala@firmarealestate.com';
$source = $data['source'] ?? 'formulario';
$name = $data['name'] ?? '';
$phone = $data['phone'] ?? '';
$email = $data['email'] ?? '';
$location= $data['location'] ?? ($data['address'] ?? '');
$type = $data['property_type'] ?? '';
$urgency = $data['urgency'] ?? '';
$message = $data['message'] ?? '';
$now = current_time('d/m/Y H:i');
$label_map = array(
'hero_form' => 'Inicio — Análisis de Mercado',
'seller_form' => 'Vende tu Propiedad',
);
$source_label = $label_map[$source] ?? ucfirst($source);
$subject = "Nuevo Lead [{$source_label}] - {$name}";
$body = "Has recibido un nuevo lead desde el sitio web.\n\n";
$body .= "═══════════════════════════\n";
$body .= "DATOS DEL CLIENTE\n";
$body .= "═══════════════════════════\n";
$body .= "Fecha y hora: {$now}\n";
$body .= "Nombre: {$name}\n";
$body .= "Teléfono/WA: {$phone}\n";
$body .= "Correo: {$email}\n\n";
$body .= "PROPIEDAD\n";
$body .= "───────────────────────────\n";
$body .= "Ubicación: {$location}\n";
$body .= "Tipo: {$type}\n";
$body .= "¿Cuándo?: {$urgency}\n\n";
if ($message) {
$body .= "Mensaje:\n{$message}\n\n";
}
$body .= "───────────────────────────\n";
$body .= "Fuente: {$source_label}\n";
$body .= "Sitio: https://test.firmarealestate.com\n";
$headers = array('Content-Type: text/plain; charset=UTF-8');
try {
wp_mail($to, $subject, $body, $headers);
} catch (Throwable $e) {
error_log('[Firma] wp_mail error: ' . $e->getMessage());
}
}
/* =========================================================
* HERO FORM — Handle AJAX Submission
* (Home page "Solicitar Análisis de Mercado" form)
* ========================================================= */
function firma_re_handle_hero_form()
{
check_ajax_referer('firma_form_nonce', 'nonce');
$location = sanitize_text_field($_POST['location'] ?? '');
$type = sanitize_text_field($_POST['property_type'] ?? '');
$name = sanitize_text_field($_POST['name'] ?? '');
$phone = sanitize_text_field($_POST['phone'] ?? '');
$email = sanitize_email($_POST['email'] ?? '');
$urgency = sanitize_text_field($_POST['timeline'] ?? $_POST['urgency'] ?? '');
$message = sanitize_textarea_field($_POST['message'] ?? '');
if (empty($name) || empty($phone)) {
wp_send_json_error('Campos obligatorios incompletos.');
return;
}
// 1. Save in WordPress dashboard
$post_id = wp_insert_post(array(
'post_title' => "Lead: {$name} - {$location}",
'post_type' => 'lead',
'post_status' => 'publish',
));
if ($post_id) {
update_post_meta($post_id, '_lead_type_source', 'hero_form');
update_post_meta($post_id, '_lead_name', $name);
update_post_meta($post_id, '_lead_phone', $phone);
update_post_meta($post_id, '_lead_email', $email);
update_post_meta($post_id, '_lead_location', $location);
update_post_meta($post_id, '_lead_type', $type);
update_post_meta($post_id, '_lead_urgency', $urgency);
update_post_meta($post_id, '_lead_message', $message);
}
// 2. Send to Supabase
$payload = array(
'source' => 'hero_form',
'name' => $name,
'phone' => $phone,
'email' => $email,
'location' => $location,
'property_type' => $type,
'urgency' => $urgency,
'message' => $message,
);
try {
firma_re_send_to_supabase($payload);
} catch (Throwable $e) {
error_log('[Firma] Supabase hero form error: ' . $e->getMessage());
}
// 3. Send email notification
firma_re_send_lead_email($payload);
wp_send_json_success('Lead guardado correctamente.');
}
add_action('wp_ajax_submit_hero_valoracion', 'firma_re_handle_hero_form');
add_action('wp_ajax_nopriv_submit_hero_valoracion', 'firma_re_handle_hero_form');
/* =========================================================
* SELLER FORM — Handle AJAX Submission
* (Vende tu Propiedad page)
* ========================================================= */
function firma_re_handle_seller_lead()
{
// Security: verify nonce
if (!isset($_POST['seller_nonce']) || !wp_verify_nonce($_POST['seller_nonce'], 'firma_seller_nonce')) {
wp_send_json_error('Solicitud no válida.');
return;
}
$name = sanitize_text_field($_POST['name'] ?? '');
$phone = sanitize_text_field($_POST['phone'] ?? '');
$email = sanitize_email($_POST['email'] ?? '');
$address = sanitize_text_field($_POST['address'] ?? $_POST['location'] ?? '');
$prop_type= sanitize_text_field($_POST['property_type'] ?? '');
$urgency = sanitize_text_field($_POST['timeline'] ?? $_POST['urgency'] ?? '');
$message = sanitize_textarea_field($_POST['message'] ?? '');
if (empty($name) || empty($phone) || empty($address)) {
wp_send_json_error('Campos obligatorios incompletos.');
return;
}
// 1. Save in WordPress dashboard
$post_id = wp_insert_post(array(
'post_title' => "Vendedor: {$name} - {$address}",
'post_type' => 'lead',
'post_status' => 'publish',
));
if ($post_id) {
update_post_meta($post_id, '_lead_type_source', 'seller_form');
update_post_meta($post_id, '_lead_name', $name);
update_post_meta($post_id, '_lead_phone', $phone);
update_post_meta($post_id, '_lead_email', $email);
update_post_meta($post_id, '_lead_location', $address);
update_post_meta($post_id, '_lead_prop_type', $prop_type);
update_post_meta($post_id, '_lead_urgency', $urgency);
update_post_meta($post_id, '_lead_message', $message);
}
// 2. Send to Supabase
$payload = array(
'source' => 'seller_form',
'name' => $name,
'phone' => $phone,
'email' => $email,
'location' => $address,
'property_type' => $prop_type,
'urgency' => $urgency,
'message' => $message,
);
try {
firma_re_send_to_supabase($payload);
} catch (Throwable $e) {
error_log('[Firma] Supabase seller form error: ' . $e->getMessage());
}
// 3. Send email notification
firma_re_send_lead_email($payload);
wp_send_json_success('Lead de vendedor guardado y email enviado.');
}
add_action('wp_ajax_submit_seller_lead', 'firma_re_handle_seller_lead');
add_action('wp_ajax_nopriv_submit_seller_lead', 'firma_re_handle_seller_lead');
/* =========================================================
* ADMIN DASHBOARD — GET LEADS (AJAX)
* Reads leads from Supabase; requires admin capability.
* The service key stays server-side.
* ========================================================= */
function firma_leads_get()
{
// Security: only WP admins
if (!current_user_can('manage_options')) {
wp_send_json_error('Sin autorización.', 403);
return;
}
check_ajax_referer('firma_dashboard_nonce', 'nonce');
if (!defined('SUPABASE_URL') || !defined('SUPABASE_SERVICE_KEY')) {
wp_send_json_error('Credenciales de Supabase no configuradas.');
return;
}
// Build query params
$search = sanitize_text_field($_POST['search'] ?? '');
$source = sanitize_text_field($_POST['source'] ?? '');
$prop_type= sanitize_text_field($_POST['property_type'] ?? '');
$urgency = sanitize_text_field($_POST['urgency'] ?? '');
$status = sanitize_text_field($_POST['status'] ?? '');
$date_from= sanitize_text_field($_POST['date_from'] ?? '');
$date_to = sanitize_text_field($_POST['date_to'] ?? '');
$page = max(1, intval($_POST['page'] ?? 1));
$per_page = 50;
$offset = ($page - 1) * $per_page;
// Build Supabase REST query
$params = array(
'order' => 'created_at.desc',
'limit' => $per_page,
'offset' => $offset,
);
// Filters
if ($source) $params['source'] = 'eq.' . $source;
if ($prop_type) $params['property_type'] = 'eq.' . $prop_type;
if ($urgency) $params['urgency'] = 'eq.' . $urgency;
if ($status) $params['status'] = 'eq.' . $status;
if ($date_from) $params['created_at'] = 'gte.' . $date_from . 'T00:00:00Z';
if ($date_to) {
// If both from and to, use between-style — just override with lte for to
$params['created_at'] = ($date_from ? 'gte.' . $date_from . 'T00:00:00Z&created_at=lte.' . $date_to . 'T23:59:59Z' : 'lte.' . $date_to . 'T23:59:59Z');
}
// Text search across name/email/phone/location using Supabase 'or'
if ($search) {
$s = addslashes($search);
$params['or'] = "(name.ilike.*{$s}*,email.ilike.*{$s}*,phone.ilike.*{$s}*,location.ilike.*{$s}*)";
}
$url = rtrim(SUPABASE_URL, '/') . '/rest/v1/leads?' . http_build_query($params);
$response = wp_remote_get($url, array(
'headers' => array(
'apikey' => SUPABASE_SERVICE_KEY,
'Authorization' => 'Bearer ' . SUPABASE_SERVICE_KEY,
'Content-Type' => 'application/json',
'Prefer' => 'count=exact',
),
'timeout' => 15,
));
if (is_wp_error($response)) {
wp_send_json_error('Error de conexión con Supabase: ' . $response->get_error_message());
return;
}
$code = wp_remote_retrieve_response_code($response);
$body = wp_remote_retrieve_body($response);
$data = json_decode($body, true);
// Get total count from Content-Range header
$content_range = wp_remote_retrieve_header($response, 'content-range');
$total = 0;
if (preg_match('/\/(\d+)$/', $content_range, $m)) {
$total = intval($m[1]);
}
if ($code >= 200 && $code < 300) {
wp_send_json_success(array(
'leads' => $data,
'total' => $total,
'page' => $page,
'per_page'=> $per_page,
));
} else {
wp_send_json_error('Supabase error (' . $code . '): ' . $body);
}
}
add_action('wp_ajax_firma_leads_get', 'firma_leads_get');
/* =========================================================
* ADMIN DASHBOARD — UPDATE LEAD (AJAX)
* Updates status / notes for a specific lead.
* ========================================================= */
function firma_leads_update()
{
if (!current_user_can('manage_options')) {
wp_send_json_error('Sin autorización.', 403);
return;
}
check_ajax_referer('firma_dashboard_nonce', 'nonce');
if (!defined('SUPABASE_URL') || !defined('SUPABASE_SERVICE_KEY')) {
wp_send_json_error('Credenciales de Supabase no configuradas.');
return;
}
$id = sanitize_text_field($_POST['lead_id'] ?? '');
$status = sanitize_text_field($_POST['status'] ?? '');
$notes = sanitize_textarea_field($_POST['notes'] ?? '');
if (empty($id)) {
wp_send_json_error('ID de lead requerido.');
return;
}
$allowed_statuses = array('nuevo', 'contactado', 'en_proceso', 'cerrado', 'descartado');
if ($status && !in_array($status, $allowed_statuses, true)) {
wp_send_json_error('Estado no válido.');
return;
}
$patch = array();
if ($status) $patch['status'] = $status;
$patch['notes'] = $notes; // Can be empty string to clear notes
if ($status === 'contactado' || $status === 'en_proceso') {
$patch['contacted_at'] = gmdate('c');
}
$url = rtrim(SUPABASE_URL, '/') . '/rest/v1/leads?id=eq.' . urlencode($id);
$response = wp_remote_request($url, array(
'method' => 'PATCH',
'headers' => array(
'apikey' => SUPABASE_SERVICE_KEY,
'Authorization' => 'Bearer ' . SUPABASE_SERVICE_KEY,
'Content-Type' => 'application/json',
'Prefer' => 'return=representation',
),
'body' => wp_json_encode($patch),
'timeout' => 15,
));
if (is_wp_error($response)) {
wp_send_json_error('Error al actualizar: ' . $response->get_error_message());
return;
}
$code = wp_remote_retrieve_response_code($response);
if ($code >= 200 && $code < 300) {
wp_send_json_success('Lead actualizado correctamente.');
} else {
wp_send_json_error('Supabase error (' . $code . '): ' . wp_remote_retrieve_body($response));
}
}
add_action('wp_ajax_firma_leads_update', 'firma_leads_update');
Warning: Cannot modify header information - headers already sent by (output started at /home/u927131979/domains/firmarealestate.com/public_html/wp-content/themes/wp-theme-firma/functions.php:1) in /home/u927131979/domains/firmarealestate.com/public_html/wp-includes/feed-rss2-comments.php on line 8
Comentarios en:
https://firmarealestate.com/?attachment_id=236080
Mon, 09 Mar 2026 19:36:34 +0000
hourly
1
https://wordpress.org/?v=6.8.3