1

I have a custom post type "Propietario" with several custom fields, and 3 of them: "dni", "email" and "phone" I need unique for all Propietario Post types. This CPT is only accesible throw admin wordpress page.

@vijay-pancholi's answer has made me understand what is the flow when registering new custom fields. And after this I have edited my answer.

I am using object-oriented programming for creating my CPT since it is part of a more complex plugin. The method involved, which stores the fields, is "properties_save_fields_owner". The code is more complex but I have tried to reduce it to show only the code involved for this problem:

 <?php

 class Propietario {
public function __construct() {
    add_action('init', array($this, 'registrar_cpt_propietario'));
    add_action('add_meta_boxes', array($this, 'propietarios_meta_box'));
    add_action('save_post', array($this, 'inmuebles_guardar_campos_propietario'));
}

    
/**
 * Registration Propietario CPT
 */
public function registrar_cpt_propietario() {
    $labels = array(
        'name' => 'Propietario',
        'singular_name' => 'Propietario',
        'menu_name' => 'Propietarios',
        'name_admin_bar' => 'Propietario',
        'add_new' => 'Añadir Propietario',
        ...
    );

    $args = array(
        'labels' => $labels,
        'public' => false,
        ...
    );
    
    register_post_type('propietario', $args);
}

/**
 * Add metabox "Datos del propietario"
 */
public function propietarios_meta_box() {
    add_meta_box('propietarios_info', 
        'Información del Propietario', 
        array($this, 'mostrar_campos_propietario'), 
        'propietario',
        'normal',
        'high' );
}

/**
 * Muestra los campos del propietario en el formulario de edición de propietarios.
 * @param WP_Post $post El objeto de entrada actual.
 */
public function mostrar_campos_propietario($post) {
    $nombre = get_post_meta($post->ID, 'nombre', true);
    $apellidos = get_post_meta($post->ID, 'apellidos', true);
    $email = get_post_meta($post->ID, 'email', true);
    $telefono = get_post_meta($post->ID, 'telefono', true);
    $dni = get_post_meta($post->ID, 'dni', true);
    ?>
    <div id="contenedor-propietario">
        <table class="form-table">
            <tr>
                <th><label for="nombre">Nombre*</label></th>
                <td><input type="text" name="nombre" id="nombre" value="<?php echo esc_attr($nombre ?? ''); ?>" required></td>
            </tr>
            
            ...
        </table>
    </div>
    <?php 
}


/**
 * Saves custom field values when saving an propietario
 * @param int $post_id ID of the current propietario
 */
function inmuebles_guardar_campos_propietario($post_id) {
    // Check if it's not an autosave
    if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;
    // Check if it's the correct post type
    if ('propietario' !== get_post_type($post_id)) return;

    //Check if there is already an owner with the same DNI, email or telefono
    $dni = isset($_POST['dni']) ? sanitize_text_field($_POST['dni']) : '';
    $email = isset($_POST['email']) ? sanitize_text_field($_POST['email']) : '';
    $telefono = isset($_POST['telefono']) ? sanitize_text_field($_POST['telefono']) : '';

    //Check if there is already an owner with the same DNI, email or telefono
    if (!empty($dni) || !empty($email) || !empty($telefono)) {
        $exists_propietario  = get_posts(array(
            'post_type' => 'propietario',
            'post_status' => 'publish',
            'meta_query' => array(
                'relation' => 'OR',
                array(
                    'key' => 'dni',
                    'value' => $dni,
                    'compare' => '='
                ),
                array(
                    'key' => 'email',
                    'value' => $email,
                    'compare' => '='
                ),
                array(
                    'key' => 'telefono',
                    'value' => $telefono,
                    'compare' => '='
                ),
            ),
        ));
    } else {
        $exists_propietario = array();
    }

    if (!empty($exists_propietario)) {
        wp_die('Ya existe un propietario con el mismo DNI, teléfono o email. <br> <a href="javascript:history.back()">Volver</a>', 'Error', array('response' => 400));
    }
        
    // Guardar los metadatos del propietario
    if (array_key_exists('nombre', $_POST)) {
        update_post_meta($post_id, 'nombre', sanitize_text_field($_POST['nombre']));
    }
    if (array_key_exists('apellidos', $_POST)) {
        update_post_meta($post_id, 'apellidos', sanitize_text_field($_POST['apellidos']));
    }
    if (array_key_exists('email', $_POST)) {
        update_post_meta($post_id, 'email', sanitize_text_field($_POST['email']));
    }
    if (array_key_exists('telefono', $_POST)) {
        update_post_meta($post_id, 'telefono', sanitize_text_field($_POST['telefono']));
    }
    if (array_key_exists('dni', $_POST)) {
        update_post_meta($post_id, 'dni', sanitize_text_field($_POST['dni']));
    } 
}

  }

 new Propietario();

After debugging, the main problem is that the method inmuebles_save_fields_propietario is executed several times. When I try to create a new CPT it runs right when the metabox opens clicking in "add new". That's why I added the line:

if (!empty($id) || !empty($email) || !empty($telephone)) {

And the code is correct, but even if the line is executed:

wp_die('There is already an owner with the same ID, phone number or email. <br> <a href="javascript:history.back()">Back</a>', 'Error', array('response' = > 400));

The method is executed again and for some reason that I don't know the CPT is registered. You register with empty fields, but a new Owner is created.

I have tried adding exit() after the wp_die, but there is no way I can prevent the method from being executed again, and therefore a new CPT is registered.

How Can I stop registration of CPT when display the error?

2 Answers 2

1

you can use the save_post hook to validate the uniqueness of email and phone fields before saving the post.

Replace seller with your actual post type slug and add below code in functions.php file

// Add custom meta box for Seller post type
function add_seller_meta_box() {
    add_meta_box(
        'seller_meta_box',
        'Seller Details',
        'render_seller_meta_box',
        'seller',
        'normal',
        'default'
    );
}
add_action('add_meta_boxes', 'add_seller_meta_box');

// Render the custom meta box fields
function render_seller_meta_box($post) {
    // Add your custom fields HTML inputs here
    echo '<label for="seller_email">Email:</label>';
    echo '<input type="text" id="seller_email" name="seller_email" value="' . get_post_meta($post->ID, 'seller_email', true) . '" /><br>';

    echo '<label for="seller_phone">Phone:</label>';
    echo '<input type="text" id="seller_phone" name="seller_phone" value="' . get_post_meta($post->ID, 'seller_phone', true) . '" /><br>';
}

// Save custom meta box data
function save_seller_meta_box_data($post_id) {
    // Check if it's not an autosave
    if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;

    // Check if the current user has permission to edit the post
    if (!current_user_can('edit_post', $post_id)) return;

    // Check if it's the correct post type
    if ('seller' !== get_post_type($post_id)) return;

    // Validate uniqueness of email and phone fields
    $email = isset($_POST['seller_email']) ? sanitize_email($_POST['seller_email']) : '';
    $phone = isset($_POST['seller_phone']) ? sanitize_text_field($_POST['seller_phone']) : '';

    // Check if email or phone already exists
    $existing_sellers = get_posts(array(
        'post_type' => 'seller',
        'post_status' => 'publish',
        'meta_query' => array(
            'relation' => 'OR',
            array(
                'key' => 'seller_email',
                'value' => $email,
                'compare' => '='
            ),
            array(
                'key' => 'seller_phone',
                'value' => $phone,
                'compare' => '='
            )
        )
    ));

    if (!empty($existing_sellers)) {
        wp_die('A seller with this email or phone already exists.', 'Duplicate Seller', array('response' => 400));
    }

    // Save meta data
    update_post_meta($post_id, 'seller_email', $email);
    update_post_meta($post_id, 'seller_phone', $phone);
}
add_action('save_post', 'save_seller_meta_box_data');
1

I finally solved it by doing the validation before the registration process. In this way, the registration does not start until the fields are validated:

 /** Validation fields **/
function validar_datos_propietario($post_ID, $data) {
    if ('propietario' !== $data['post_type']) return;

    $dni = isset($_POST['dni']) ? sanitize_text_field($_POST['dni']) : '';
    $email = isset($_POST['email']) ? sanitize_text_field($_POST['email']) : '';
    $telefono = isset($_POST['telefono']) ? sanitize_text_field($_POST['telefono']) : '';

    $meta_query = array('relation' => 'OR');

    if (!empty($dni)) {
        $meta_query[] = array(
           'key' => 'dni',
           'value' => $dni,
           'compare' => '='
        );
    }

    $meta_query[] = array(
        'key' => 'email',
        'value' => $email,
        'compare' => '='
    );

    $meta_query[] = array(
        'key' => 'telefono',
        'value' => $telefono,
        'compare' => '='
    );

    $exists_propietario = get_posts(array(
        'post_type' => 'propietario',
        'post_status' => 'publish',
        'meta_query' => $meta_query,
    ));

    if (!empty($exists_propietario)) {
        wp_die('Ya existe un propietario con los mismos datos<br> <a href="javascript:history.back()">Volver</a>', 'Error', array('response' => 400));
    }

 }   
 add_action('pre_post_update', 'validar_datos_propietario', 10, 2);

with pre_post_update registration does not start until the fields are validated

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.