Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

WordPress

Allen Atha
PLUS
Allen Atha
Courses Plus Student 24,710 Points

Having trouble while creating a Custom Post Type Widget

Hello Treehousers,

I'm trying REALLY hard to get this WordPress plugin to work. I feel that I'm really close but I can't quite get it to work. I've just finished Zac's course on Creating Plugin's (awesome course by-the-way) and I am trying to have a go at it myself in the form of just some simple property listings.

I could really use someone a bit more experienced to take a look at my code and see where I'm fouling it up. Thanks a bunch.

<?php
/*
 *Plugin Name: Idea Tree Property Plugin
 *Plugin URI: http://#
 *Description: Declares a plugin that will create a custom post type displaying Property information.
 *Version: 1.0
 *Author: Allen Atha
 *Author URI: http://jumpdragonmedia.com/allenatha/
 *License: GPLv2
*/

/*
 * Assign global variables
 *
*/

$plugin_url = WP_PLUGIN_URL . '/wpideatreeproperties';

add_action( 'init', 'wpideatree_create_property' );

function wpideatree_create_property() {

    global $plugin_url;

    register_post_type( 'properties',
        array(
            'labels' => array(
                'name' => 'Properties',
                'singular_name' => 'Property',
                'add_new' => 'Add New',
                'add_new_item' => 'Add New Property',
                'edit' => 'Edit',
                'edit_item' => 'Edit Property',
                'new_item' => 'New Property',
                'view' => 'View',
                'view_item' => 'View Property',
                'search_items' => 'Search Properties',
                'not_found' => 'No Properties were found',
                'not_found_in_trash' => 'No Properties were found in Trash',
                'parent' => 'Parent Property'
            ),

            'public' => true,
            'menu_position' => 15,
            'supports' => array( 'title', 'editor', 'comments', 'thumbnail' ),
            'taxonomies' => array( 'PropertyStatus' ),
            'menu_icon' => plugins_url( 'get_template_directory_uri() . "images/cutom-posttype-icon.png"' ),
            'has_archive' => true
        )
    );
}

add_action( 'admin_init', 'wpideatree_properties_admin' );

function wpideatree_properties_admin() {
    add_meta_box( 'properties_meta_box',
        'Property Details',
        'display_property_meta_box',
        'properties', 'normal', 'high'
    );
}

function display_wpideatree_properties_meta_box( $property ) {
    // Retrieve current name of the Director and Movie Rating based on review ID
    $price = esc_html( get_post_meta( $property->ID, 'price', true ) );
    $location = esc_html( get_post_meta( $property->ID, 'location', true ) );
    $construction = esc_html( get_post_meta( $property->ID, 'construction', true ) );
    $property_status = intval( get_post_meta( $property->ID, 'property_status', true ) );
?>
    <table>
        <tr>
            <td style="width: 100%">Price:</td>
            <td><input type="text" size="80" name="property_price" value="<?php echo $price; ?>" /></td>
        </tr>
        <tr>
            <td style="width: 100%">Location:</td>
            <td><input type="text" size="80" name="property_location" value="<?php echo $location; ?>" /></td>
        </tr>
        <tr>
            <td style="width: 100%">Date of Construction:</td>
            <td><input type="text" size="80" name="property_construction" value="<?php echo $construction; ?>" /></td>
        </tr>
        <tr>
            <td style="width: 150px">Property Status</td>
            <td>
                <select style="width: 100px" name="property_rating">
                <?php
                // Generate all items of drop-down list
                for ( $rating = 5; $rating >= 1; $rating -- ) {
                ?>
                    <option value="<?php echo $rating; ?>" <?php echo selected( $rating, $property_status ); ?>>
                    <?php echo $rating; ?> stars <?php } ?>
                </select>
            </td>
        </tr>
    </table>
    <?php }

add_action( 'save_post', 'add_wpideatree_property_fields', 10, 2 );

function add_wpideatree_property_fields( $property_id, $property ) {
    // Check post type for movie reviews
    if ( $property->post_type == 'properties' ) {
        // Store data in post meta table if present in post data
        if ( isset( $_POST['property_price'] ) && $_POST['property_price'] != '' ) {
            update_post_meta( $property_id, 'price', $_POST['property_price'] );
        }
        if ( isset( $_POST['property_location'] ) && $_POST['property_location'] != '' ) {
            update_post_meta( $property_id, 'location', $_POST['property_location'] );
        }
        if ( isset( $_POST['property_construction'] ) && $_POST['property_construction'] != '' ) {
            update_post_meta( $property_id, 'construction', $_POST['property_construction'] );
        }
        if ( isset( $_POST['property_rating'] ) && $_POST['property_rating'] != '' ) {
            update_post_meta( $property_id, 'property_status', $_POST['property_rating'] );
        }
    }
}

add_filter( 'template_include', 'wpideatree_include_template_function', 1 );

function wpideatree_include_template_function( $template_path ) {
    if ( get_post_type() == 'properties' ) {
        if ( is_single() ) {
            // checks if the file exists in the theme first,
            // otherwise serve the file from the plugin
            if ( $theme_file = locate_template( array ( 'single-property.php' ) ) ) {
                $template_path = $theme_file;
            } else {
                $template_path = plugin_dir_path( __FILE__ ) . '/single-property.php';
            }
        }
    }
    return $template_path;
}


?>
Andrew Shook
Andrew Shook
31,709 Points

Allen, what is the plugin not doing that it should or what errors are you getting?

5 Answers

Andrew Shook
Andrew Shook
31,709 Points

So I copied all the code from above a put it into a plugin real quick. Everything seemed to work correctly. The only problem that I say was the mark up in your single-property.php. I went a head a added the correct markup for the 2014 theme. Here it is:

<?php
 /*

  Template Name: Property

 */

get_header(); ?>

<div id="main-content" class="main-content">
    <div id="primary" class="content-area">
        <div id="content" class="site-content" role="main">
            <?php
            $mypost = array( 'post_type' => 'properties', );
            $loop = new WP_Query( $mypost );
            ?>
            <?php while ( $loop->have_posts() ) : $loop->the_post();?>
                <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
                    <header class="entry-header">

                        <!-- Display featured image in right-aligned floating div -->
                        <div>
                            <?php the_post_thumbnail( array( 100, 100 ) ); ?>
                        </div>      
                        <!-- Display Title and Price -->
                        <strong>Title: </strong><?php the_title(); ?><br />
                        <strong>Price: </strong>
                        <?php echo esc_html( get_post_meta( get_the_ID(), 'price', true ) ); ?>
                        <br />
                        <!-- Display Location -->
                        <strong>Location: </strong>
                        <?php echo esc_html( get_post_meta( get_the_ID(), 'location', true ) ); ?>
                        <br />
                        <!-- Display Date of Construction -->
                        <strong>Date of Construction: </strong>
                        <?php echo esc_html( get_post_meta( get_the_ID(), 'construction', true ) ); ?>
                        <br />

                        <!-- Display yellow stars based on rating -->
                        <strong>Rating: </strong>
                        <?php
                        $nb_stars = intval( get_post_meta( get_the_ID(), 'property_rating', true ) );
                        for ( $star_counter = 1; $star_counter <= 5; $star_counter++ ) {
                            if ( $star_counter <= $nb_stars ) {
                                echo '<img src="' . plugins_url( 'Movie-Reviews/images/icon.png' ) . '" />';
                            } else {
                                echo '<img src="' . plugins_url( 'Movie-Reviews/images/grey.png' ). '" />';
                            }
                        }
                        ?>
                    </header>

                    <!-- Display property contents -->
                    <div class="entry-content"><?php the_content(); ?></div>
                </article>

            <?php endwhile; ?>
        </div>
    </div>
    <?php wp_reset_query(); ?>
    <?php get_sidebar( 'content' ); ?>
    <?php get_sidebar(); ?>
</div>

<?php get_footer(); ?>
Andrew Shook
Andrew Shook
31,709 Points

Found some errors in you plugin's main file and I made some fixes:

<?php
/*
 *Plugin Name: Idea Tree Property Plugin
 *Plugin URI: http://#
 *Description: Declares a plugin that will create a custom post type displaying Property information.
 *Version: 1.0
 *Author: Allen Atha
 *Author URI: http://jumpdragonmedia.com/allenatha/
 *License: GPLv2
*/

/*
 * Assign global variables
 *
*/

$plugin_url = WP_PLUGIN_URL . '/wpideatreeproperties';

add_action( 'init', 'wpideatree_create_property' );

function wpideatree_create_property() {

    global $plugin_url;

    register_post_type( 'properties',
        array(
            'labels' => array(
                'name' => 'Properties',
                'singular_name' => 'Property',
                'add_new' => 'Add New',
                'add_new_item' => 'Add New Property',
                'edit' => 'Edit',
                'edit_item' => 'Edit Property',
                'new_item' => 'New Property',
                'view' => 'View',
                'view_item' => 'View Property',
                'search_items' => 'Search Properties',
                'not_found' => 'No Properties were found',
                'not_found_in_trash' => 'No Properties were found in Trash',
                'parent' => 'Parent Property'
            ),

            'public' => true,
            'menu_position' => 15,
            'supports' => array( 'title', 'editor', 'comments', 'thumbnail' ),
            'taxonomies' => array( 'PropertyStatus' ),
            'menu_icon' => plugins_url( 'get_template_directory_uri() . "images/cutom-posttype-icon.png"' ),
            'has_archive' => true
        )
    );
}

add_action( 'admin_init', 'wpideatree_properties_admin' );

function wpideatree_properties_admin() {
    add_meta_box( 'properties_meta_box',
        'Property Details',
        // changed this function callback to match the function name of the below function.
        'display_wpideatree_properties_meta_box',
        'properties', 'normal', 'high'
    );
}

function display_wpideatree_properties_meta_box( $property ) {
    // Retrieve current name of the Director and Movie Rating based on review ID
    $price = esc_html( get_post_meta( $property->ID, 'price', true ) );
    $location = esc_html( get_post_meta( $property->ID, 'location', true ) );
    $construction = esc_html( get_post_meta( $property->ID, 'construction', true ) );
    $property_status = intval( get_post_meta( $property->ID, 'property_status', true ) );
?>
    <table>
        <tr>
            <td style="width: 100%">Price:</td>
            <td><input type="text" size="80" name="property_price" value="<?php echo $price; ?>" /></td>
        </tr>
        <tr>
            <td style="width: 100%">Location:</td>
            <td><input type="text" size="80" name="property_location" value="<?php echo $location; ?>" /></td>
        </tr>
        <tr>
            <td style="width: 100%">Date of Construction:</td>
            <td><input type="text" size="80" name="property_construction" value="<?php echo $construction; ?>" /></td>
        </tr>
        <tr>
            <td style="width: 150px">Property Status</td>
            <td>
                <select style="width: 100px" name="property_rating">
                <?php
                // Generate all items of drop-down list
                for ( $rating = 5; $rating >= 1; $rating -- ) {
                ?>
                    <option value="<?php echo $rating; ?>" <?php echo selected( $rating, $property_status ); ?>>
                    <?php echo $rating; ?> stars <?php } ?>
                </select>
            </td>
        </tr>
    </table>
    <?php }

add_action( 'save_post', 'add_wpideatree_property_fields', 10, 2 );

function add_wpideatree_property_fields( $property_id, $property ) {
    // Check post type for movie reviews
    if ( $property->post_type == 'properties' ) {
        // Store data in post meta table if present in post data
        if ( isset( $_POST['property_price'] ) && $_POST['property_price'] != '' ) {
            update_post_meta( $property_id, 'price', $_POST['property_price'] );
        }
        if ( isset( $_POST['property_location'] ) && $_POST['property_location'] != '' ) {
            update_post_meta( $property_id, 'location', $_POST['property_location'] );
        }
        if ( isset( $_POST['property_construction'] ) && $_POST['property_construction'] != '' ) {
            update_post_meta( $property_id, 'construction', $_POST['property_construction'] );
        }
        if ( isset( $_POST['property_rating'] ) && $_POST['property_rating'] != '' ) {
            update_post_meta( $property_id, 'property_status', $_POST['property_rating'] );
        }
    }
}

add_filter( 'template_include', 'wpideatree_include_template_function', 1 );

function wpideatree_include_template_function( $template_path ) {
    if ( get_post_type() == 'properties' ) {
        if ( is_single() ) {
            // checks if the file exists in the theme first,
            // otherwise serve the file from the plugin
            if ( $theme_file = locate_template( array ( 'single-property.php' ) ) ) {
                $template_path = $theme_file;
            } else {
                // removed forward slash here. __FILE__ ends in forward slash. 
                $template_path = plugin_dir_path( __FILE__ ) . 'single-property.php';
            }
        }
    }
    return $template_path;
}


?>
Allen Atha
PLUS
Allen Atha
Courses Plus Student 24,710 Points

Andrew Shook - What I am trying to design is a custom post type plugin that has the predefined fields of; price, location and date of construction (just to get started). I would like to be able to:

1) click on the post icon in the dash menuenter values into these fields and into the wp editor. 2) create a page and assign it my template from the template drop-down to display my custom posts

// I just realized that I did not add that file in the original forum post. Let me do that now.

<?php
 /*

  Template Name: Property

 */

get_header(); ?>
<div id="primary">
    <div id="content" role="main">
    <?php
    $mypost = array( 'post_type' => 'properties', );
    $loop = new WP_Query( $mypost );
    ?>
    <?php while ( $loop->have_posts() ) : $loop->the_post();?>
        <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
            <header class="entry-header">

                <!-- Display featured image in right-aligned floating div -->
                <div style="float: right; margin: 10px">
                    <?php the_post_thumbnail( array( 100, 100 ) ); ?>
                </div>

                <!-- Display Title and Price -->
                <strong>Title: </strong><?php the_title(); ?><br />
                <strong>Price: </strong>
                <?php echo esc_html( get_post_meta( get_the_ID(), 'price', true ) ); ?>
                <br />
                <!-- Display Location -->
                <strong>Location: </strong>
                <?php echo esc_html( get_post_meta( get_the_ID(), 'location', true ) ); ?>
                <br />
                <!-- Display Date of Construction -->
                <strong>Date of Construction: </strong>
                <?php echo esc_html( get_post_meta( get_the_ID(), 'construction', true ) ); ?>
                <br />

                <!-- Display yellow stars based on rating -->
                <strong>Rating: </strong>
                <?php
                $nb_stars = intval( get_post_meta( get_the_ID(), 'property_rating', true ) );
                for ( $star_counter = 1; $star_counter <= 5; $star_counter++ ) {
                    if ( $star_counter <= $nb_stars ) {
                        echo '<img src="' . plugins_url( 'Movie-Reviews/images/icon.png' ) . '" />';
                    } else {
                        echo '<img src="' . plugins_url( 'Movie-Reviews/images/grey.png' ). '" />';
                    }
                }
                ?>
            </header>

            <!-- Display property contents -->
            <div class="entry-content"><?php the_content(); ?></div>
        </article>

    <?php endwhile; ?>
    </div>
</div>
<?php wp_reset_query(); ?>
<?php get_footer(); ?>
Andrew Shook
Andrew Shook
31,709 Points

Allen, I get what you are trying to do. What I'm asking is what does the plugin currently do/how much do you have done? Also, what is it that you need help with specifically. I.e. you can't get the custom post type to work or the custom fields aren't storing values.

Allen Atha
PLUS
Allen Atha
Courses Plus Student 24,710 Points

Andrew, this plugin was modified (forked?) from a tuts+ article which was designed to do movie reviews. I thought that I would use it to try making custom post types programmatically, as Zac has already shown how to do so with the aid of plugins in the How to Build a WordPress Theme course (which as a great course).

So, right now the plugin breaks the twenty-twelve theme completely. I think it is the last function (wpideatree_include_template_function) that does it in. I was able to see the following before it break completely:

  1. the code created an admin nav menu titled Properties
  2. I was unable to see my custom fields, only the wp editor in the post editor
  3. when I created a new page I was unable to see the template "Property" in the template drop-down menu to apply the custom posts.

Thanks for the help and the replies!

Andrew Shook
Andrew Shook
31,709 Points

Ok, so to help you out it would be easier if I have your code. Do you have a github I could pull you code from? Or could you post all the code here so I could debug?

Allen Atha
PLUS
Allen Atha
Courses Plus Student 24,710 Points

Andrew, Thank you so much for catching that mismatched display and I had no idea that the FILE ends with a slash! The theme is now working and when I update the Custom post the values, they stick.

But I am still having trouble actually displaying the post as it not currently finding the theme template. The template still doesn't appear in the template drop down menu on the page admin. I've tried to directly place the single-property.php file in the themes folder, and still it does not appear in the drop down menu. I'm racking my brain trying to figure out why I can't get the template to appear. Any thoughts?

Again, thank you for all your help!!!

Andrew Shook
Andrew Shook
31,709 Points

Allen, I haven't forgotten about you. I did find that the template selector you see with pages is not available to other post types. I am working on a hack right now. It may take a while. I have it showing the templates but it isn't saving that data. However, I was wondering, why do you need the template selector? You already have it so what they can create their own single-property.php template.

Allen Atha
PLUS
Allen Atha
Courses Plus Student 24,710 Points

Andrew,

Sorry to have not gotten back to you for a couple of days now. Work has had me jumping. This plugin that I am working on is a part of a code challenge. The parameters of the challenge are as follows:

Create a wordpress plugin as follows: 1) Plugin should create a custom post type called "property" 2) Properties should be able to created, edited and deleted from the backend by wordpress admin users. 3) Property custom post type should have a custom taxonomy called PropertyStatus (There should be two values defined: Sale, Rent) and on creating a new property we should be able to choose this taxonomy. 4) Property custom post type should include a meta-box with with meta values for: --Price --Location --Date of construction

I thought that I could do it. When I started on it over a week ago I thought it would be pretty straight forward. But, now I don't think that I'm quite up to it as of yet. Thank you though for all of your help so far. If I am able to crack it, i will be sure to return to this forum post and fill you in. It was my first code challenge outside of Treehouse.

Keep up the good work in helping us!

-Allen

Andrew Shook
Andrew Shook
31,709 Points

It looks like you've completed most of the challenge. What is it that you have left?