I am working on some custom post types. I finished the first one and realized that the metabox code I was using could be re-used by other, future, custom post types (as well as pages, posts, etc). So I put the class in its own php file and included it from the functions.php file of my child theme. I've never used classes before, but I thought I could then call that class from wherever I wanted since that is what I do for functions. instead I called it from my post-types.php file and got the following error:
"Fatal error: Class 'My_meta_box' not found in D:\helga\xampp\htdocs\plagueround\wp-content\themes\plagueround_new2\functions\post-types.php on line 73"
In the functions.php of my child theme I've included the file where my class lives:
define('CHILDTHEME_DIRECTORY', get_stylesheet_directory() . '/');
// Meta Box Class - makes meta boxes
require_once(CHILDTHEME_DIRECTORY . 'functions/meta_box_class.php');
here's my class
//My Meta Box CLASS
//from: http://www.deluxeblogtips.com/2010/05/howto-meta-box-wordpress.html
class My_meta_box {
protected $_meta_box;
// create meta box based on given data
function __construct($meta_box) {
$this->_meta_box = $meta_box;
add_action('admin_menu', array(&$this, 'add'));
add_action('save_post', array(&$this, 'save'));
}
/// Add meta box for multiple post types
function add() {
foreach ($this->_meta_box['pages'] as $page) {
add_meta_box($this->_meta_box['id'], $this->_meta_box['title'], array(&$this, 'show'), $page, $this->_meta_box['context'], $this->_meta_box['priority']);
}
}
// Callback function to show fields in meta box
function show() {
global $post;
// Use nonce for verification
echo '<input type="hidden" name="mytheme_meta_box_nonce" value="', wp_create_nonce(basename(__FILE__)), '" />';
echo '<table class="form-table">';
foreach ($this->_meta_box['fields'] as $field) {
// get current post meta data
$meta = get_post_meta($post->ID, $field['id'], true);
echo '<tr>',
'<th style="width:20%"><label for="', $field['id'], '">', $field['name'], '</label></th>',
'<td>';
switch ($field['type']) {
case 'text':
echo '<input type="text" name="', $field['id'], '" id="', $field['id'], '" value="', $meta ? $meta : $field['std'], '" size="30" style="width:97%" />',
'<br />', $field['desc'];
break;
case 'textarea':
echo '<textarea name="', $field['id'], '" id="', $field['id'], '" cols="60" rows="4" style="width:97%">', $meta ? $meta : $field['std'], '</textarea>',
'<br />', $field['desc'];
break;
case 'select':
echo '<select name="', $field['id'], '" id="', $field['id'], '">';
foreach ($field['options'] as $option) {
echo '<option', $meta == $option ? ' selected="selected"' : '', '>', $option, '</option>';
}
echo '</select>';
break;
case 'select2': //for when value and display text don't match
//$options array must be multidimensional with both the 'value' and the 'text' for each option
//for example = array( array(text=>text1,value=>value1),array(text=>text2,value=>value2))
//then in <option> value = $option['value'] and text = $option['text']
echo '<select name="', $field['id'], '" id="', $field['id'], '">';
foreach ($field['options'] as $option) {
echo '<option value="',$option['value'],'"', $meta == $option['value'] ? ' selected="selected"' : '', '>', $option['desc'], '</option>';
}
echo '</select>';
break;
case 'radio':
foreach ($field['options'] as $option) {
echo '<input type="radio" name="', $field['id'], '" value="', $option['value'], '"', $meta == $option['value'] ? ' checked="checked"' : '', ' />', $option['name'];
}
break;
case 'checkbox':
echo '<input type="checkbox" name="', $field['id'], '" id="', $field['id'], '"', $meta ? ' checked="checked"' : '', ' />';
break;
}
echo '<td>',
'</tr>';
}
echo '</table>';
}
// Save data from meta box
function save($post_id) {
// verify nonce
if (!wp_verify_nonce($_POST['mytheme_meta_box_nonce'], basename(__FILE__))) {
return $post_id;
}
// check autosave
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
return $post_id;
}
// check permissions
if ('page' == $_POST['post_type']) {
if (!current_user_can('edit_page', $post_id)) {
return $post_id;
}
} elseif (!current_user_can('edit_post', $post_id)) {
return $post_id;
}
foreach ($this->_meta_box['fields'] as $field) {
$old = get_post_meta($post_id, $field['id'], true);
$new = $_POST[$field['id']];
if ($new && $new != $old) {
update_post_meta($post_id, $field['id'], $new);
} elseif ('' == $new && $old) {
delete_post_meta($post_id, $field['id'], $old);
}
}
}
}
then in my post-types.php file where i am defining some meta boxes for a custom post type i have:
$prefix = '_events_';
$post_id = $_GET['post'] ? $_GET['post'] : $_POST['post_ID'] ;
$events_meta_box = array(
'id' => 'wpt_events',
'title' => 'Events Options',
'pages' => array('events'), // multiple post types possible
'context' => 'side',
'priority' => 'low',
'fields' => array(
array(
'name' => 'Headline',
'desc' => 'Enter the heading you\'d like to appear before the video',
'id' => $prefix . 'heading1',
'type' => 'text',
'std' => ''
),
)
);
$my_box = new My_meta_box($events_meta_box);
So- how do I reference classes from other files?
EDITS/CONTINUATION
simply moving the require_once statement to the post-types.php (the one trying to call the class) seemed to work. but for the heck of it i tried the autoload script
function __autoload($className)
{
require(CHILDTHEME_DIRECTORY .'functions/class_' . $className . '.php') ;
}
where I renamed my class file to class_My_meta_box.php and My_meta_box is the class name
which results in the following errors:
Warning: require(D:\helga\xampp\htdocs\plagueround/wp-content/themes/plagueround_new/functions/class_WP_User_Search.php) [function.require]: failed to open stream: No such file or directory in D:\helga\xampp\htdocs\plagueround\wp-content\themes\plagueround_new\functions.php on line 66
Fatal error: require() [function.require]: Failed opening required 'D:\helga\xampp\htdocs\plagueround/wp-content/themes/plagueround_new/functions/class_WP_User_Search.php' (include_path='.;D:\helga\xampp\php\PEAR') in D:\helga\xampp\htdocs\plagueround\wp-content\themes\plagueround_new\functions.php on line 66
i don't totally understand what it says, BUT i think it is trying to autoload some default wordpress class... and is looking in my directory where it obviously doesn't exist.
Actually, it doesnt matter if the file contains a class or something else. For PHP being able to execute code from other files, PHP has to know where the file is, so it's your regular require or include.
Example:
// foo.class.php
class Foo {}
// main.php
require_once '/path/to/foo.class.php';
$foo = new Foo;
When using classes, it actually makes sense to use a Naming Convention and use an Autoloader, so PHP will try to include the class on it's own, without you having to require or include it.
You can use the constant WP_PLUGIN_DIR to describe the path.
// Foo.class.php
class Foo {}
// main.php
require_once WP_PLUGIN_DIR.'/Foo.class.php';
$foo = new Foo;
Just use the absolute path:
require_once("fullpath/functions/meta_box_class.php") or die ("Could Not load file");
It looks like meta_box_class.php isn't being included. To find out what files have been included at any point, try:
var_dump(get_included_files());
Related
Sorry about the code format, CTRL+K is said to move things 4 spaces. But it doesnt work in Chrome:(
Update: Amazing, I tried this 4 times. EAch time it triggered a Chrome Shortcut. I gave up and submitted this. It gave an error saying that I had code and did not properly format it. Then amazingly, Ctrl+K works. Not sure why this is so hard...
ANYWAYS,
I upgraded to WP 5.0 on a customer site and now all of the custom fields do not save.... I was using custom code and now the fields do not show in wordpress. It seems that everything I try today is not working. StackOverflow is now the latest to join this...
Id appreciate some help with this if anyone can read the last result.
-------------------------
$meta_box = array(
'id' => 'tunebot-meta-marketing-box',
'title' => 'Enable Marketing Links?',
'page' => 'page',
'context' => 'normal',
'priority' => 'high',
'fields' => array(
array(
'name' => 'Hide Title?',
'id' => 'tunebot_hide_titler',
'type' => 'checkbox'
),
array(
'name' => 'Display Image?',
'id' => 'tunebot_display_image',
'type' => 'checkbox'
),
array(
'name' => 'Enable Top Banner?',
'id' => 'tunebot_banner',
'type' => 'checkbox'
),
array(
'name' => 'Enable Marketing Links?',
'id' => 'tunebot_marketing_links',
'type' => 'checkbox'
),
)
);
add_action('admin_init', 'tunebot_add_box');
// Add meta box
function tunebot_add_box() {
global $meta_box;
add_action('post_submitbox_misc_actions', 'tunebot_show_box');
//add_meta_box($meta_box['id'], $meta_box['title'], 'tunebot_show_box', $meta_box['page'], $meta_box['context'], $meta_box['priority']);
}
/**
* Shows a box with options bellow it, under the text of the body.
*/
function tunebot_show_box() {
global $meta_box, $post;
// Use nonce for verification
$output = '<input type="hidden" name="tunebot_meta_box_nonce" value="' . wp_create_nonce(basename(__FILE__)) . '"/>';
foreach($meta_box['fields'] as $field) {
// get current post meta data
$postId = $post->ID;
$key = 'tb_' . $field['id'];
$meta = get_post_meta($postId, $field['id'], TRUE);
$output .= '<div class="misc-pub-section misc-pub-section-last">';
switch($field['type']) {
case 'text':
$output .= '<input type="text" name="' . $key . '" id="' . $key . '"
value="' . $meta ? $meta : $field['std'] . '" size="30" style="width:97%"/>' . '<br/>' .
$field['desc'];
break;
case 'textarea':
$output .= '<textarea name="' . $key . '" id="' . $key . '" cols="60" rows="4"
style="width:97%">' . $meta ? $meta : $field['std'] . '</textarea>' . '<br/>' .
$field['desc'];
break;
case 'select':
$output .= '<select name="' . $key . '" id="' . $key . '">';
foreach($field['options'] as $option) {
$output .= '
<option
' . $meta == $option ? ' selected="selected"' : '' . '>' . $option . '</option>';
}
$output .= '</select>';
break;
case 'radio':
foreach($field['options'] as $option) {
$output .= '<input type="radio" name="' . $key . '" value="' . $option['value'] . '"' . (($meta == $option['value']) ? ' checked="checked"' : '' . ' />' . $option['name']);
}
break;
case 'checkbox':
$output .= '<input type="checkbox" name="' . $key . '" id="' . $key . '"' . ($meta == "on" ? ' checked="checked"' : '') . ' />';
break;
}
$output .= '<label for="' . $key . '">' . $field['name'] . '</label></div>';
}
echo $output;
}
add_action('save_post', 'tunebot_save_data');
function tunebot_save_data($post_id) {
global $meta_box;
// verify nonce
if(isset($_POST['tunebot_meta_box_nonce']) && !wp_verify_nonce($_POST['tunebot_meta_box_nonce'], basename(__FILE__))) {
return $post_id;
}
// check autosave
if(defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
return $post_id;
}
// check permissions
if(isset($_POST['post_type']) && 'page' == $_POST['post_type']) {
if(!current_user_can('edit_page', $post_id)) {
return $post_id;
}
} elseif(!current_user_can('edit_post', $post_id)) {
return $post_id;
}
foreach($meta_box['fields'] as $field) {
if(isset($field['id'])) {
$key = 'tb_' . $field['id'];
if(isset($_POST[$key])) {
$new = $_POST[$key];
} else {
$new = FALSE;
}
$old = get_post_meta($post_id, $field['id'], TRUE);
if($new && $new != $old) {
update_post_meta($post_id, $field['id'], $new);
} elseif('' == $new && $old) {
delete_post_meta($post_id, $field['id'], $old);
}
}
}
return $post_id;
}
I'm trying to disable the wpautop filter on pages where the metabox checkbox is selected.
Here is the code to add my checkbox, I know it's a bit verbose but it was originally taken from an example with multiple elements to add. I'm planning on editing it later.
$prefix = 'dbkt_';
$meta_box = array(
'id' => 'my-meta-box',
'title' => 'Disable Automatic formatting?',
'page' => 'page',
'context' => 'normal',
'priority' => 'high',
'fields' => array(
array(
'name' => 'Disable wpautop?',
'id' => $prefix . 'checkbox',
'type' => 'checkbox'
)
)
);
add_action('admin_menu', 'mytheme_add_box');
// Add meta box
function mytheme_add_box() {
global $meta_box;
add_meta_box($meta_box['id'], $meta_box['title'], 'mytheme_show_box', $meta_box['page'], $meta_box['context'], $meta_box['priority']);
}
// Callback function to show fields in meta box
function mytheme_show_box() {
global $meta_box, $post;
// Use nonce for verification
echo '<input type="hidden" name="mytheme_meta_box_nonce" value="', wp_create_nonce(basename(__FILE__)), '" />';
echo '<table class="form-table">';
foreach ($meta_box['fields'] as $field) {
// get current post meta data
$meta = get_post_meta($post->ID, $field['id'], true);
echo '<tr>',
'<th style="width:20%"><label for="', $field['id'], '">', $field['name'], '</label></th>',
'<td>';
switch ($field['type']) {
case 'text':
echo '<input type="text" name="', $field['id'], '" id="', $field['id'], '" value="', $meta ? $meta : $field['std'], '" size="30" style="width:97%" />', '<br />', $field['desc'];
break;
case 'textarea':
echo '<textarea name="', $field['id'], '" id="', $field['id'], '" cols="60" rows="4" style="width:97%">', $meta ? $meta : $field['std'], '</textarea>', '<br />', $field['desc'];
break;
case 'select':
echo '<select name="', $field['id'], '" id="', $field['id'], '">';
foreach ($field['options'] as $option) {
echo '<option ', $meta == $option ? ' selected="selected"' : '', '>', $option, '</option>';
}
echo '</select>';
break;
case 'radio':
foreach ($field['options'] as $option) {
echo '<input type="radio" name="', $field['id'], '" value="', $option['value'], '"', $meta == $option['value'] ? ' checked="checked"' : '', ' />', $option['name'];
}
break;
case 'checkbox':
echo '<input type="checkbox" name="', $field['id'], '" id="', $field['id'], '"', $meta ? ' checked="checked"' : '', ' />';
break;
}
echo '</td><td>',
'</td></tr>';
}
echo '</table>';
}
add_action('save_post', 'mytheme_save_data');
// Save data from meta box
function mytheme_save_data($post_id) {
global $meta_box;
// verify nonce
if (!wp_verify_nonce($_POST['mytheme_meta_box_nonce'], basename(__FILE__))) {
return $post_id;
}
// check autosave
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
return $post_id;
}
// check permissions
if ('page' == $_POST['post_type']) {
if (!current_user_can('edit_page', $post_id)) {
return $post_id;
}
} elseif (!current_user_can('edit_post', $post_id)) {
return $post_id;
}
foreach ($meta_box['fields'] as $field) {
$old = get_post_meta($post_id, $field['id'], true);
$new = $_POST[$field['id']];
if ($new && $new != $old) {
update_post_meta($post_id, $field['id'], $new);
} elseif ('' == $new && $old) {
delete_post_meta($post_id, $field['id'], $old);
}
}
}
That is all working fine, the checkbox is added to the edit page where I want it, and it's state is saved correctly. The part I'm having issues with is actually getting the value of the checkbox and disabling wpautop based on this value.
Here is my (not working) code for disabling the filter based on the checkbox:
$is_checked = get_post_meta( $post->ID, 'my-meta-box', true );
if($is_checked){
remove_filter( 'the_content', 'wpautop' );
remove_filter( 'the_excerpt', 'wpautop' );
}
I'm really new to PHP and web programming in general so I'm having a really hard time trying to figure out how to debug my code. Is there an equivalent to a console I can print to in PHP? What is the general process to debug my code while working in a wordpress development environment?
Turns out I needed to wrap the check in a function & use an action call. Something about the order that the php is ran vs the value of the checkbox is recieved? If someone can explain why I had to do it this way that would be awesome.
Here is the working code:
add_action('template_redirect','my_function');
function my_function(){
$is_checked = get_post_meta( get_the_ID(), 'dbkt_checkbox', true );
if($is_checked) {
remove_filter( 'the_content', 'wpautop' );
remove_filter( 'the_excerpt', 'wpautop' );
}
}
I added a content rating system to my platform where the authors can select which audience their post is appropriate for. Currently, these options are available:
Unrated
G
PG
R
The code that I use to display the rating options on the post edit page is:
// Article Content Rating
add_action( 'add_meta_boxes', 'rating_select_box' );
function rating_select_box() {
add_meta_box(
'rating_select_box', // id, used as the html id att
__( 'Content Rating (optional)' ), // meta box title
'rating_select_cb', // callback function, spits out the content
'post', // post type or page. This adds to posts only
'side', // context, where on the screen
'low' // priority, where should this go in the context
);
}
function rating_select_cb( $post ) {
global $wpdb;
$value = get_post_meta($post->ID, 'rating', true);
echo '<div class="misc-pub-section misc-pub-section-last"><span id="timestamp"><label>Article Content Rating: </label>';
$ratings = array(
1 => ' G ',
2 => ' PG ',
3 => ' R ',
);
echo '<select name="rating">';
echo '<option value=""' . ((($value == '') || !isset($ratings[$value])) ? ' selected="selected"' : '') . '> Unrated </option>';
// output each rating as an option
foreach ($ratings as $id => $text) {
echo '<option value="' . $id . '"' . (($value == $id) ? ' selected="selected"' : '') . '">' . $text. '</option>';
}
echo '</select>';
echo '</span></div>';
}
add_action( 'save_post', 'save_metadata');
function save_metadata($postid)
{
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return false;
if ( !current_user_can( 'edit_page', $postid ) ) return false;
if( empty($postid) ) return false;
if ( is_null($_REQUEST["rating"]) ) {
delete_post_meta($postid, 'rating');
} else {
update_post_meta($postid, 'rating', $_REQUEST['rating']);
}
}
// END Article Content Rating
Now, the problem is, what code do I add to single.php to display their choice? So for instance, if the author selected PG, then I want to echo 'Content Rating: PG'; or if it was on default (unrated), I want to echo 'Content Rating: Unrated';. How is this possible? Ideally, a solution that is light on the server as my platform is heavily trafficked.
You already use the delete_post_meta() and update_post_meta() functions to remove and modify the custom values. Simply use the get_post_meta() function to obtain the value for the current post, and echo it out as you see fit.
If you're in The Loop, it would be something like:
$rating = get_post_meta(get_the_ID(), 'rating', TRUE);
Edit:
You already know your ID to rating mapping (I might make this mapping a global array, or some defines, or something similar). Simply use that to look up the string to output:
$ratings = array(
1 => 'G',
2 => 'PG',
3 => 'R'
);
if(array_key_exists($rating, $ratings)) {
echo "Content Rating: $ratings[$rating]";
} else {
echo "Content Rating: Unrated";
}
It looks as if you're saving the key to your custom field rather than its value. I suppose this would be alright if you planned on redeclaring your $ratings array, or (God forbid) use it globally. But still, it would probably be best if you saved the actual Rating rather than its ID number.
So change this line:
foreach ($ratings as $id => $text) {
echo '<option value="' . $id . '"' . (($value == $id) ? ' selected="selected"' : '') . '">' . $text. '</option>';
}
To this:
echo '<option value="Unrated"' . ((!$value || $value == 'Unrated' ? ' selected="selected"' : '') . '">Unrated</option>';
foreach ($ratings as $id => $text) {
echo '<option value="' .trim($text). '"' . (($value == trim($text)) ? ' selected="selected"' : '') . '">' . $text. '</option>';
}
After setting your value within the post, you can add this in single.php:
if(have_posts()) : while(have_posts()) : the_post();
echo 'Content Rating: '.get_post_meta($post->ID, 'rating', true);
endwhile;endif;
UPDATE:
As mentioned in my comments, I personally try to avoid globals and redeclaring things as much as possible. So if you would prefer to still reference your ratings by Key, you can get around globals and redeclaring your ratings array by adding a few simple functions:
functions.php
function gw_get_ratings_array()
{
$ratings = array(
1 => 'G',
2 => 'PG',
3 => 'R'
);
return $ratings;
}
function gw_get_rating($key=0)
{
$i = (int)$key;
$ratings = gw_get_ratings_array();
return isset($ratings[$i]) && $ratings[$i] ? $ratings[$i] : 'Unrated';
}
single.php
if(have_posts()) : while(have_posts()) : the_post();
$rating_id = get_post_meta($post->ID, 'rating', true);
echo 'Content Rating: '.gw_get_rating($rating_id);
endwhile;endif;
This way, if you ever need to add more Rating Types, you only need to alter the gw_get_ratings_array function rather than searching for each declaration of the array itself.
So I've been playing around with some custom metaboxes and following tutorials etc - I've got to the point where the top metabox field is saving correctly but the second one (width) doesn't save - is there anything obvious I'm doing wrong here? I've tried separating the second field's save in to a separate function to test but that also did not work.
add_action( 'add_meta_boxes', 'youtube_metaboxes' );
function youtube_metaboxes() {
add_meta_box('wpt_youtube', 'youtube URL', 'wpt_youtube', 'product', 'side', 'default');
}
function wpt_youtube() {
global $post;
echo '<input type="hidden" name="youtubemeta_noncename" id="youtubemeta_noncename" value="' .
wp_create_nonce( plugin_basename(__FILE__) ) . '" />';
$addyoutube = get_post_meta($post->ID, '_youtube', true);
echo '<input type="text" name="_youtube" value="' . $addyoutube . '" class="widefat" />';
$youtubeWidth = get_post_meta($post->ID, '_width', true);
echo 'Width: <br /><input type="text" name="_width" value="' . $youtubeWidth . '" class="widefat" />';
}
// Save the Metabox Data
function wpt_save_youtube_meta($post_id, $post) {
if ( !wp_verify_nonce( $_POST['youtubemeta_noncename'], plugin_basename(__FILE__) )) {
return $post->ID;
}
if ( !current_user_can( 'edit_post', $post->ID ))
return $post->ID;
$addyoutube_meta['_youtube'] = $_POST['_youtube'];
foreach ($addyoutube_meta as $key => $value) {
if( $post->post_type == 'revision' ) return;
$value = implode(',', (array)$value); // If $value is an array, make it a CSV (unlikely)
if(get_post_meta($post->ID, $key, FALSE)) {
update_post_meta($post->ID, $key, $value);
} else {
add_post_meta($post->ID, $key, $value);
}
if(!$value) delete_post_meta($post->ID, $key);
}
$addWidth_meta['_width'] = $_POST['_width'];
foreach ($addWidth_meta as $key => $value) {
if( $post->post_type == 'revision' ) return;
$value = implode(',', (array)$value); // If $value is an array, make it a CSV (unlikely)
if(get_post_meta($post->ID, $key, FALSE)) {
update_post_meta($post->ID, $key, $value);
} else {
add_post_meta($post->ID, $key, $value);
}
if(!$value) delete_post_meta($post->ID, $key);
}
}
add_action('save_post', 'wpt_save_youtube_meta', 1, 2); // save the custom fields
I had a look through this article:
http://wp.tutsplus.com/tutorials/reusable-custom-meta-boxes-part-1-intro-and-basic-fields/
Seems like a much better way of creating custom meta boxes.
I´m woring on a costum meta-box for wordpress. Trouble is wordpress only seems to retain/save some of the values I enter in the fields.. I can´t really find a pattern either.. so here's the code:
<?php
function add_products_metaboxes() {
add_meta_box('sra_product_info', 'Product Information', 'sra_products_info', 'product', 'side', 'default');
}
// The Productinfo Metabox
function sra_products_info() {
//get access to the post object
global $post;
// Noncename needed to verify where the data originated
echo '<input type="hidden" name="productmeta_noncename" id="productmeta_noncename" value="' .
wp_create_nonce( plugin_basename(__FILE__) ) . '" />';
// Get the data from the field if its already been entered
$name = get_post_meta($post->ID, '_name', true);
$price = get_post_meta($post->ID, '_price', true);
$includes = get_post_meta($post->ID, '_includes', true);
$supports = get_post_meta($post->ID, '_supports', true);
$version = get_post_meta($post->ID, '_version' , true);
$extrainfo = get_post_meta($post->ID, '_extrainfo', true);
// Echo out the form
echo '<form>';
echo '<label for="_name">Name</label>' . '<input type="text" name="_name" value="' . $name . '"/>';
echo '<label for="_price">Price</label>' . '<input type="text" name="_price" value="' . $price . '"/>';
echo '<label for="_includes">Includes</label> <textarea name="_includes" rows="4" cols="10">' . $includes . '</textarea>';
echo '<label for="_supports">Supports</label> <input type="text" name="_supports" value="' . $supports . '"/>';
echo '<label for="_version">Version</label>' . '<input type="text" name="_version" value="' . $version . '"/>';
echo '<label for="_extrainfo">Extras</label> <textarea name="_extrainfo" rows="4" cols="10">' . $extrainfo . '</textarea>';
echo '</form>';
}
// Save the Metabox Data
function sra_save_product_meta($post_id, $post) {
// verify this came from the our screen and with proper authorization,
// because save_post can be triggered at other times
if ( !wp_verify_nonce( $_POST['productmeta_noncename'], plugin_basename(__FILE__) )) {
return $post->ID;
}
// Is the user allowed to edit the post or page?
if ( !current_user_can( 'edit_post', $post->ID ))
return $post->ID;
// OK, we're authenticated: we need to find and save the data
// check if the field exists in the posts array - if it does, then put cintent in $product_meta.
// this code needs to be refactored!
if (isset($_POST['_name'])) {
$product_meta['_name'] = $_POST['_name'];
}
if (isset($_POST['_price'])) {
$product_meta['_price'] = $_POST['_price'];
}
if (isset($_POST['_includes'])) {
$product_meta['_includes'] = $_POST['_includes'];
}
if (isset($_POST['_supports'])) {
$product_meta['_supports'] = $_POST['_supports'];
}
if (isset($_POST['_version'])) {
$product_meta['_version'] = $_POST['_version'];
}
if (isset($_POST['_extrainfo'])) {
$product_meta['_extrainfo'] = $_POST['_extrainfo'];
}
// Add values of $prpduct_meta as custom fields
foreach ($product_meta as $key => $value) { // Cycle through the $product_meta array!
if( $post->post_type == 'revision' ) return; // Don't store custom data twice
$value = implode(',', (array)$value); // If $value is an array, make it a CSL (unlikely)
if(get_post_meta($post->ID, $key, FALSE)) { // If the custom field already has a value
update_post_meta($post->ID, $key, $value);
} else { // If the custom field doesn't have a value
add_post_meta($post->ID, $key, $value);
}
if(!$value) delete_post_meta($post->ID, $key); // Delete if blank
}
}
add_action('save_post', 'sra_save_product_meta', 1, 2); // save the custom fields
Do you see any obvious mistakes? I think I've become a bit blind to my own mistakes in this code..
In general, I would advise to use prefixes for your field names. Values like _name have too much chances getting in conflict with other values with the same name elsewhere. Use things like _product_name, etc. Can you try that? If your code works with pages, it should have an impact.
And why not adding the 4th parameter with 'true' to add_post_meta() and previous value for update_post_meta()? See WordPress codex about these functions: http://codex.wordpress.org/Function_Reference/add_post_meta. So it would go:
if(get_post_meta($post->ID, $key, FALSE)) { // If the custom field already has a value
update_post_meta($post->ID, $key, $value, /***OLDVALUE***/ ); // See http://codex.wordpress.org/Function_Reference/update_post_meta for old value
} else { // If the custom field doesn't have a value
add_post_meta($post->ID, $key, $value, true);
}
I think it is clear you have a conflict with a metakey with the same name. Not in pages, but in posts. So try to use this 4th parameter to ensure you are referencing a unique key (and my advice, still, use clear prefixes to differenciate from anything else, be it plugins, core, etc.)