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

Stephen O'Connor
Stephen O'Connor
22,291 Points

WP_Query Question

OK, this is a little hard to explain but I will try my best to paint a good picture.

I have a site just now where I have setup a custom post type - 'components' - to hold posts that I am looking to use in the sidebar of the site as related posts on a per page basis. These components will consist of a selection of components: an image with text and a link, contact details, testimonials etc.

I can get my related posts to display on the page but I am looking to use specific custom fields from the components custom post type in the related posts, so I am using WP_Query.

The issue I am having is when I use WP_Query all my posts from the custom post type components are displaying instead of the ones I have chosen on the page.

I am using the Related plugin to pick and choose related posts/sidebar items.

My query below:

<?php
     global $related;
     $rel = $related->show( get_the_ID(), true );
?>

<?php
     $args = array(
          'post_type' => 'component'
     );

     $the_query = new WP_Query( $args );
?>

<?php if ( have_posts() ) : while ( $the_query->have_posts() ) : $the_query->the_post(); ?>

     <?php the_field( 'component_heading' ); ?>

<?php endwhile; ?>

<?php endif; ?>

I am just looking for the components chosen on the page to display, not all the components that have been saved.

Thanks.

5 Answers

Great :)

So my solution only requires them and we will hook into there data as we go..

Below I have pasted a simplified snippet of something I have just done, I have left on all of the div classes but removed attributes so you only see what is needed to echo out the data to the page in among a working layout and then you can work on your styling of the returned elements :)

Firstly we simply declare your post type for a custom query:

                <!-- Declare Custom Post Type for Custom Query -->

                <?php 

                    $args = array(

                        //Triple check the post type name as nothing beyond this point will display should it be incorrect 
                        'post_type' => 'components'

                    );

                    $infoDropdown = new WP_Query( $args );

                ?>

                <!-- //Close Custom Query Declaration -->

Once that is taken care of its down to the loop, as I mentioned I have left the div classes in so we can see how the custom loop is tying in with the layout just like a normal wordpress loop really.

<div class="panel-group">

    <div class="panel">

        <!-- Open Custom Query Loop -->
        <?php if ( have_posts() ) : while ( $components->have_posts() ) : $components->the_post(); ?>

        <div class="panel-heading">

                <!-- Get Items From Custom Post Type and Declare as Variables -->
                <?php 

                    //Get Custom Post Type By Slug and Declare as Variable
                    $image = get_field('component_image');

                    //Get Custom Post Type By Slug and Declare as Variable
                    $heading = get_field('component_heading');

                    //Get Custom Post Type By Slug and Declare as Variable
                    $text = get_field('component_text');

                    //Get Custom Post Type By Slug and Declare as Variable
                    $link = get_field('component_link');


                ?>

            <h4 class="panel-title">

                <a  class="<?php the_permalink(); ?>">

                    <?php echo $heading ?>

                </a>

            </h4>

        </div>

        <div class="panel-body">

            <div class="panel-image">

                <?php echo $image ?>

            </div>

            <div class="panel-info">

                    <?php echo $info ?>

                </div>

            <div class="panel-link">

                       <?php echo $link ?>

                </div>            

        </div>


        <?php endwhile; endif; ?>
        <!-- //Close Custom Query Loop -->

    </div>

</div>

I have not tested this code with a custom post type (possibly a silly thing to do) but this is a custom query that will get the data from a post type called "components", store that data in variables for us to use later in the code and then echo out that data where you would like.

To style this appropriately so that if your client was to not enter a link of image just use min and max heights rather that fixed. The loop will still run for the number of time there are component posts.

The only thing I did not ask and am getting to now is that if your client were to have more than one post this code would loop through them all and whip them on the page unless we restrict the number displayed. However from what you have said you intend for them to have more than one :)

All the code I posted was wrapped in a container div originally as it was echoed out into a column on the right hand side of a page.

Below is my fully working original so you have a concrete reference that is tested and worked to refer to should the above need a little tweaking. There is tons of stuff below you simply will not need to achieve your desired result but I though it would be helpful to have a tested snippet of code :)

Sorry for the long answer but I tried to be as descriptive as possible to help, if we cant get it working please let me know i will set up a custom post type and tweak until working :)

            <!-- Drop Down Panel Custom Post Type -->
            <div class="col-md-5 col-md-offset-1">

                <div class="drop-group-title">

                      <?php if( !dynamic_sidebar( 'drop-group-title' ) ): ?>

                        <p>Please Add Widget Drop Group Title</p>

                      <?php endif; ?>

               </div>


                <!-- Declare Custom Post Type for Custom Query -->
                <?php 

                    $args = array(

                        'post_type' => 'info-dropdown'

                    );

                    $infoDropdown = new WP_Query( $args );

                ?>
                <!-- //Close Custom Query Declaration -->

                <!-- Open Panel Group -->
                <div class="panel-group" id="accordion" role="tablist" aria-multiselectable="true">

                    <div class="panel panel-info">

                        <!-- Custom Query Loop -->
                        <?php if ( have_posts() ) : while ( $infoDropdown->have_posts() ) : $infoDropdown->the_post(); ?>

                        <div class="panel-heading" role="tab" id="headingOne">

                                <!-- Get Items From Custom Post Type -->
                                <?php 

                                    //Get Custom Post Type By Slug and Declare as Variable
                                    $title = get_field('title');

                                    //Get Custom Post Type By Slug and Declare as Variable
                                    $info = get_field('description');

                                    //This controls specific ID's for DropDown Capabilities on the Titles
                                    $dropdownContols = array( 'One', 'Two', 'Three', 'Four', 'Five' );
                                    $i = $infoDropdown->current_post;


                                ?>

                            <h4 class="panel-title">

                                <a  class="panel-toggle-control"
                                    data-toggle="collapse"
                                    data-parent="#accordion"

                                    href="#collapse<?php echo $dropdownContols[$i]; ?>"

                                    aria-expanded="true"
                                    aria-controls="collapse<?php echo $dropdownContols[$i]; ?>">

                                    <?php the_title(); ?>

                                    <span class="panel-chevron glyphicon pull-right"></span>

                                </a>

                            </h4>

                        </div>

                        <div id="collapse<?php echo $dropdownContols[$i]; ?>"
                             class="panel-collapse collapse <?php if( $infoDropdown->current_post == 2 ) : ?>in<?php endif; ?>"
                             role="tabpanel"
                             aria-labelledby="headingOne">

                            <div class="panel-body">

                                <?php echo $info ?>

                            </div>

                        </div>



                        <?php endwhile; endif; ?>
                        <!-- //Close Custom Query Loop -->

                    </div>

                </div>

            </div>
            <!-- //Close Drop Down Panel Custom Post Type -->

I realise the above is very code rich but in there you can see the declaration of a custom post type and the point in which I echo it out along with its title.

Hope this can help and im sure we will have data on your screen soon enough!

Craig

Stephen O'Connor
Stephen O'Connor
22,291 Points

Hi Craig,

Thanks for the very detailed answer, it has been a big help, I can certainly see clearer what I need to do to get all the information displayed on the screen. Getting the information and then storing it in variables for future use is something I wasn't doing so will definitely implement this.

I'll have a play around with things today and hopefully come to a solution.

Again, I appreciate your time and help on this, hopefully I can get it to work.

Thanks.

No problem Stephen I hope all goes well,

Have you done the course on wordpress them dev. ?

This is where i learnt about custom query :)

Good Luck !!

Stephen O'Connor
Stephen O'Connor
22,291 Points

Yeah I have, but I still struggle with some things in WordPress and PHP. My next venture is to learn PHP a little bit more in depth, but actually finding the time to do that at the moment is a struggle!

Thanks again.

Hi Stephen :)

I think we can sort this pretty quick for you and have everything working from the back end so you simply and the content from admin and php does the rest...

So you have a custom post type with custom fields or just custom fields added to you normal pages and post?

Also what are the slug names i.e. components-title or components-info of the custom fields you set up?

I will then be able to paste in a custom query for you with the details you require to be displayed :)

Hope we can sort this for you and you can kick back and relax for the day ...(if only)..

Craig

Stephen O'Connor
Stephen O'Connor
22,291 Points

Hi Craig,

This sounds encouraging :) I appreciate you looking at this for me.

OK, so to give you a better picture of what I am trying to do. My site will have 5 different 'types' of page/sidebar component, a list of services, an image with text and a link, contact details, a testimonial and an advert, and I'd like my client to be able to pick and choose what components go on each page and what order they are displayed in. After some digging the Related plugin seems to be able to do this very easily.

At the moment I only have 1 custom post type called 'Components', I think I will probably have to make more to suit each type of component I am looking for but if I can get one working I can alter the rest to suit.

So the custom post type is called 'Components', the custom field field group is called 'Component Elements', and the fields in that group are called 'Component Image' (component_image), 'Component Heading' (component_heading), 'Component Text' (component_text) and 'Component Link' (component_link).

All the different components will need to be styled differently so I will need to add some sort of hook to say 'if component = image component' use this styling or 'if component = services list' use that styling etc.

Let me know if you need anymore information, and again, appreciate you looking at this for me.

** EDIT ** I am using Custom Post Types UI and Advanced Custom Fields if that matters any.

No problem Stephen,

Just another question before i get ahead of myself, are you using Custom Post Type UI by WebDevStudios and Advanced Custom Fields by Elliot Condon as your plugins for the custom posts / fields ?

Craig

Hi,

Would it be possible to give the specific posts / pages you would like content to be looped from a specific category and then then you can and then you can hook in to it through your args array ?

                <?php 

                    $args = array(

                        'post_type'     => 'post',
                        'category_name' => 'feature'
                    );

                    $feature_content = new WP_Query( $args );

                ?>

Sorry if this is way off :)

Craig

Stephen O'Connor
Stephen O'Connor
22,291 Points

Hi Craig,

Thanks for coming back to me. I am not sure if this would work or not tbh, I'll do some digging today to see if I can implement this.

The Related plugin I am using gives you some sample code that seems to work but it only displays the title of the post, code below. Which I guess is along the lines of what I am looking to do but I am looking to style the output my own way and also return the values of custom fields (from a custom post type) and not just the title of the post. PHP is not my strong point and I am not really sure how to alter this to make it work for my needs.

If you, or anyone else could offer help that would be great. I fear today could be a long day of scratching my head and swearing at my screen :)

<?php
    global $related;
    $rel = $related->show( get_the_ID(), true );

    // Display the title of each related post
    if( is_array( $rel ) && count( $rel ) > 0 ) {
        foreach ( $rel as $r ) {
            if ( is_object( $r ) ) {
                if ($r->post_status != 'trash') {
                    echo get_the_title( $r->ID ) . '<br />';
                }
            }
        }
    }
?>
Stephen O'Connor
Stephen O'Connor
22,291 Points

Great minds ... I've just edited my last comment to say that :) I am using Custom Post Types UI and Advanced Custom Fields.

Thanks.

Stephen O'Connor
Stephen O'Connor
22,291 Points

Hi Craig,

I just thought I'd give you an update on my progress and what code I actually used to get this all to work correctly.

So after a few attempts using the Related plugin I still could only get all my sidebar items displaying, no matter if they were related to the page via the plugin or not, so this solution didn't seem to be the correct one for me.

So further searching around I saw that ACF actually had a relationship field that you could use and custom code given to output data from an array which was returned from the related post(s) in question, so using this code and changing it to suit my needs I came up with the following, which allows my client to pick and choose which sidebar components they would like to appear on each page and what order they appear in, it also allows my client to build their own sidebar components in future and use them as they see fit, which I feel is a good thing to be able to offer them as it gives them a lot of control over what they can display on their website.

<div class="components">

    <?php

        $posts = get_field('sidebar_components'); <!-- Relationship Field -->


    if( $posts ): ?>



            <?php foreach( $posts as $p ): // variable must NOT be called $post (IMPORTANT) ?>



                <?php if ( $p->post_type == 'image-component'): ?>

                    <!-- Image Components -->
                    <div class="single-component one-edge-shadow">
                        <div class="image-component">
                            <a href="<?php the_field('image_component_link', $p->ID); ?>"><img src="<?php the_field('image_component_image', $p->ID); ?>"></a>
                            <div class="image-component-container">
                                <div class="skew">
                                    <div class="inner">
                                        <h5><a href="<?php the_field('image_component_link', $p->ID); ?>"><?php the_field('image_component_heading', $p->ID); ?></a></h5>
                                        <p><?php the_field('image_component_text', $p->ID); ?></p>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                    <!-- End Image Components -->

                <?php endif; ?>



                <?php if ( $p->post_type == 'services-list'): ?>

                    <!-- Services List -->
                    <div class="single-component one-edge-shadow">
                        <div class="services">
                            <div class="skew">
                                <div class="inner">
                                    <h5><?php the_field('services_list_heading', $p->ID); ?></a></h5>
                                    <?php the_field('services_list_content', $p->ID); ?>
                                </div>
                            </div>
                        </div>
                    </div>
                    <!-- End Services List -->

                <?php endif; ?>



                <?php if ( $p->post_type == 'testimonials'): ?>

                        <!-- Testimonial -->
                        <div class="single-component one-edge-shadow">
                            <div class="testimonial">
                                <div class="skew">
                                    <p><?php the_field('testimonial_text', $p->ID); ?></p>
                                    <p class="name"><?php the_field('testimonial_name', $p->ID); ?></p>
                                    <p class="company"><?php the_field('testimonial_company', $p->ID); ?></p>
                                </div>
                            </div>
                        </div>
                        <!-- End Testimonial -->

                <?php endif; ?>



                <?php if ( $p->post_type == 'contact-details'): ?>

                        <!-- Contact Details -->
                        <div class="single-component one-edge-shadow">
                            <div class="contact">
                                <h5><?php the_field('contact_details_heading', $p->ID); ?></h5>
                                <p><?php the_field('contact_details_number', $p->ID); ?></p>
                                <p><a href="<?php the_field('contact_details_link', $p->ID); ?>"><?php the_field('contact_details_text', $p->ID); ?> <i class="fa fa-angle-double-right"></i></a></p>
                            </div>
                        </div>
                        <!-- End Contact Details -->

                <?php endif; ?>



            <?php endforeach; ?>



    <?php endif; ?>

</div>

I also used your suggestion of storing the values from the fields as variable to implement PictureFill which loads different image sizes at different screen resolutions, so I appreciate you pointing that out. I did this on a slider I have on the homepage.

<div class="home-hero flexslider">
                        <ul class="slides">


                            <?php if( have_rows('slider') ): ?>

                                <?php while( have_rows('slider') ): the_row(); 

                                    // Variables
                                    $slide_image = get_sub_field('slide_image');
                                    $slide_image_alt = $slide_image['alt'];
                                    $slide_image_size_large = 'slider-image-large';
                                    $slide_image_size_medium = 'slider-image-medium';
                                    $slide_image_size_small = 'slider-image-small';

                                    $slide_heading = get_sub_field('slide_heading');
                                    $slide_sub_heading = get_sub_field('slide_sub_heading');
                                    $slide_link = get_sub_field('slide_link');

                                    $final_image_large = $slide_image['sizes'][ $slide_image_size_large ];
                                    $final_image_medium = $slide_image['sizes'][ $slide_image_size_medium ];
                                    $final_image_small = $slide_image['sizes'][ $slide_image_size_small ];

                                ?>


                                <li>
                                    <a href="<?php echo $slide_link; ?>">
                                        <picture>
                                            <!--[if IE 9]><video style="display: none;"><![endif]-->
                                            <source srcset="<?php echo $final_image_large; ?>" media="(min-width: 1025px)">
                                            <source srcset="<?php echo $final_image_medium; ?>" media="(min-width: 769px)">
                                            <!--[if IE 9]></video><![endif]-->
                                            <img srcset="<?php echo $final_image_small; ?>" alt="<?php echo $slide_image_alt; ?>">
                                        </picture>
                                        <div class="caption">
                                            <div class="caption-heading">
                                                <h3><?php echo $slide_heading; ?></h3>
                                            </div>
                                            <div class="caption-text">
                                                <p class="sub"><?php echo $slide_sub_heading; ?></p>
                                            </div>
                                        </div>
                                    </a>
                                </li>


                                <?php endwhile; ?>

                            <?php endif; ?>


                        </ul>
                        <div class="flex-direction-nav-new"></div>
                    </div>

Again, I appreciate your help with this, input from someone else always seems to generate new ideas, and I am glad I found a solution to my issue.

Hi Stephen :)

Im glad you have a solid solution in place! Reading over your code it would seem I still had the wrong end of the stick a little bit with what i suggested. My code would have only echoed out the specific hard coded options specified, I really like how this gives the user high levels of custom elements!

This will most certainly be something I have a go at over the coming weeks to implement on future projects should this kind of capability be needed :)

Its also good for me still being new to the industry to see how other approach things so I appreciate you posting your solution.

Thanks Again Craig

Stephen O'Connor
Stephen O'Connor
22,291 Points

No worries. I'm used to building sites with ExpressionEngine and it is probably the most customisable cms I have used and gives you total control over what you can do and what your clients can do. When I have been building in WordPress I was always a little bit frustrated because it didn't seem as customisable as EE. But after digging a lot deeper into the ACF plugin and the ACF Repeater Field it looks like WordPress has caught up.

I like this solution because it gives my client a lot of control over what they can add to each page, with the custom post types and advanced custom fields they can build as many image components, testimonials, services lists etc as they wish and pick and choose which page they appear on and what order they appear in, totally independent of all the other pages on the site.

Appreciate your help again and if you need any help in the future trying to implement something similar give me a shout and I can try and help out.