Cyborg
Cyborg

Reputation: 1447

How to get and update single/multiple Custom Fields in post.php page?

I made simple form where I can add and update Custom fields in WordPress post.php page.

The working code I used

I added this code in the end of my themes function.php :

define('MY_WORDPRESS_FOLDER',$_SERVER['DOCUMENT_ROOT']);
define('MY_THEME_FOLDER',str_replace('\\','/',dirname(__FILE__)));
define('MY_THEME_PATH','/' . substr(MY_THEME_FOLDER,stripos(MY_THEME_FOLDER,'wp-content')));

add_action('admin_init','my_meta_init');

function my_meta_init()
{
    // review the function reference for parameter details
    // http://codex.wordpress.org/Function_Reference/wp_enqueue_script
    // http://codex.wordpress.org/Function_Reference/wp_enqueue_style

    //wp_enqueue_script('my_meta_js', MY_THEME_PATH . '/custom/meta.js', array('jquery'));
    wp_enqueue_style('my_meta_css', MY_THEME_PATH . '/custom/meta.css');

    // review the function reference for parameter details
    // http://codex.wordpress.org/Function_Reference/add_meta_box

    foreach (array('post','page') as $type) 
    {
        add_meta_box('my_all_meta', 'My Custom Meta Box', 'my_meta_setup', $type, 'normal', 'high');
    }

    add_action('save_post','my_meta_save');
}

function my_meta_setup()
{
    global $post;

    // using an underscore, prevents the meta variable
    // from showing up in the custom fields section
    $meta = get_post_meta($post->ID,'_my_meta',TRUE);

    // instead of writing HTML here, lets do an include
    include(MY_THEME_FOLDER . '/custom/meta.php');

    // create a custom nonce for submit verification later
    echo '<input type="hidden" name="my_meta_noncename" value="' . wp_create_nonce(__FILE__) . '" />';
}

function my_meta_save($post_id) 
{
    // authentication checks

    // make sure data came from our meta box
    if (!wp_verify_nonce($_POST['my_meta_noncename'],__FILE__)) return $post_id;

    // check user permissions
    if ($_POST['post_type'] == 'page') 
    {
        if (!current_user_can('edit_page', $post_id)) return $post_id;
    }
    else 
    {
        if (!current_user_can('edit_post', $post_id)) return $post_id;
    }

    // authentication passed, save data

    // var types
    // single: _my_meta[var]
    // array: _my_meta[var][]
    // grouped array: _my_meta[var_group][0][var_1], _my_meta[var_group][0][var_2]

    $current_data = get_post_meta($post_id, '_my_meta', TRUE);  

    $new_data = $_POST['_my_meta'];

    my_meta_clean($new_data);

    if ($current_data) 
    {
        if (is_null($new_data)) delete_post_meta($post_id,'_my_meta');
        else update_post_meta($post_id,'_my_meta',$new_data);
    }
    elseif (!is_null($new_data))
    {
        add_post_meta($post_id,'_my_meta',$new_data,TRUE);
    }

    return $post_id;
}

function my_meta_clean(&$arr)
{
    if (is_array($arr))
    {
        foreach ($arr as $i => $v)
        {
            if (is_array($arr[$i])) 
            {
                my_meta_clean($arr[$i]);

                if (!count($arr[$i])) 
                {
                    unset($arr[$i]);
                }
            }
            else 
            {
                if (trim($arr[$i]) == '') 
                {
                    unset($arr[$i]);
                }
            }
        }

        if (!count($arr)) 
        {
            $arr = NULL;
        }
    }
}

Then I created a folder named "custom" inside my themes folder and saved this 2 files in there: meta.php and meta.css

meta.php looks like:

<div class="my_meta_control">

    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras orci lorem, bibendum in pharetra ac, luctus ut mauris. Phasellus dapibus elit et justo malesuada eget <code>functions.php</code>.</p>

    <label>Name</label>

    <p>
        <input type="text" name="_my_meta[link]" value="<?php if(!empty($meta['link'])) echo $meta['link']; ?>"/>
        <span>Enter in a name</span>
    </p>

    <label>Description <span>(optional)</span></label>

    <p>
        <textarea name="_my_meta[description]" rows="3"><?php if(!empty($meta['description'])) echo $meta['description']; ?></textarea>
        <span>Enter in a description</span>
    </p>

</div>

meta.css looks like :

.my_meta_control .description { display:none; }

.my_meta_control label { display:block; font-weight:bold; margin:6px; margin-bottom:0; margin-top:12px; }

.my_meta_control label span { display:inline; font-weight:normal; }

.my_meta_control span { color:#999; display:block; }

.my_meta_control textarea, .my_meta_control input[type='text'] { margin-bottom:3px; width:99%; }

.my_meta_control h4 { color:#999; font-size:1em; margin:15px 6px; text-transform:uppercase; }

With this code above I get this result:

enter image description here

Now I can add and update Name and Description Custom Fields here which works great.

Thats what I wanted BUT the problem IS:

This box will use "Name" and "Description" from: _my_meta and I don't want it. Previously I have already saved Custom Fields Values to all my published posts as: phone, home_city, home_country, name ++

My question is: How can I modify this Code to work with my already saved custom fields instead of using this new _my_meta ? As mentioned my custom field names is: phone, home_city, home_country, name ++

Upvotes: 1

Views: 1885

Answers (1)

brasofilo
brasofilo

Reputation: 26055

Simple, you don't need _my_meta. And before anything is worth noting that your example uses this single meta key to store multiple values as a serialized array, _my_meta[link] and _my_meta[description]. So it looks like this after deserializing:

'my_meta' = array(
   'link' => 'some value',
   'description' => 'another value'
)

The thing is, it's practical to use a single custom field as a container for many key/values, but this is not good if you plan to use those fields for searching results or ordering a query by meta key. In this case it's better to use single fields.

As you say that you already have custom fields, much probably they are single fields, in which case you'd do the following to adapt the code.

In my_meta_setup():

$phone = get_post_meta( $post->ID, 'phone', TRUE );
$phone = !empty($phone) ? $phone : ''; // this makes the HTML cleaner
$home_city = get_post_meta( $post->ID, 'home_city', TRUE );
$home_city = !empty($home_city) ? $home_city : '';
?>
<input type="text" name="phone" value="<?php echo $phone; ?>"/>
<input type="text" name="home_city" value="<?php echo $home_city; ?>"/>

In my_meta_save():

$phone = get_post_meta( $post_id, 'phone', TRUE );  
$home_city = get_post_meta( $post_id, 'home_city', TRUE );  
update_post_meta( $post_id, 'phone', $new_phone );
update_post_meta( $post_id, 'home_city', $new_home_city );

Other notes:

  • put wp_enqueue_style inside a wp_enqueue_scripts action hook.

  • avoid using constants. We can get the theme folder with get_stylesheet_directory_uri() and the path with get_stylesheet_directory().

  • WordPress path is already defined in ABSPATH and the URL we can get with site_url(), but you probably don't need this.

  • the action hook save_post takes 2 arguments, the second being $post, we don't need the global

    add_action( 'save_post','my_meta_save', 10, 2 );
    function my_meta_save( $post_id, $post ) {}
    

Upvotes: 1

Related Questions