phpwordpressmeta-boxes

WordPress - custom post type metabox not save information into DB when post is submitted


I have this code in a WordPress Plugin that will register a custom post type to manage some products that I will display using the rest API.

    public function setup_post_type()
    {
        $post_type_supports = [
            'title',
            'editor',
            'revisions',
            'thumbnail'
            //'custom-fields'
        ];

        register_post_type( 
            'products',
            [
                'label' => 'Products',
                'description' => 'Temporary products managment',
                'show_in_rest' => true,
                'rest_namespace' => $this->namespace,
                'public' => true,
                'supports' => $post_type_supports,
                'show_ui' => true,
                'show_in_menu' => true,
                'menu_icon' => 'dashicons-store',
                'register_meta_box_cb' => [$this, 'register_product_metabox']
            ]
        );

    }

    //
    public function register_product_metabox()
    {
        add_meta_box( 
            'temporary_product_metabox', 
            'Products informations', 
            [$this, 'product_metabox_content'], 
            'products', 
        );
    }

    public function product_metabox_content()
    {
        wp_nonce_field('product_metabox', 'product_metabox_nonce');
        ?>
            <p>
                <label for="cod-prod">Product code</label>
            </p>
            <p>
                <input type="text" id="cod-prod" name="product_code">
            </p>            
            <p>
                <label for="category">Category</label>            
            </p>
            <p>
                <input type="text" id="category" name="category">
            </p>
            <p>
                <label fro="unit">Unit</label>
            </p>
            <p>
                <select name="unit" id="unit">
                    <option disabled selected>Select an option</option>
                    <option value="kg">kg</option>
                    <option value="pcs">pcs</option>
                </select>
            </p>            
            <p>
                <label for="info">Info</label>
            </p>
            <p>
                <input type="text" name="info" id="info">
            </p>
            <p>
                <label for="start">Start date</label>
            </p>
            <p>
                <input type="date" id="start" name="start_date">
            </p>            
            <p>
                <label for="end">End date</label>
            </p>
            <p>
                <input type="date" id="end" name="end_date">
            </p>
        <?php
    }

    public function save_product_metabox_data($post_id)
    {
        if( !wp_verify_nonce('product_metabox', 'product_metabox_nonce') ){
            return false;
        } else {
            //
            //$post_mets = array_map($this->check_post_array(), $_POST);
            $serached_keys = [
                'product_code',
                'category',
                'unit',
                'info',
                'start_date',
                'end_date'
            ];

            $post_meta = array_intersect_key($_POST, $serached_keys);

            foreach( $post_meta as $key => $val ){
                update_post_meta( 
                    $post_id, 
                    $key, 
                    $val, 
                );
            }
        }
    }

I've noticed that when I try to save the data that are coming from the metabox, inside the postmeta table nothing is added, but only the post is saved correctly.

What I'm doing wrong and how I can fix this?


Solution

  • Your error is coming from array_intersect_key array_intersect_key only compares keys and returns items with the same keys.

    Going by the below array in your code:

    $serached_keys = [
                    'product_code',
                    'category',
                    'unit',
                    'info',
                    'start_date',
                    'end_date'
                ];
    

    The keys to the above array are integer like so:

    $serached_keys = [
                    0 =>'product_code',
                    1 =>'category',
                    2 =>'unit',
                    3 =>'info',
                    4 =>'start_date',
                    5 =>'end_date'
                ];
    

    Using array_intersect_key to compare the $serached_keys array and a $_POST array which has string keys like the array below will return empty array

     $POST   =     [ 'product_code' => 'product code value',
                    'category' => 'category value',
                    'unit' => 'unit value',
                    'info' => 'info value',
                    'start_date' => 'start_date value',
                    'end_date' => 'end date value' ];
    

    Now to the solution since we have detected the problem:

    reverse your check array like so:

    $new_serached_keys = [
                    'product_code' => 0,
                    'category' =>1,
                    'unit' => 2,
                    'info' => 3,
                    'start_date'=>4,
                    'end_date' =>5
                ]; 
    

    Using this in $post_meta = array_intersect_key($_POST, $new_serached_keys); will return an array of item that have similar keys on both array

    NOTE this will not compare values

    Your new code should look like the below code to work:

     public function setup_post_type()
        {
            $post_type_supports = [
                'title',
                'editor',
                'revisions',
                'thumbnail'
                //'custom-fields'
            ];
    
            register_post_type( 
                'products',
                [
                    'label' => 'Products',
                    'description' => 'Temporary products managment',
                    'show_in_rest' => true,
                    'rest_namespace' => $this->namespace,
                    'public' => true,
                    'supports' => $post_type_supports,
                    'show_ui' => true,
                    'show_in_menu' => true,
                    'menu_icon' => 'dashicons-store',
                    'register_meta_box_cb' => [$this, 'register_product_metabox']
                ]
            );
    
        }
    
        //
        public function register_product_metabox()
        {
            add_meta_box( 
                'temporary_product_metabox', 
                'Products informations', 
                [$this, 'product_metabox_content'], 
                'products', 
            );
        }
    
        public function product_metabox_content()
        {
            wp_nonce_field('product_metabox', 'product_metabox_nonce');
            ?>
                <p>
                    <label for="cod-prod">Product code</label>
                </p>
                <p>
                    <input type="text" id="cod-prod" name="product_code">
                </p>            
                <p>
                    <label for="category">Category</label>            
                </p>
                <p>
                    <input type="text" id="category" name="category">
                </p>
                <p>
                    <label fro="unit">Unit</label>
                </p>
                <p>
                    <select name="unit" id="unit">
                        <option disabled selected>Select an option</option>
                        <option value="kg">kg</option>
                        <option value="pcs">pcs</option>
                    </select>
                </p>            
                <p>
                    <label for="info">Info</label>
                </p>
                <p>
                    <input type="text" name="info" id="info">
                </p>
                <p>
                    <label for="start">Start date</label>
                </p>
                <p>
                    <input type="date" id="start" name="start_date">
                </p>            
                <p>
                    <label for="end">End date</label>
                </p>
                <p>
                    <input type="date" id="end" name="end_date">
                </p>
            <?php
        }
    
        public function save_product_metabox_data($post_id)
        {
            if( !wp_verify_nonce('product_metabox', 'product_metabox_nonce') ){
                return false;
            } else {
                //
                //$post_mets = array_map($this->check_post_array(), $_POST);
    //Made the below array an associative array so that the keys can
    //match $_POST keys
                $serached_keys = [
                    'product_code'=>"",
                    'category'=>"",
                    'unit'=>"",
                    'info'=>"",
                    'start_date'=>"",
                    'end_date'=>""
                ];
    
                $post_meta = array_intersect_key($_POST, $serached_keys);
    
                foreach( $post_meta as $key => $val ){
                    update_post_meta( 
                        $post_id, 
                        $key, 
                        $val, 
                    );
                }
            }
        }