No other way to put this: How do I use The Loop? - wordpress

I apologise for this post being so long. The REASON for me asking such a stupid question as the topic suggests is BECAUSE there is just so many different things going wrong that I need to provide details of WHY I am asking this question.
Please bear with me...
I am busy creating a custom theme for my personal use have a LOT of slug-based pages and I use WP_query a lot(!) for many things from a custom news ticker to procedurally generating my navbar to mention but a few.
I was under the impression that creating a custom WP_Query means the content inside the results will not interfere with the operation of the main Loop and yet, I get very strange behaviour...
All my custom slug-based pages always work perfectly fine but when I use this in my navagation.php template part:
$query = new WP_Query($args);
if ($query->have_posts()) : while ($query->have_posts()) : $query->the_post();
//do my stuff here
endwhile; endif;
...this results in pages and posts loading just fine during the Loop but when I get to the product I am trying to view it always shows the same product no matter what link I follow. Eventually I added this to the product page:
if (have_posts()) {
the_post();
rewind_posts();
}
...and that made the products load up just fine. Yeay! No idea WHY I have to do it but it works. Strangely enough, though, in the template, just before it loads the template part that does the product layout, I print the name of the post currently in the global $post and then watch as it prints the wrong name above the right product after starting the Loop. (!?)
So then I find out about get_posts() and I like the fact that it gives me an array rather than an object that contains an array and so I swap over to using get_posts() in my navigation.php header template part and now my header section still works perfectly and my products display perfectly... but all posts and pages now show the same content. All posts and pages now show the same WooCommerce product. (!?) What's more confusing is that I do 3 WP_Query calls in navigation.php and the Loop in my posts and pages all show the first entry from the FIRST query, not the last...
After much struggling I decided it wasn't worth the aggravation so I swapped back to using WP_Query. Now things are all messed up in ways I can't even begin to understand... Now my posts and pages work just fine (so does my custom menu) but my products now all show the same product while in the loop. I tried doing this:
global $post;
$current = $post;
//do my query and loop over it
$post = $current;
Somehow that code turns the $post (which is just a pointer into the array) into an array itself (or something) because the product template now first displays the same product on every page I go to and then it displays the $post product it was supposed to directly below it. If I set $post to null directly after I set $current then setting $post back to $current afterwards results in only the wrong page showing up.
Somehow I managed to get it to stop showing the wrong product and now, instead, only my slug-based pages work because anything that uses the Loop (post, page and product) just tells me this:
Fatal error: Uncaught Error: Cannot use object of type WP_Query as array in D:\xampp\wordpress\htdocs\wp-includes\class-wp-query.php:3071 Stack trace: #0 D:\xampp\wordpress\htdocs\wp-includes\class-wp-query.php(3099): WP_Query->next_post() #1 D:\xampp\wordpress\htdocs\wp-includes\query.php(805): WP_Query->the_post()
..and tracking the stack trace to where that occurs seems to indicate that (apparently) I am trying to use a WP_query as an array when I say this during the Loop:
if (have_posts()) : while (have_posts()) : the_post()
How is THAT code wrong? It's straight from the manual! :O
According to the Codex, even though get_posts() also uses WP_Query it allows you to have multiple Loops and it says that you should use the restore_post_data() (I think) IF you updated the main Loop contents. But I am NOT trying to modify the main Loop at all. I want to do a query, have the results in a variable, run over that result and then discard the variable before going into the Loop and showing the page content as normal. I want my queries to run independently of the Loop and NOT in any way interfere with the operation of the Loop at all.
So:
why the heck does my custom WP_Query calls interfere with that I am seeing in the Loop and
why the heck do I get the error about trying to pass a WP_Query object as an array when calling the default, vanilla Loop
why do my products display correctly but my posts and pages do not
or why does my post and pages show correctly while my products show two different products
How the heck can my fully functional site get THIS broken just by going from $posts = get_posts($args) to $query = new WP_Query($args) ???? In a separate job completely outside the Loop, no less!
It makes absolutely no sense and since it makes no sense I have no idea where to start when trying to implement a fix. So what am I not seeing here? rewinding the posts, restoring the post data... nothing helps. I am completely dumbfounded.
Am I not using the Loop correctly? All I want to do is this:
Load a page that does a custom WP_query and displays the content
Load the template part that performs the Loop (i.e. single-product)
Display the template part that page loads (i.e. content-single-product) and have it be the right content
It shouldn't be this hard, should it?

Such a simple little thing to cause such a massive amount of grief... :(
Inside my navigation template part when I made the switch back from get_posts() to WP_Query I stored one query in $posts and the other in $query. Seems $posts is a reserved variable in WordPress because the moment I changed $posts to $query also everything worked 100% perfectly again!
I was aware of $post but not $posts. Now I know. Special thanks to #zipkundan for pointing me towards wp_reset_postdata(). That page taught me that custom queries DO in fact affect the global Loop (News to me!) and showed how to work around it.
So basically, the problem with my posts not showing what they were supposed to was due to me not calling wp_reset_postdata() after running through my custom loop and the reason for all the inexplicable weird page anomalies was due to me saving my custom query to a reserved variable name.
Mystery solved.

Related

Wordpress - How to skip the search result page and directly jump to the first result

I am creating a shipment tracking site using wordpress.
Is there a way to jump to the first result without seeing the result page?
If you have a search.php or searchform.php file in your theme, you can just remove the while() loop so that WP only displays the first result.
if ( have_posts() ) :
the_post();
// Include your template for displaying content here
else :
// Display no post found notice
endif;
Note that this will override ALL search form results, so if you have other search forms in different places that need to return multiple results, then you will need to add some logic to handle both cases.

Wordpress | Design an entire category (Not category page)

I'm creating my first wordpress theme, and I've looked around on google, and the wordpress codex for an answer to my question, but I can't seem to find exactly what I'm looking for, or couldn't get it working.
What I'm trying to do, or trying to figure out, is how I can make it so a certain category has a certain design.
So if I wanted to make an index.php for any music videos in "www.domain.com/music/trash/drake-song.mp4.html"
the trash category, it'd have its own design, but songs in
"www.domain.com/music/good-music/coldplay-viva-la-vida.mp4.html"
the good-music category, I want it to look pretty much completely different. I've tried using something similar inside my header.php to this;
<?php
if( is_tag( 'good-music' ) ):
$my_classes = array( 'good-class', 'good-class-two' );
else:
$my_classes = array( 'not-good-class' );
endif;_
?>
but it seemed to simply change the category page.
"www.domain.com/categories/good-music"
Anyone know what I could be doing wrong? I know basic html/css/php/javascript, new to creating a WordPress theme, and can't seem to get this working..
Also:
Using XAMPP to host locally, using Friendly URL's, properly configured
In order to generate category-specific markup for a single post layout, you can put code like the below in your single.php file after the call of get_header().
Please note that this checks for your category based upon category slug. So if your category slug (the url version of your category) does not match the first arguments in the in_array() function call below, then you should change the argument to match the slug for your category.
<?php
/* Start the Loop */
while ( have_posts() ) : the_post();
?>
<?php
$categories = get_the_category();
$catSlugs = array();
foreach ($categories as $category){
$catSlugs[] = $category->slug;
}
if (in_array('good-music',$catSlugs)){
$post_cat = 'good-music';
} else {
$post_cat = 'not-good-music';
}
get_template_part( 'template-parts/post/content', $post_cat );
?>
<?php
endwhile; // End of the loop.
?>
It is important that this code only appear where there is a query to loop against.
Specifically, the file single.php in your theme should be the default file for displaying a single post, regardless of category. When you navigate to the url of a single post, this layout should be triggered.
As part of that triggering, a wordpress query of just that post is returned to be looped through.
Then, the code from while ( have_posts() ) : the_post(); until endwhile; will run one time, because there is a single post to be processed.
If there were more than one post, such as on a category page or on your default post listing page, then the code inside of that while loop would run as many times as there are posts in the query for that layout.
If you were to place the code in the header, it won't work because the header is prepared independently of the loop that runs on this page.
You could run a custom WP_query() in the header, but that is rarely a good way to handle site content.
In this situation it would not be appropriate, because you are customizing content of existing posts, and only differentiating based upon category.
So, just use the standard layouts files with custom layout parts.
I stripped out the divs in the loop below, because you may or may not be using bootstrap.
After this code is placed on your page, you would create files called content-good-music.php and content-not-good-music.php in YOUR_THEME_DIR/template-parts/post/ directory. The key is that you would add whatever your category slug is to the end of your
These files will contain the unique markup for these kinds of posts. You can also use a similar logic in your post listing loop to give the listed posts for each category their own unique php files.
Here's some get_template_part() documentation.
https://developer.wordpress.org/reference/functions/get_template_part/

Set wordpress query before template

I have a business goal forcing me to try to change the global wordpress query after the URL has been determined, but before the templates start outputting variables in the context of the original post. I need to be able to use a plugin to check some meta values on the original post, and then change the query to represent another post object to display different data without changing the url.
I've tried using setup_postdata() what seems like everywhere.
(tried including wp_reset_query();)
global $post;
$post = get_post(145, OBJECT );
setup_postdata($post);
However, the template is still outputting the original query.
I'm open to other solutions. Thanks in advance.
add_action('wp_loaded', function(){
query_posts(array('p'=>145,'post_type' =>'any'));
});
This worked out fine. It can be added just about anywhere. However, it messes up page templates, and displays pages as if they're single.php!!! If I can get around that, then I'll be in good shape. Help?
EDIT: Got it working. I have to check and use p for posts, and page_id for pages. So long as those are set, the templates will follow correctly. Otherwise it was trying to apply the standard post template to pages.

Find from where the data comes to "the_content()" function

This might look an ordinary question though I'm stuck in it. I'm new to the wordpress. I've bought a wordpress theme and I'm trying to edit some pages as I want. Now I want to edit the default post page where I've already started editing the "single.php" and "post-format.php" files. I want to know from where or how "the_content()" function gets data?
Since I want some html part of the page to be removed though that html part comes through a "the_content" function. Therefore, I'm unable to remove that part without getting rid of "the_content" function. But I can't get rid of "the_content" function because the very same function calls some important part too.
Hope you guys can help!
From Where
As a function get_the_content() retrieve the post content (Generally Used in a Loop) from database and prints on the frontend.
And again the_content() as filter controls how you show the post content.
How
Dead simple answer by WordPress API. You need to understand WordPress Database_API for in-depth understanding.
Frequently Used by
wp-includes/plugin.php: apply_filters()
wp-includes/post-template.php: get_the_content()
wp-includes/post-template.php: the_content
Usage Case: (from Codex)
post_password_required()
get_the_password_form() if post_password_required() fails
wp_kses_no_null() while processing the tag.
balanceTags()
get_permalink()
global: $id, $post ,$more, $page, $pagesm, $multipage, $preview, $pagenow
Ref:
- Filter the_content() | Functionthe_content()
Optional: Offline WP Codex Docs Search/Browser for Windows/OSx

Should I use wp_reset_postdata() or just save the global $post variable myself?

I have a Wordpress 4.3 site that uses Yoast for SEO. I have a custom post type and a shortcode that can be used to generate a list of posts of that type. The shortcode function uses what I believe to be the recommended approach in Wordpress for generating a list of posts of a certain type:
$query = new WP_Query(...);
while ($query->have_posts())
{
$query->the_post();
// Now I can call methods like the_ID(), the_permalink(), etc
// I can also access details of the post directly, because at
// this point it is stored in the global $post variable.
}
wp_reset_postdata(); // To restore original copy of global $post variable
When viewing the actual page that contains the shortcode, everything works fine because the global $wp_query variable stashes a copy of the global $post variable before the shortcode function gets called, which enables wp_reset_postdata() to successfully restore the state of the global $post variable.
However, I recently discovered a problem when editing the page and although I have fixed the issue, I would like to know if my solution is correct practice in the Wordpress world.
The problem was that whenever I edited the page, several fields would get changed without me having actually touched any of the settings. Further investigation revealed that the reason for this was that the HTML for the edit page, specifically the contents of some form fields, had already been altered by the time they reached my browser. Compounding this problem was the fact that the permalink field, which is highly visible, was not being altered, but a hidden field called slug was being altered, and so when the page was submitted, Wordpress was updating the permalink with the value of this now corrupted, hidden slug field. My permalink wasn't so perma after all!
The only clue I had about what was causing the problem was that the permalink that was being set belonged to another post; in fact, one of the posts that comes up when the shortcode function gets executed.
After a day and a half of debugging, I figured out the precise reason why the form fields were being trashed:
When preparing the edit page for a post, Wordpress calls all the related plugins in case they need to add any additional information or controls to the sidebar.
One such plugin is Yoast, which reports an SEO Status. In order to calculate this status, Yoast silently renders the post so that it can then analyse the contents of the page, taking into account the focus keywords, etc.
In order for Yoast to silently render a page, all of the shortcode functions that contribute output to that page must also be executed.
When my shortcode function gets executed as part of Yoast's silent page rendering, it does what I beleive to be the right thing by calling wp_reset_postdata() at the end to restore the contents of the global $post variable.
However, the problem was that wp_reset_postdata() was not, in fact, restoring the global $post variable, because the global $wp_query variable did not have a copy. I would have expected wp_reset_postdata() or WP_Query->reset_postdata() to throw an error at that point, but they don't.
So every form field in the edit page that was generated after Yoast did its work ended up with values from the wrong post, because the global $post variable had been left with the wrong contents.
I have resolved the problem by adding the following defensive/unobtrusive code to the top of my shortcode function:
global $wp_query;
if ( $wp_query->post == null )
{
return '';
}
This means my shortcode function will only execute "the loop" when there is a guarantee that it will be able to restore the global $post variable using wp_reset_postdata().
Should I stick to this solution or take it one step further and simply save a copy of the global $post variable myself and just ignore wp_reset_postdata() altogether?

Resources