Blog

Creating Custom Post Types, with Multiple Text Fields in a Single Meta Box and Template Info, in WordPress
Posted on October 31, 2015 in PHP, WordPress by Matt Jennings

Below are WordPress and PHP code samples on how to:

  • Create custom post types using a plugin.
  • Create multiple text fields (using input and textarea tags for example) using inside a single meta box to push a custom post type into the MySQL database.
  • Using various theme templates to have said custom post types appear on a:
    • Page, including a limit to how posts can appear on said page template.
    • Single post template.

Plugin Example found at /wp-content/plugins/wp-job-listing/wp-job-listing.php

<?php
/**
 * Plugin Name: WP Job Listing
 * Plugin URI: http://hatrackmedia.com
 * Description: This plugin allows you to add a simple job listing section to your WordPress website.
 * Author: Bobby Bryant
 * Author URI: http://hatrackmedia.com
 * Version: 0.0.1
 * License: GPLv2
 */
// Exit if accessed directly
if(!defined('ABSPATH')) {
    exit;
}

// Create a custom post type
function dwwp_register_post_type() {
    $singular = 'Job Listing';
    $plural = $singular . 's';
    $labels = array(
        'name'                  => $plural,
        'singular_name'         => $singular,
        'add_name'              => 'Add New',
        'add_new_item'          => 'Add New ' . $singular,
        'edit'                  => 'Edit',
        'edit_item'             => 'Edit ' . $singular,
        'new_item'              => 'New ' . $singular,
        'view'                  => 'View ' . $singular,
        'view_item'             => 'View' . $singular,
        'search_term'           => 'Search ' . $plural,
        'parent'                => 'Parent ' . $singular,
        'not_found'             => 'No ' . $plural . ' found',
        'not_found_in_trash'    => 'No ' . $plural . ' in Trash'
    );
    $args = array(
        'labels'                => $labels,
        'public'                => true,
        'publicly_queryable'    => true,
        'exclude_from_search'   => false,
        'show_in_nav_menus'     => true,
        'show_ui'               => true,
        'show_in_menu'          => true,
        'show_in_admin_bar'     => true,
        'menu_position'         => 6,
        'menu_icon'             => 'dashicons-businessman',
        'can_export'            => true,
        'delete_with_user'      => false,
        'hierarchical'          => false,
        // Use this is post type doesn't need archive page
        'has_archive'           => false,
        'query_var'             => true,
        'capability_type'       => 'post',
        'map_meta_cap'          => true,
        'rewrite'               => array(
            'slug'                  => 'job-listings',
            'with_front'            => true,
            'pages'                 => true,
            'feeds'                 => true
        ),
        'supports'              => array(
            'title',
            'thumbnail'
        )
    );
    register_post_type('job', $args);
}
add_action('init', 'dwwp_register_post_type');

/**
 * Adds a box to the main column on the Post and Page edit screens.
 */
function job_listings_add_meta_box() {
    add_meta_box(
        'jobs_listings_id',
        __( 'New Job', 'job_listings_plugin' ),
        'jobs_listings_meta_box_callback',
        // This is the name of the custom post type,
        // does NOT need to 'slug' element of the
        // $args array above,
        // and must be only letter with no
        // special characters
        'job'
    );
}

function jobs_listings_meta_box_callback($post) {
    // Add a nonce field so we can check for it later.
    wp_nonce_field( 'myplugin_save_meta_box_data', 'myplugin_meta_box_nonce' );

    $job_title_value = get_post_meta($post->ID, '_job_title', true);
    $job_salary_value = get_post_meta($post->ID, '_job_salary', true);


    echo '<p><label for="job_title">Title</label> <input type="text" name="job_title" id="' . $post->ID . '" value="' . $job_title_value . '" style="width: 100%;" /></p>';

    echo '<p><label for="job_salary">Salary</label> <input type="text" name="job_salary" id="' . $post->ID . '" value="' . $job_salary_value . '" style="width: 100%;" /></p>';
}

add_action( 'add_meta_boxes', 'job_listings_add_meta_box' );


function jobs_save_meta_box_data( $post_id ) {
    /*
     * We need to verify this came from our screen and with proper authorization,
     * because the save_post action can be triggered at other times.
     */
    // Check if our nonce is set.
    if ( ! isset( $_POST['myplugin_meta_box_nonce'] ) ) {
        return;
    }

    // Verify that the nonce is valid.
    if ( ! wp_verify_nonce( $_POST['myplugin_meta_box_nonce'], 'myplugin_save_meta_box_data' ) ) {
        return;
    }

    // If this is an autosave, our form has not been submitted, so we don't want to do anything.
    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
        return;
    }

    if ( ! current_user_can( 'edit_post', $post_id ) ) {
        return;
    }

    /* OK, it's safe for us to save the data now. */
    // Make sure that it is set.
    if ( !isset($_POST['job_title']) && !isset($_POST['job_salary']) ) {
        return;
    }

    // Sanitize user input.
    $my_data_job_title = sanitize_text_field( $_POST['job_title'] );
    $my_data_job_salary = sanitize_text_field( $_POST['job_salary'] );

    // Update the meta field in the database.
    update_post_meta( $post_id, '_job_title', $my_data_job_title );
    update_post_meta( $post_id, '_job_salary', $my_data_job_salary );

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

/job-listings page template in a file called /wp-content/themes/twentyfifteen/job-listings.php that Lists All of the Job Listings Custom Post Types from Plugin Above

<?php
/*
Template Name: Job Listings
*/

/**
 * The template for displaying pages
 *
 * This is the template that displays all pages by default.
 * Please note that this is the WordPress construct of pages and that
 * other "pages" on your WordPress site will use a different template.
 *
 * @package WordPress
 * @subpackage Twenty_Fifteen
 * @since Twenty Fifteen 1.0
 */

get_header(); ?>

	<div id="primary" class="content-area">
		<main id="main" class="site-main" role="main">

			<?php
			$args = array(
				'post_type'      => 'job',
				'orderby'        => 'title',
				'order'          => 'asc',
				'posts_per_page' => 3
			);

			$lib_query = new WP_Query($args);
			if ($lib_query->have_posts()) {
				while ($lib_query->have_posts()) : $lib_query->the_post();

					$img_src = wp_get_attachment_image_src(get_post_thumbnail_id($post->ID));

					?>
					<div class="single-job">

						<p><strong><a href="<?php the_permalink(); ?>">_job_title:</strong> <?php echo get_post_meta($post->ID, '_job_title', true); ?></a></p>

						<p><strong>_job_salary:</strong> <?php echo get_post_meta($post->ID, '_job_salary', true); ?></p>

						<p><strong>Single Image:</strong><br /><?php echo get_the_post_thumbnail(); ?></p>

						<p><strong>Background Image:</strong></p>
						<p style="background: url(<?php echo $img_src[0]; ?>); height: 100px;"></p>

					</div>
				<?php endwhile;
				wp_reset_postdata();
			}
			?>

		</main><!-- .site-main -->
	</div><!-- .content-area -->

<?php get_footer(); ?>

Single Job Listings Post Template in a file called /wp-content/themes/twentyfifteen/single-job.php

<?php
/*
Template Name: Single Job Listings Post Template
*/

/**
 * The template for displaying pages
 *
 * This is the template that displays all pages by default.
 * Please note that this is the WordPress construct of pages and that
 * other "pages" on your WordPress site will use a different template.
 *
 * @package WordPress
 * @subpackage Twenty_Fifteen
 * @since Twenty Fifteen 1.0
 */

get_header(); ?>

<div class="list-container">

        <h1>Single Job Listings Post Template</h1>

    <?php
    // Start the loop.
    while ( have_posts() ) : the_post();

        $img_src = wp_get_attachment_image_src(get_post_thumbnail_id($post->ID));
    ?>

        <div class="single-job">

            <p><strong><a href="<?php the_permalink(); ?>">_job_title:</strong> <?php echo get_post_meta($post->ID, '_job_title', true); ?></a></p>

            <p><strong>_job_salary:</strong> <?php echo get_post_meta($post->ID, '_job_salary', true); ?></p>

            <p><strong>Single Image:</strong><br /><?php echo get_the_post_thumbnail(); ?></p>

            <p><strong>Background Image:</strong></p>
            <p style="background: url(<?php echo $img_src[0]; ?>); height: 100px;"></p>

        </div>


    <?php
        // End the loop.
    endwhile;
    ?>


</div>

<?php get_footer(); ?>

Code in /wp-content/themes/twentyfifteen/functions.php that Enables the single-job.php Template Above to Work and Enable Thumbnail Support for Said Custom Post Types

// Get Custom Post Type Template for a Single Post
function my_single_template($single) {
	if(file_exists(get_template_directory() . '/single-' . get_the_ID() . '.php'))
		return get_template_directory() . '/single-' . get_the_ID() . '.php';
	return $single;
}
add_filter('single_template', 'my_single_template');

/*
 * Enable support for Post Thumbnails on posts and pages.
 *
 * See: https://codex.wordpress.org/Function_Reference/add_theme_support#Post_Thumbnails
 */
add_theme_support( 'post-thumbnails' );

Code to add in the Custom Structure field, after Logging in the WordPress Admin and going to Settings > Permalinks and choosing the Custom Structure radio button

/%category%/%postname%/

Leave a Reply