0

I have this code in functions.php in order to have a meta box displayed in the backend. The problem is, this was functioning normally until I've moved the website from a subdomain (dev) to the root and now even if the metabox appears in the backend, it doesn't retain the values anymore.

<?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')));

<?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()
{
    $post_id = $_GET['post'] ? $_GET['post'] : $_POST['post_ID'] ;
    if ($post_id == '2') {
    foreach (array('post','page') as $type) 
    {
        add_meta_box('my_all_meta_home', 'Additional info', 'my_meta_setup', $type, 'normal', 'high');
    }
    }
    add_action('save_post','my_meta_save');
}
function my_meta_setup()
{
    global $post;
    $meta = get_post_meta($post->ID,'_my_meta',TRUE);
    include(MY_THEME_FOLDER . '/meta.php');
    echo '<input type="hidden" name="my_meta_noncename" value="' . wp_create_nonce(__FILE__) . '" />';
}

function my_meta_save($post_id) 
{
    if (!wp_verify_nonce($_POST['my_meta_noncename'],__FILE__)) return $post_id;
    if ($_POST['post_type'] == 'page') 
    {
        if (!current_user_can('edit_page', $post_id)) return $post_id;
    } 
    $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;
        }
    }
}

Would you please help me understand what's wrong? I can't figure this out and is quite frustrating. The code is not changed at all, the output for my metabox is in another php file in the theme root, nothing is changed really.

The only thing I can think of, is that developing the website on a subdomain, when I've copied the files to the root I didn't create another database as I didn't need one and have used the one I had and then used a plugin to change all the URL's. And then I've used a plugin to search and replace URL values in the database, but this was happening before altering the database. I can't be this anyway.

When I edit the metabox in the back end, I have no error, the post/page is updated, but it's obvious the database doesn't retain the new values and after editing the fields are emtpy. Here's what I have in the meta.php:

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


<label>Body text</label>
<textarea name="_my_meta[body-text]" rows="5"><?php if(!empty($meta['body-text'])) echo $meta['body-text']; ?></textarea>
<span>Enter in the body text</span>


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

<span>e.g. <code><a href='services/' > View our Services page < /a ></code></span>

Later edit:

This is how I get my metabox values:

<?php 
global $wp_query;
$postid = $wp_query->post->ID;
$array = get_post_meta($postid,'_my_meta',TRUE);

  echo "<h1>"; echo $array['title']; echo "</h1>"; 
  echo '<p>'; echo $array['body-text']; echo '</p>'; 
  echo $array['link']; ?>
6
  • Probably not causing the issue but in anycase you should really use get_template_directory(); to get the Parent theme's directory (and get_stylesheet_directory() if you are after the child theme directory). See Codex. Commented Feb 24, 2012 at 10:35
  • Could you try to see why the meta is not saving. I.e. in your checks in my_meta_save, on failure, die with some message: wp_die('Reason for failure') to determine which check you are failing on. Also, you should check its not an auto-save routine. Commented Feb 24, 2012 at 10:40
  • Yes @StephenHarris, it doesn't cause issues as it loads, otherwise my php file wouldn't show up in the admin section, right? As for the error, this is the first time I am using wp_die() and wp_die('message') will show me "message" as expected. This line instead: wp_die( '<pre>' . var_export( $post, true ) . '</pre>' ); will show me NULL, if placed before function or in the beggining, but after return, it shows nothing. Commented Feb 24, 2012 at 11:06
  • are you sure that the data isn't saving, or is it just not showing up in the metaboxes on refresh? that could be an issue w/ your meta.php. is $meta defined in meta.php? Commented Feb 24, 2012 at 12:32
  • Is not showing up on refresh and that's why I've assumed that and then, after Stephen's help I've realised the data doesn't get saved.. then, I get the values in meta.php directly: <input type="text" name="_my_meta[title]" value="<?php if(!empty($meta['title'])) echo $meta['title']; ?>"/>, do I have to define $meta in meta.php? Commented Feb 24, 2012 at 13:11

1 Answer 1

0

Many of the comments below refer to code used for debugging, which for clarity I've removed.

I should have spotted this soon - you are adding only one row into the postmeta table, and that row has the key _my_meta. Before inserting the array int the table, WordPress serializes the array. When you retrieve the meta, you are retrieving a serialized array which you would then need to unserialize.

However, I don't think this is what you want, (nor is it advisable). It would be better to save each of the values in the array as a separate key-value pair in the database (this would be more effecient, and allowing querying of specific key-values etc).

To do that you need to loop through the received data array and add each key-value individually: (I have relaced your code with appropriate comments)

function my_meta_save($post_id) {

// verify this is not an auto save routine. 
if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE ) return $post_id;

//Perform nonce checks & permissions (for pages and posts)

//Sanitize the input 

//Declare a white list of 'keys' with their defaults (or null)
//- i.e. this code will not add any other keys:
$whitelist = array(
    'title'=>null,
    'img01-title'=>null,
    'img01-url'=>null
);
   //It would probably make sense to do this before sanitzing. 
    $new_data = shortcode_atts($whitelist,$new_data);

   //Now add/update or remove key-values appropriately
   foreach ($whitelist as $key=>$value){
        //If the key has a value, update it. If it doesn't already exist it will add it
        if(!is_null($whiltelist[$key]))
              update_post_meta($post_id,$key,$value);
        else
              delete_post_meta($post_id,$key);
    }

    //No need to return, this is an action not a filter
 }

Remarks

  1. I've added an auto-save check so that data is updated when the post/page auto saves
  2. You've checked permissions if the post is a page - you should do this for posts too.
  3. I've made use of shortcode_atts which will remove any keys that you haven't declared in $whitelist. It will assign default values to keys that are missing/don't have a value.
  4. update_post_meta will add a new key if it doesn't exist
8
  • Thank you for all your help. I've removed the concatenator from var_dumps after </pre> for both lines, and then I got this: string(11) "" string(16) "Array"success:. Now, what does it mean? That I have double quotes for the data inside and are not closed, and also on the link one.. that must be, my head is spinning now lol, I am starting to understand it, almost. Commented Feb 24, 2012 at 11:39
  • Sorry try updated code. Commented Feb 24, 2012 at 12:05
  • Everything looks fine, right?! I've updated all the fields I have: current data: string(0) "" sent data: array(12) { ["title"]=> string(4) "test" ["body-text"]=> string(4) "test" ["link"]=> string(4) "test" ["img01-title"]=> string(4) "test" ["img01-url"]=> string(4) "test" ["img01-link"]=> string(4) "test" ["title-2nd"]=> string(4) "test" ["body-text-2nd"]=> string(4) "test" ["link-2nd"]=> string(4) "test" ["img02-title"]=> string(4) "test" ["img02-url"]=> string(4) "test" ["img02-link"]=> string(4) "test" } success: Commented Feb 24, 2012 at 12:18
  • But if I go back and edit them again, I still get current data: string(0), and that would usually mean that the values are not actually saving, right? I will go and check the database, do a Search for one value.. Commented Feb 24, 2012 at 12:23
  • I don't know if it helps, but I have no values in the database with "test1", the string I have used for the latest test. Commented Feb 24, 2012 at 12:28

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.