Wordpress - creating meta boxes and saving - wordpress

I'm trying to create a metabox, it should be nice and easy but I'm getting it wrong. It pertains to a tour custom post, and adding the price in for that tour:
So initially I create this custom post type (this works):
register_post_type( 'tours',
array(
'labels' => array(
'name' => __( 'Tours' ),
'singular_name' => __( 'Tour' ),
'add_new' => 'Add New Tour Instance',
'add_new_item' => 'Add New Tour Instance',
'edit' => 'Edit',
'edit_item' => 'Edit Tour Instance',
'new_item' => 'New Tour Instance',
'view' => 'View',
'view_item' => 'View Tour Instance',
'search_items' => 'Search Tour Instances',
'not_found' => 'No Tour Instances found',
'not_found_in_trash' => 'No Tour Instances found in Rubbish',
'parent' => 'Parent Tour Instance'
),
'public' => true,
'supports' => array( 'title', 'editor', 'thumbnail'),
'taxonomies' => array( '' ),
//'menu_icon' => plugins_url( 'images/image.png', __FILE__ ),
'capability_type' => 'post',
'rewrite' => array("slug" => "tours") // Permalinks format
)
);
Then I create the box itself (this also works):
add_action( 'admin_init', 'tour_meta' );
function tour_meta() {
add_meta_box(
'tours_meta_box',
'Tour Price',
'display_tours_price_meta_box',
'tours',
'side',
'high'
);
}
Now, within the overall function, I then try to get the detail and save it:
function display_tours_price_meta_box() {
global $post;
// Noncename needed to verify where the data originated
echo '<input type="hidden" name="tourmeta_noncename" id="tourmeta_noncename" value="' .
wp_create_nonce( plugin_basename(__FILE__) ) . '" />';
// Get the price data if its already been entered
$price = get_post_meta($post->ID, '_price', true);
echo 'Add the total cost for this tour here, do not include monetary characters like £ or $';
echo '<input type="text" name="_price" ' . $price . '" class="widefat" />';
}
function save_tours_meta($tour_id, $tour) {
if ( !wp_verify_nonce( $_POST['tourmeta_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;
$tour_meta['_price'] = $_POST['_price'];
// Add values of $tour_meta as custom fields
foreach ($tour_meta as $key => $value) {
if( $post->post_type == 'revision' ) return;
$value = implode(',', (array)$value);
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', 'save_tours_meta', 1, 2);
The actual box appears, and the information is echo'd. However it does not save. I haven't the foggiest why. It must pertain to my last function, but I don't understand what is going wrong.
Thanks

You should better simplify your saving process like this :
function save_tours_meta($post_id) {
if ( !wp_verify_nonce( $_POST['tourmeta_noncename'], plugin_basename(__FILE__) )) {
// You don't need to return anything
return;
}
// Is the user allowed to edit the post or page?
if ( !current_user_can( 'edit_post', $post_id ) && !isset($_POST['_price']))
return;
// If you just have 1 value
update_post_meta($post_id, '_price', $_POST['_price']);
}
Just notice that the update_post_meta function will update the post meta or create it if it doesn't exist so don't bother usind add_post_meta.

I think it's your arguments. You declare the function as
function save_tours_meta($tour_id, $tour) {
but you're using (eg) $post->ID. $post in this case isn't the global variable, but the function argument. Try using $tour->ID or just $tour_id instead.
A couple of other (unrelated) things:
You can call update_post_meta() and it'll add the key if it doesn't exist, so you can remove your if statement (just reducing the lines of code).
Your "revision" check should return the post ID (and can be moved outside your loop)

Related

Can't view new post type in wordpress

I've created a custom post type using the example shown here. In my case I'm creating a Career post type for job ads.
Everything seems fine. My Careers section appears in the dashboard and I can create job ads, which have /careers/job-title as their permalink. Exactly as I would like. But I can't view them. If I click on view or go to the url directly I get a 404.
This is a new local installation using xampp and bitnami wordpress. It's basically a default installation, I've added a few plugins previously but for debugging purposes I've disabled all of them.
Any ideas?
function create_posttype() {
$args = array(
'labels' => array(
'name' => __('Careers'),
'singular_name' => __('Careers'),
'all_items' => __('All Job Postings'),
'add_new_item' => __('Add New Job Posting'),
'edit_item' => __('Edit Job Posting'),
'view_item' => __('View Job Posting')
),
'public' => true,
'has_archive' => true,
'rewrite' => array('slug' => 'careers'),
'show_ui' => true,
'show_in_menu' => true,
'show_in_nav_menus' => true,
'capability_type' => 'post',
'supports' => array('title', 'editor', 'thumbnail'),
'exclude_from_search' => false,
'menu_position' => 6,
'has_archive' => true,
'menu_icon' => 'dashicons-format-status'
);
register_post_type('careers', $args);
}
add_action( 'init', 'create_posttype');
function my_add_meta_box(){
add_meta_box( 'job-details', 'Job Details', 'my_meta_box_cb', 'Careers', 'normal', 'default');
}
function my_meta_box_cb($post){
$values = get_post_custom( $post->ID );
$salary = isset( $values['salary'] ) ? esc_attr( $values['salary'][0] ) : "";
$salary_unit = isset( $values['salary_unit'] ) ? esc_attr( $values['salary_unit'][0] ) : "hr";
wp_nonce_field( 'job_details_nonce_action', 'job_details_nonce' );
$html = '';
$html .= '<label>Salary</label>';
$html .= '<input type="number" name="salary" id="salary" style="margin-top:15px; margin-left:9px; margin-bottom:10px;" value="'. $salary .'" />';
$html .= '<label> / </label>';
$html .= '<input type="text" list=salary_units name="salary_unit" id="salary_unit" style="margin-left:9px; margin-top:15px;" value="'. $salary_unit .'" />';
$html .= '<datalist id=salary_units><option>hr<option>day<option>month<option>annum</datalist>';
echo $html;
}
function my_save_meta_box($post_id){
// Bail if we're doing an auto save
if( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return;
// if our nonce isn't there, or we can't verify it, bail
if( !isset( $_POST['job_details_nonce'] ) || !wp_verify_nonce( $_POST['job_details_nonce'], 'job_details_nonce_action' ) ) return;
// if our current user can't edit this post, bail
if( !current_user_can( 'edit_post' ) ) return;
if(isset( $_POST['salary'] ) )
update_post_meta( $post_id, 'salary', $_POST['salary']);
if(isset( $_POST['salary_unit'] ) )
update_post_meta( $post_id, 'salary_unit', $_POST['salary_unit']);
}
add_action( 'add_meta_boxes', 'my_add_meta_box' );
add_action( 'save_post', 'my_save_meta_box' );
When you register a new post type, you need to flush your rewrite rules.
To do that go to Settings -> Permalinks and press save.
If you're building something you plan to distribute you'll want to flush rewrite rules automatically. For further information see: https://codex.wordpress.org/Function_Reference/register_post_type#Flushing_Rewrite_on_Activation

Wordpress add_action undefined offset 0 in plugin.php line 925 and 943

I have a public function to attach taxonomies to custom post types. I am getting this error code in Wordpress when debugging is set to true:
Notice: Undefined offset: 0 in C:\xampp\htdocs\yanjep-dev\wp-includes\plugin.php on line 925
Notice: Undefined offset: 0 in C:\xampp\htdocs\yanjep-dev\wp-includes\plugin.php on line 943
This repeats 9 times each.
I have isolated the problem to an add_action function here:
add_action( 'init',
call_user_func_array( 'register_taxonomy', array( $taxonomy_name, $post_type_name, $args ) )
);
The entire function is here:
public function add_taxonomy( $name, $args = array(), $labels = array() )
{
if( ! empty( $name ) )
{
// We need to know the post type name, so the new taxonomy can be attached to it.
$post_type_name = $this->post_type_name;
// Taxonomy properties
$taxonomy_name = strtolower( str_replace( ' ', '_', $name ) );
$taxonomy_labels = $labels;
$taxonomy_args = $args;
if( ! taxonomy_exists( $taxonomy_name ) )
{
//Capitilize the words and make it plural
$name = ucwords( str_replace( '_', ' ', $name ) );
$plural = $name . 's';
// Default labels, overwrite them with the given labels.
$labels = array_merge(
// Default
array(
'name' => _x( $plural, 'taxonomy general name' ),
'singular_name' => _x( $name, 'taxonomy singular name' ),
'search_items' => __( 'Search ' . $plural ),
'all_items' => __( 'All ' . $plural ),
'parent_item' => __( 'Parent ' . $name ),
'parent_item_colon' => __( 'Parent ' . $name . ':' ),
'edit_item' => __( 'Edit ' . $name ),
'update_item' => __( 'Update ' . $name ),
'add_new_item' => __( 'Add New ' . $name ),
'new_item_name' => __( 'New ' . $name . ' Name' ),
'menu_name' => __( $name ),
),
// Given labels
$taxonomy_labels
);
// Default arguments, overwitten with the given arguments
$args = array_merge(
// Default
array(
'label' => $plural,
'labels' => $labels,
'public' => true,
'show_ui' => true,
'show_in_nav_menus' => true,
'_builtin' => false,
),
// Given
$taxonomy_args
);
// Add the taxonomy to the post type
add_action( 'init',
call_user_func_array( 'register_taxonomy', array( $taxonomy_name, $post_type_name, $args ) )
);
}
else
{
add_action( 'init', array($this, 'add_taxonomy_to_post_type'));
}
}
}
I am working locally using Xampp. If I comment out the action, the notices disappear. I know it has something to to with the number of arguments, but I can't solve it.
Any help is appreciated.
As you know, add_action requires two arguments: the filter (register_taxonomy, and the function name to call.
AFAIK, add_action needs to reference an actual function, and you cannot pass in a call_user_func_array call. If you trace the code in WP, you'll see that add_action in turn calls add_filter, which in turn calls _wp_filter_build_unique_id, which is where your error is being thrown. If you investigate that code, you'll see it's expecting either a string - as in the function name to call (such as register_my_taxonomy), or else an array for class methods (following the PHP standard way). Examples:
add_action('init', 'register_my_taxonomy'); // Call a standard function
add_action('init', array($this, 'register_my_taxonomy'); // call a public class method
add_action('init', array(__CLASS__, 'register_my_taxonomy'); // call a public static method
So, since it appears you are working in a class, in your add_action('init'...) call, I'd recommend changing it to reference a class function:
add_action( 'init',
array($this, 'register_my_taxonomy')
);
And in your class, create the function register_my_taxonomy which loops over your taxonomies and calls register_taxonomy directly.

Sell in only some cities woocommerce

In my account page,
I want to use a similar code as below to sell in a specific "cities" or "postcodes", the below code is used to sell in a specific "states":
/**
* Sell only in Alger & Zeralda
*/
function wc_sell_only_states( $states ) {
$states['DZ'] = array(
'ALG' => __( 'Alger', 'woocommerce' ),
'ZLD' => __( 'Zeralda', 'woocommerce' ),
);
return $states;
}
add_filter( 'woocommerce_states', 'wc_sell_only_states' );
What shall I use or modify?
I tried this, but it displays "Error code 500":
// define the woocommerce_countries_base_city callback
function filter_woocommerce_countries_base_city( $var ) {
// make filter magic happen here...
$var['DZ'] = array(
'ALG' => __( 'Alger', 'woocommerce' ),
'ZLD' => __( 'Zeralda', 'woocommerce' ),
);
return $var;
};
// add the filter
add_filter( 'woocommerce_countries_base_city', 'filter_woocommerce_countries_base_city', 10, 1 );
Thank you in advanced!
Try This it worked for me!!
add_filter( 'woocommerce_form_field_args', 'custom_form_field_args', 10, 3 );
function custom_form_field_args( $args, $key, $value ) {
if ( $args['id'] == 'billing_city' ) {
$args = array(
'label' => __( 'Town / City', 'woocommerce' ),
'required' => TRUE,
'clear' => TRUE,
'type' => 'select',
'options' => array(
'' => ('Select City' ),
'Bangalore' => ('Bangalore' ),
'Mysore' => ('Mysore' )
),
'class' => array( 'update_totals_on_change' )
);
} // elseif … and go on
return $args;
};
There is a simpler solution to this. The approach also depends on the some assumption which are listed below:
Assumption : If there is only one City which you want the City field to be set to then you can use jQuery. Using jQuery you will be setting the value of the field and make the fields disabled to avoid change in City field value.
A rough example will be :
jQuery('#billing_city').val('USA').attr('disabled','disabled');
You just need to add this line such that it is execute on Checkout page.

wordpress 3.5 custom post type, custom meta box, load scripts conditionally

I have this little strange problem ;). I would like to load custom scripts (css, js) only when an admin's custom post type editor is loaded (adding new custom post type, editing custo mpost type).
Custom post types are registered this way:
add_action( 'init', 'cs_product_register_post_types' );
function cs_product_register_post_types() {
$product_args = array(
'public' => true,
'rewrite' => array(
'slug' => 'products',
'with_front' => false,
'pages' => false
),
'supports' => array(
'title',
'editor',
'page-attributes'
),
'labels' => array(
'name' => 'Produkty',
'singular_name' => 'Produkt',
'add_new' => 'Dodaj nowy produkt',
'add_new_item' => 'Dodaj nowy produkt',
'edit_item' => 'Edytuj produkt',
'new_item' => 'Nowy produkt',
'view_item' => 'Wyswietl produkt',
'search_items' => 'Wyszukaj produkt',
'not_found' => 'Produktu nie znaleziono',
'not_found_in_trash' => 'Brak usuniętych produktów'
),
'menu_position' => 3,
);
register_post_type( 'products', $product_args );
}
For those there is a function registering custom metabox:
add_action( 'add_meta_boxes', 'cs_products_mb_create' );
function cs_products_mb_create() {
//create a custom meta box
add_meta_box( 'products-info', 'Ustawienia Produktu', 'cs_products_mb_function', 'products', 'normal', 'high' );
}
That works only for registered custom post type (products).
Now the only thing is to load custom js. It can be done this way:
add_action('admin_print_styles-post.php', 'cs_products_admin_styles');
add_action('admin_print_styles-post-new.php', 'cs_products_admin_styles');
function cs_products_admin_styles() {
wp_enqueue_style( 'thickbox' );
wp_enqueue_style ('theme', get_bloginfo('template_url') . '/css/admin.css', '', '1.0');
}
But it works for all posts, and its not a best way to do it ;).
Thanks for any ideas.
edit
After digging, and digging, and digging... One of simplest ways to do it:
//load scripts only when on products custom post type edit page
if ( ( isset($_GET['post_type']) && $_GET['post_type'] == 'products' ) || ( isset($post_type) && $post_type == 'products' ) ) {
add_action('admin_enqueue_scripts', 'cs_admin_customposttype_scripts');
}
function cs_admin_customposttype_scripts(){
wp_enqueue_style ('theme', get_bloginfo('template_url') . '/css/admin.css', '');
wp_enqueue_script( 'cs-image-upload', get_bloginfo('template_url').'/js/admin.js', array( 'jquery') );
}
But the problem with this solution is, that it works only when new custom post is being created. When editing, $_GET['post_type'] or $post_type are not available.
After searching a little bit more...
//load scripts only when on products custom post type edit page
if ( ( isset($_GET['post_type']) && $_GET['post_type'] == 'products' ) || ( isset($post_type) && $post_type == 'products' ) || ( isset($_GET['post']) && get_post_type($_GET['post']) == 'products' ) ) {
add_action('admin_enqueue_scripts', 'cs_admin_customposttype_scripts');
}
function cs_admin_customposttype_scripts(){
wp_enqueue_style ('theme', get_bloginfo('template_url') . '/css/admin.css', '');
wp_enqueue_script( 'cs-image-upload', get_bloginfo('template_url').'/js/admin.js', array( 'jquery') );
}
Aditional or, and use of only one known variable - postID that is sent with $_GET and using get_post_type function did the job.

Showing custom taxonomy column in custom posts type listings

I have created a custom post type named banners. Thereby I register a new taxonomy called location that specifies on which page the banner is to be shown. Everything is great however when I click on the custom posts type 'Banner' in the admin window I see all the banners created however the table does not have a column for the taxonomy 'Location'.
In other words I want to be able to see what location the banner is in, in the banners listing.
For those interested, the register_taxonomy register_taxonomy function, as of WordPress 3.5, now offers an argument for show_admin_column (false by default). Set to true, it automatically displays the taxonomy column in the admin.
You can use the manage_post-type_custom_column and manage_edit_post-type_columns filters to add your taxonomy column to the post type listing.
add_action( 'admin_init', 'my_admin_init' );
function my_admin_init() {
add_filter( 'manage_edit-banner_columns', 'my_new_custom_post_column');
add_action( 'manage_banner_custom_column', 'location_tax_column_info', 10, 2);
}
function my_new_custom_post_column( $column ) {
$column['location'] = 'Location';
return $column;
}
function location_tax_column_info( $column_name, $post_id ) {
$taxonomy = $column_name;
$post_type = get_post_type($post_id);
$terms = get_the_terms($post_id, $taxonomy);
if (!empty($terms) ) {
foreach ( $terms as $term )
$post_terms[] ="<a href='edit.php?post_type={$post_type}&{$taxonomy}={$term->slug}'> " .esc_html(sanitize_term_field('name', $term->name, $term->term_id, $taxonomy, 'edit')) . "</a>";
echo join('', $post_terms );
}
else echo '<i>No Location Set. </i>';
}
//what version of wordpress you are using
//since wp 3.5 you can pass parameter show_admin_column=>true
// hook into the init action and call create_book_taxonomies when it fires
add_action( 'init', 'create_book_taxonomies', 0 );
// create two taxonomies, genres and writers for the post type "book"
function create_book_taxonomies() {
// Add new taxonomy, make it hierarchical (like categories)
$labels = array(
'name' => _x( 'Genres', 'taxonomy general name' ),
'singular_name' => _x( 'Genre', 'taxonomy singular name' ),
'search_items' => __( 'Search Genres' ),
'all_items' => __( 'All Genres' ),
'parent_item' => __( 'Parent Genre' ),
'parent_item_colon' => __( 'Parent Genre:' ),
'edit_item' => __( 'Edit Genre' ),
'update_item' => __( 'Update Genre' ),
'add_new_item' => __( 'Add New Genre' ),
'new_item_name' => __( 'New Genre Name' ),
'menu_name' => __( 'Genre' ),
);
$args = array(
'hierarchical' => true,
'labels' => $labels,
'show_ui' => true,
'show_admin_column' => true,
'query_var' => true,
'rewrite' => array( 'slug' => 'genre' ),
);
register_taxonomy( 'genre', array( 'book' ), $args );
}
In addition to Jonathan Wold answer, you can add the ability to filter by your custom taxonomy like this:
add_action('restrict_manage_posts', 'filter_post_type_backend_by_taxonomies', 99, 2);
function filter_post_type_backend_by_taxonomies($post_type, $which) {
if( 'your_post_type' !== $post_type) {
return;
}
$taxonomies = array( 'your_custom_taxonomy' );
foreach( $taxonomies as $taxonomy_slug ) {
$taxonomy_obj = get_taxonomy( $taxonomy_slug );
$taxonomy_name = $taxonomy_obj->labels->name;
$terms = get_terms($taxonomy_slug);
echo "<select name='{$taxonomy_slug}' id='{$taxonomy_slug}' class='postform'>";
echo '<option value="">' . sprintf( esc_html__( 'Show all %s', 'domain-name' ), $taxonomy_name) . '</option>';
foreach ( $terms as $term ) {
printf(
'<option value="%1$s" %2$s>%3$s (%4$s)</option>',
$term->slug,
( ( isset( $_GET[$taxonomy_slug] ) && ( $_GET[$taxonomy_slug] == $term->slug ) ) ? ' selected="selected"' : '' ),
$term->name,
$term->count
);
}
echo '</select>';
}
}

Resources