I have written a plugin to create a new custom post type named gardener
, and have added a custom taxonomy called region
, in addition to a meta box with several fields called _gardener_address
. The last is where the problem lies.
You see, I used the code shared at https://gist.github.com/cferdinandi/46aca88d6d142791a32a9d30017f1cd8 to create my meta box, and though everything works fine on the admin side, I am encountering a big problem when I try to actually display the meta data on my post.
The code to create the custom post type, taxonomy and meta box is as follows:
if ( ! function_exists('gardeners_post_type') ) {
if ( ! function_exists( 'region_taxonomy' ) ) {
// Register Custom Taxonomy
function region_taxonomy() {
$labels = array(
'name' => _x( 'Regio\'s', 'Taxonomy General Name', 'text_domain' ),
'singular_name' => _x( 'Regio', 'Taxonomy Singular Name', 'text_domain' ),
'menu_name' => __( 'Regio\'s', 'text_domain' ),
'all_items' => __( 'Alle Regio\'s', 'text_domain' ),
'parent_item' => __( 'Provincie', 'text_domain' ),
'parent_item_colon' => __( 'Provincie:', 'text_domain' ),
'new_item_name' => __( 'Nieuwe regio', 'text_domain' ),
'add_new_item' => __( 'Nieuwe regio', 'text_domain' ),
'edit_item' => __( 'Wijzig regio', 'text_domain' ),
'update_item' => __( 'Update regio', 'text_domain' ),
'view_item' => __( 'Bekijk regio', 'text_domain' ),
'separate_items_with_commas' => __( 'Afzonderlijke regio\'s scheiden met komma\'s', 'text_domain' ),
'add_or_remove_items' => __( 'Toevoegen of verwijderen regio\'s', 'text_domain' ),
'choose_from_most_used' => __( 'Kies uit de meest gebruikte regio\'s', 'text_domain' ),
'popular_items' => __( 'Populaire regio\'s', 'text_domain' ),
'search_items' => __( 'Zoek regio', 'text_domain' ),
'not_found' => __( 'Regio niet gevonden', 'text_domain' ),
'no_terms' => __( 'Geen regio beschikbaar', 'text_domain' ),
'items_list' => __( 'Regio-overzicht', 'text_domain' ),
'items_list_navigation' => __( 'Regio-overzicht navigatie', 'text_domain' ),
);
$args = array(
'labels' => $labels,
'hierarchical' => false,
'public' => true,
'show_ui' => true,
'show_admin_column' => true,
'show_in_nav_menus' => true,
'show_tagcloud' => true,
'show_in_rest' => true,
);
register_taxonomy( 'region', array( 'gardener' ), $args );
}
add_action( 'init', 'region_taxonomy', 0 );
}
// Register Custom Post Type
function gardeners_post_type() {
$labels = array(
'name' => _x( 'Hoveniers', 'Post Type General Name', 'text_domain' ),
'singular_name' => _x( 'Hovenier', 'Post Type Singular Name', 'text_domain' ),
'menu_name' => __( 'Hoveniers', 'text_domain' ),
'name_admin_bar' => __( 'Hovenier', 'text_domain' ),
'archives' => __( 'Hovenieroverzicht', 'text_domain' ),
'attributes' => __( 'Hovenier eigenschappen', 'text_domain' ),
'parent_item_colon' => __( 'Hoofdhovenier:', 'text_domain' ),
'all_items' => __( 'Alle hoveniers', 'text_domain' ),
'add_new_item' => __( 'Nieuwe hovenier', 'text_domain' ),
'add_new' => __( 'Nieuwe hovenier', 'text_domain' ),
'new_item' => __( 'Nieuwe hovenier', 'text_domain' ),
'edit_item' => __( 'Wijzig hovenier', 'text_domain' ),
'update_item' => __( 'Update hovenier', 'text_domain' ),
'view_item' => __( 'Bekijk hovenier', 'text_domain' ),
'view_items' => __( 'Bekijk hoveniers', 'text_domain' ),
'search_items' => __( 'Zoek hovenier', 'text_domain' ),
'not_found' => __( 'Hovenier niet gevonden', 'text_domain' ),
'not_found_in_trash' => __( 'Hovenier niet gevonden in Prullenbak', 'text_domain' ),
'featured_image' => __( 'Uitgelichte afbeelding', 'text_domain' ),
'set_featured_image' => __( 'Stel uitgelichte afbeelding in', 'text_domain' ),
'remove_featured_image' => __( 'Verwijder uitgelichte afbeelding', 'text_domain' ),
'use_featured_image' => __( 'Gebruik als uitgelichte afbeelding', 'text_domain' ),
'insert_into_item' => __( 'Invoegen bij hovenier', 'text_domain' ),
'uploaded_to_this_item' => __( 'Geüploadet naar deze hovenier', 'text_domain' ),
'items_list' => __( 'Hovenieroverzicht', 'text_domain' ),
'items_list_navigation' => __( 'Hovenieroverzichtsmenu', 'text_domain' ),
'filter_items_list' => __( 'Filter hoveniers', 'text_domain' ),
);
$rewrite = array(
'slug' => 'hovenier',
'with_front' => true,
'pages' => true,
'feeds' => false,
);
$args = array(
'label' => __( 'Hovenier', 'text_domain' ),
'description' => __( 'Overzicht van hoveniers', 'text_domain' ),
'labels' => $labels,
'supports' => array( 'title', 'editor', 'thumbnail', 'revisions' ),
'taxonomies' => array( 'region' ),
'hierarchical' => false,
'public' => true,
'show_ui' => true,
'show_in_menu' => true,
'menu_position' => 70,
'menu_icon' => 'dashicons-groups',
'show_in_admin_bar' => true,
'show_in_nav_menus' => true,
'can_export' => true,
'has_archive' => true,
'exclude_from_search' => false,
'publicly_queryable' => true,
'rewrite' => $rewrite,
'capability_type' => 'page',
'show_in_rest' => true,
);
register_post_type( 'gardener', $args );
}
add_action( 'init', 'gardeners_post_type', 0 );
// CUSTOM META BOX ---------------------------------------------
//
// Create Metabox
//
/**
* Create the metabox
* @link https://developer.wordpress.org/reference/functions/add_meta_box/
https://gist.github.com/cferdinandi/46aca88d6d142791a32a9d30017f1cd8
*/
function _gardener_address_create_metabox() {
// Can only be used on a single post type (ie. page or post or a custom post type).
// Must be repeated for each post type you want the metabox to appear on.
add_meta_box(
'_gardener_address_metabox', // Metabox ID
'Contactinformatie', // Title to display
'_gardener_address_render_metabox', // Function to call that contains the metabox content
'gardener', // Post type to display metabox on
'normal', // Where to put it (normal = main colum, side = sidebar, etc.)
'high' // Priority relative to other metaboxes
);
}
add_action( 'add_meta_boxes', '_gardener_address_create_metabox' );
/**
* Create the metabox default values
* This allows us to save multiple values in an array, reducing the size of our database.
* Setting defaults helps avoid "array key doesn't exit" issues.
* @todo
*/
function _gardener_address_metabox_defaults() {
return array(
'street' => '',
'zip' => '',
'city' => '',
'tel1' => '',
'tel2' => '',
'email' => '',
'url' => '',
'fb' => '',
'twitter' => '',
'linkedin' => '',
'insta' => '',
'pint' => '',
);
}
/**
* Render the metabox markup
* This is the function called in `_gardener_address_create_metabox()`
*/
function _gardener_address_render_metabox() {
// Variables
global $post; // Get the current post data
$saved = get_post_meta( $post->ID, '_gardener_address', true ); // Get the saved values
$defaults = _gardener_address_metabox_defaults(); // Get the default values
$details = wp_parse_args( $saved, $defaults ); // Merge the two in case any fields don't exist in the saved data
?>
<style>
#_gardener_address_metabox .inside {
display:flex;
align-items:flex-start;
justify-content: space-between;
}
.gardener_address_fieldset div {
display:flex;
align-items: center;
justify-content: space-between;
width:100%;
}
.gardener_address_fieldset legend {
font-weight:600;
margin-bottom:1rem;
}
.gardener_address_fieldset label {
margin-right:1rem;
}
.gardener_address_fieldset input {
}
</style>
<fieldset class="gardener_address_fieldset">
<legend>Adresgegevens</legend>
<div>
<label for="_gardener_address_custom_metabox_street">
<?php
// This runs the text through a translation and echoes it (for internationalization)
_e( 'Straat', '_gardener_address' );
?>
</label>
<?php
// It's important that the `name` is an array. This let's us
// easily loop through all fields later when we go to save
// our submitted data.
//
// The `esc_attr()` function here escapes the data for
// HTML attribute use to avoid unexpected issues
?>
<input type="text" name="_gardener_address_custom_metabox[street]" id="_gardener_address_custom_metabox_street" value="<?php echo esc_attr( $details['street'] ); ?>">
</div>
<div>
<label for="_gardener_address_custom_metabox_zip">
<?php
_e( 'Postcode', '_gardener_address' );
?>
</label>
<input type="text" name="_gardener_address_custom_metabox[zip]" id="_gardener_address_custom_metabox_zip" value="<?php echo esc_attr( $details['zip'] ); ?>">
</div>
<div>
<label for="_gardener_address_custom_metabox_city">
<?php
_e( 'Plaats', '_gardener_address' );
?>
</label>
<input type="text" name="_gardener_address_custom_metabox[city]" id="_gardener_address_custom_metabox_city" value="<?php echo esc_attr( $details['city'] ); ?>">
</div>
</fieldset>
<fieldset class="gardener_address_fieldset">
<legend>Telefoonnummers</legend>
<div>
<label for="_gardener_address_custom_metabox_tel1">
<?php _e( 'Telefoon', '_gardener_address' ); ?>
</label>
<input type="tel" name="_gardener_address_custom_metabox[tel1]" id="_gardener_address_custom_metabox_tel1" value="<?php echo esc_attr( $details['tel1'] ); ?>">
</div>
<div>
<label for="_gardener_address_custom_metabox_tel2">
<?php _e( 'Telefoon', '_gardener_address' ); ?>
</label>
<input type="tel" name="_gardener_address_custom_metabox[tel2]" id="_gardener_address_custom_metabox_tel2" value="<?php echo esc_attr( $details['tel2'] ); ?>">
</div>
</fieldset>
<fieldset class="gardener_address_fieldset">
<legend>Web</legend>
<div>
<label for="_gardener_address_custom_metabox_email">
<?php _e( 'E-mail', '_gardener_address' ); ?>
</label>
<input type="email" name="_gardener_address_custom_metabox[email]" id="_gardener_address_custom_metabox_email" value="<?php echo esc_attr( $details['email'] ); ?>">
</div>
<div>
<label for="_gardener_address_custom_metabox_url">
<?php _e( 'Website', '_gardener_address' ); ?>
</label>
<input type="url" name="_gardener_address_custom_metabox[url]" id="_gardener_address_custom_metabox_url" value="<?php echo esc_attr( $details['url'] ); ?>">
</div>
</fieldset>
<fieldset class="gardener_address_fieldset">
<legend>Sociale media</legend>
<div>
<label for="_gardener_address_custom_metabox_fb">
<?php _e( 'Facebook', '_gardener_address' ); ?>
</label>
<input type="url" name="_gardener_address_custom_metabox[fb]" id="_gardener_address_custom_metabox_fb" value="<?php echo esc_attr( $details['fb'] ); ?>">
</div>
<div>
<label for="_gardener_address_custom_metabox_twitter">
<?php _e( 'Twitter', '_gardener_address' ); ?>
</label>
<input type="url" name="_gardener_address_custom_metabox[twitter]" id="_gardener_address_custom_metabox_twitter" value="<?php echo esc_attr( $details['twitter'] ); ?>">
</div>
<div>
<label for="_gardener_address_custom_metabox_linkedin">
<?php _e( 'LinkedIn', '_gardener_address' ); ?>
</label>
<input type="url" name="_gardener_address_custom_metabox[linkedin]" id="_gardener_address_custom_metabox_linkedin" value="<?php echo esc_attr( $details['linkedin'] ); ?>">
</div>
<div>
<label for="_gardener_address_custom_metabox_insta">
<?php _e( 'Instagram', '_gardener_address' ); ?>
</label>
<input type="url" name="_gardener_address_custom_metabox[insta]" id="_gardener_address_custom_metabox_insta" value="<?php echo esc_attr( $details['insta'] ); ?>">
</div>
<div>
<label for="_gardener_address_custom_metabox_pint">
<?php _e( 'Pinterest', '_gardener_address' ); ?>
</label>
<input type="url" name="_gardener_address_custom_metabox[pint]" id="_gardener_address_custom_metabox_pint" value="<?php echo esc_attr( $details['pint'] ); ?>">
</div>
</fieldset>
<?php
// Security field
// This validates that submission came from the
// actual dashboard and not the front end or
// a remote server.
wp_nonce_field( '_gardener_address_form_metabox_nonce', '_gardener_address_form_metabox_process' );
}
//
// Save our data
//
/**
* Save the metabox
* @param Number $post_id The post ID
* @param Array $post The post data
*/
function _gardener_address_save_metabox( $post_id, $post ) {
// Verify that our security field exists. If not, bail.
if ( !isset( $_POST['_gardener_address_form_metabox_process'] ) ) return;
// Verify data came from edit/dashboard screen
if ( !wp_verify_nonce( $_POST['_gardener_address_form_metabox_process'], '_gardener_address_form_metabox_nonce' ) ) {
return $post->ID;
}
// Verify user has permission to edit post
if ( !current_user_can( 'edit_post', $post->ID )) {
return $post->ID;
}
// Check that our custom fields are being passed along
// This is the `name` value array. We can grab all
// of the fields and their values at once.
if ( !isset( $_POST['_gardener_address_custom_metabox'] ) ) {
return $post->ID;
}
/**
* Sanitize all data
* This keeps malicious code out of our database.
*/
// Set up an empty array
$sanitized = array();
// Loop through each of our fields
foreach ( $_POST['_gardener_address_custom_metabox'] as $key => $detail ) {
// Sanitize the data and push it to our new array
// `wp_filter_post_kses` strips our dangerous server values
// and allows through anything you can include a post.
$sanitized[$key] = wp_filter_post_kses( $detail );
}
// Save our submissions to the database
update_post_meta( $post->ID, '_gardener_address', $sanitized );
}
add_action( 'save_post', '_gardener_address_save_metabox', 1, 2 );
//
// Save a copy to our revision history
// This is optional, and potentially undesireable for certain data types.
// Restoring a a post to an old version will also update the metabox.
/**
* Save events data to revisions
* @param Number $post_id The post ID
*/
function _gardener_address_save_revisions( $post_id ) {
// Check if it's a revision
$parent_id = wp_is_post_revision( $post_id );
// If is revision
if ( $parent_id ) {
// Get the saved data
$parent = get_post( $parent_id );
$details = get_post_meta( $parent->ID, '_gardener_address', true );
// If data exists and is an array, add to revision
if ( !empty( $details ) && is_array( $details ) ) {
// Get the defaults
$defaults = _gardener_address_metabox_defaults();
// For each default item
foreach ( $defaults as $key => $value ) {
// If there's a saved value for the field, save it to the version history
if ( array_key_exists( $key, $details ) ) {
add_metadata( 'post', $post_id, '_gardener_address_' . $key, $details[$key] );
}
}
}
}
}
add_action( 'save_post', '_gardener_address_save_revisions' );
/**
* Restore events data with post revisions
* @param Number $post_id The post ID
* @param Number $revision_id The revision ID
*/
function _gardener_address_restore_revisions( $post_id, $revision_id ) {
// Variables
$post = get_post( $post_id ); // The post
$revision = get_post( $revision_id ); // The revision
$defaults = _gardener_address_metabox_defaults(); // The default values
$details = array(); // An empty array for our new metadata values
// Update content
// For each field
foreach ( $defaults as $key => $value ) {
// Get the revision history version
$detail_revision = get_metadata( 'post', $revision->ID, '_gardener_address_' . $key, true );
// If a historic version exists, add it to our new data
if ( isset( $detail_revision ) ) {
$details[$key] = $detail_revision;
}
}
// Replace our saved data with the old version
update_post_meta( $post_id, '_gardener_address', $details );
}
add_action( 'wp_restore_post_revision', '_gardener_address_restore_revisions', 10, 2 );
/**
* Get the data to display on the revisions page
* @param Array $fields The fields
* @return Array The fields
*/
function _gardener_address_get_revisions_fields( $fields ) {
// Get our default values
$defaults = _gardener_address_metabox_defaults();
// For each field, use the key as the title
foreach ( $defaults as $key => $value ) {
$fields['_gardener_address_' . $key] = ucfirst( $key );
}
return $fields;
}
add_filter( '_wp_post_revision_fields', '_gardener_address_get_revisions_fields' );
/**
* Display the data on the revisions page
* @param String|Array $value The field value
* @param Array $field The field
*/
function _gardener_address_display_revisions_fields( $value, $field ) {
global $revision;
return get_metadata( 'post', $revision->ID, $field, true );
}
add_filter( '_wp_post_revision_field_my_meta', '_gardener_address_display_revisions_fields', 10, 2 );
}
I tried to display the array in my single-gardener.php
by using
<ul>
<?php
$custom_fields = get_post_custom( get_the_ID() );
$my_custom_field = $custom_fields['_gardener_address'];
foreach ( $my_custom_field as $key => $value ) {
echo "<li>" . $key . " => " . $value . "</li>";
}
?>
</ul>
However, all I get is one long string
0 => a:12:{s:6:"street";s:8:"Straat 1";s:3:"zip";s:7:"1234 AB";s:4:"city";s:4:"City";s:4:"tel1";s:0:"";s:4:"tel2";s:0:"";s:5:"email";s:0:"";s:3:"url";s:16:"http://test.com/";s:2:"fb";s:0:"";s:7:"twitter";s:0:"";s:8:"linkedin";s:0:"";s:5:"insta";s:0:"";s:4:"pint";s:0:"";}
I am pretty much a PHP beginner and honestly have no idea why my data is echoed as one long string, instead of each value being listed seperately... Can anyone guide me in the right direction?