Passing MULTIPLE vars with add_rewrite_endpoint fails - php

I have read many tutorials about passing multiple variables to a post/page in wordpress, using add_rewrite_endpoint. I am currently passing 2 variables, calendar_year / calendar_month . It works good for both but separately each one. Using both like (http://myserver/mysite/availability/calendar_year/2016/calendar_month/10/) only gets the year and if I pass them on reverse, only gets the month. Availability page shows correct (No 404 error), but it fails taking the last parameter when there are the two of them. Here is my code for add_rewrite_endpoint
function booking_calendar_add_endpoints() {
add_rewrite_endpoint('calendar_year', EP_ALL);
add_rewrite_endpoint('calendar_month', EP_ALL);
}
add_action('init','booking_calendar_add_endpoints');
And this is how I get it and use it:
global $wp_query;
$year_var = $wp_query->get( 'calendar_year' );
$month_var = $wp_query->get( 'calendar_month' );
I am sure I am missing something. Does anyone have a solution for it? Thanks.

Related

Wordpress post object is modified after get_header() is called in the theme

I have a custom page in my theme where I am creating a post from a different DB table and I want to then make this display inside wordpress as if it were a normal post. It seems to work most of the time, but randomly it seems that the post is modified after i call get_header() and i cant see why.
I have setup a mod rewrite rule in apache to hit a php file and in here i get the data I need and build the php object. I populate the wordpress post object using this function.
function BuildSimplePost($title, $body)
{
require_once( SITEROOT . '/wp-load.php' );
#$post = new WP_Post();
#$post->ID = -1;
$post->post_parent = 0;
$post->post_title = $title;
$post->post_name = "simple-response";
$post->post_excerpt = substr($body, 0, 100);
$post->comment_status = "closed";
$post->ping_status = "closed";
$post->post_type = "page";
$post->post_content = $body;
return $post;
}
Once the post is sorted I then push this post into the wordpress query objects and let the theme do the rest of the work.
$posts = array($post);
$wp_query->posts = $posts;
$wp_query->post_count = count($posts);
$wp_query->found_posts = count($posts);
$wp_query->max_num_pages = 1;
$wp_query->post = $post;
$wp_query->is_404 = 0;
$wp_query->is_singular = 1;
$wp_query->is_single = 1;
$wp_query->page_id = $post->ID;
include get_template_directory()."/external-page.php";
Inside external-page.php there is nothing weird. It is literally a copy of single.php with some html removed. The issue im having is that when get_header(); is called in this file the post is changed to something else. This then triggers a redirect which brings the user to a different page on the site that is part of wordpress.
Anyone know why the get_header method would be causing a redirect like this?
It's hard to tell exactly what's changing up your post. The way I see it, you've got two options:
Keep putting your content back into the post. This is not the WordPress way of solving this problem but it's probably the easier approach. #ArtisticPhoenix's answer above is the right concept but the wrong specific code.
Create a custom post type, which is the WordPress way. #CBroe offered this and the response to your answer to his question should (IMHO) be: "it doesn't matter how complicated your post type is, you should encapsulate it in a CPT if you're using WordPress."
Put your content back
Keep a copy of your post object somewhere and put it back right after anything that changes it. You can create a new global:
global $mypost;
$mypost = BuildSimplePost(...);
If you know the $title and $body parameters, you can just call your function again every time you need it. You could also use a transient, a update_option/get_option call, or several other things.
There are several filters that could be the cuplrit:
The the_post action should change $post. That's the one thing it really does. You may want to sit on top of the hook stack like this: add_filter('the_post', function() { global $post, $mypost; $post = $mypost; }, 10000);
Before the wp object is set up, there are several actions and you run a high likelihood of anything hooked changing $post because it's free game before then. You may have plugins or your theme hooking on: parse_request, parse_query, pre_get_posts, or posts_selection. You may try something like add_filter('parse_request', function() { global $post; $post = $mypost; }, 10000); for each of these filters.
I've seen some plugin developers adding things that change the $post global (and other things they probably shouldn't change) during calls to the actions template_redirect, get_header, loop_start, and after query. Heck, I've done it myself a few times. You could try the same thing with these filters although I'd consider them less suspect.
If that doesn't get your content back, you could try something really dirty, like forcing it in right before the call to the_post. There's no hook for this but if you control the theme it's easy.
The WP Way
I understand that you think that your post is very complicated but I'll offer you this from several years of being neck-deep in WP code: breaking the WP post model is a recipe for heartache. If you're not using posts and you're not using the way they're intended, you probably shouldn't be using WP. There are other frameworks that offer things like user authentication, themeing, database persistence, eventing, REST, etc. without the overhead of WP.
Another way
That having been said, I've used WP in the past because it was part of a requirement that I couldn't control. When my post gets too complicated, I create a wrapper object like so:
class MyPostWrapper {
private $_Post;
private $_Meta = array();
public function __construct($post) {
$this->_Post = get_post($post);
$this->_Meta = $this->_LoadMeta();
}
private function _LoadMeta() {
// Load everything into $_Meta: other tables, options, post meta, etc.
}
public function __get($name) {
if (array_key_exists($name, $this->_Meta))
return $this->_Meta[$name];
}
// Use a similar implementation for __set and __isset.
}
However complicated your post gets, you can manage its lifecycle and all of its trail very easily with a single wrapper.
Then you don't have to worry about who's eating your post. If they are, they probably should be.

Modifying query in Wordpress search

I'm trying to integrate a Query Expansion software with Wordpress, but the wordpress search engine is an AND searcher (returns those contents that contain all the words in your query, and therefore the more extensive is the query the fewer results returns).
For that reason when i use the query with the expansion features, the Searcher returns me less results.
I would like to modify the Search's behavior, and turn it into something more like an OR searcher.
Example:
For the query " iot, internet of things", I would want those posts which contents "iot", or "internet of things, or both of them.
I've reading through this document (https://codex.wordpress.org/Class_Reference/WP_Query) and i tried to use something like this:
add_action( 'template_redirect', 'hooks_setup' , 20 );
function hooks_setup() {
if (! is_home() ) //<= you can also use any conditional tag here
return;
add_action( '__before_loop' , 'set_my_query' );
add_action( '__after_loop' , 'set_my_query', 100 );
}
function set_my_query() {
global $wp_query, $wp_the_query;
switch ( current_filter() ) {
case '__before_loop':
//replace the current query by a custom query
//Note : the initial query is stored in another global named $wp_the_query
$wp_query = new WP_Query( array(
'post_type' => 'post',
'post_status' => 'publish',
//others parameters...
) );
break;
default:
//back to the initial WP query stored in $wp_the_query
$wp_query = $wp_the_query;
break;
}
}
But I don't know which parameters i need to set in wp_query. How can I achieve this?
To answer what parameters you need to set, you have to read through the same page you mentioned. Parameters for various items (post types or categories) are defined on this page and when you want to change it all you have to do is modify the parameters.
If you dont know what query you want to do I think its hard for people to help. If you are getting less results, you can open query a bit further or obtain results in 2 queries. Read through the page and you will find its common when people want to obtain different types of data and not everything is in the loop.
Also read through this to understand more about the loop and how to reset the query and do a new one then you can obtain two result sets and use them or combine them when and where you want.
Just to give you an example for string search in posts with s as parameter from the same page Prepending a term with a hyphen will exclude posts matching that term. Eg, 'pillow -sofa' will return posts containing 'pillow' but not 'sofa' (available since Version 4.4).

How to use a custom post type archive as front page in WordPress?

I'd like to use a custom post type archive as a site's front page, so that
http://the_site.com/
is a custom post type archive displayed according to my archive-{post-type}.php file.
Ideally I would like to alter the query using is_front_page() in my functions.php file. I tried the following, with a page called "Home" as my front page:
add_filter('pre_get_posts', 'my_get_posts');
function my_get_posts($query){
global $wp_the_query;
if(is_front_page()&&$wp_the_query===$query){
$query->set('post_type','album');
$query->set('posts_per_page',-1);
}
return $query;
}
but the front page is returning the content of "Home" and seems to be ignoring the custom query.
What am I doing wrong? Is there a better way, in general, of going about this?
Note: I did post this in WordPress Answers but that community is comparatively tiny.
Posting the final solution as an answer (Isaac placed it as a comment) just for anyone still looking.
Isaac was on the right track with adding a filter via functions.php. What he did wrong was call is_front_page(), which doesn't work yet because we're in pre_get_posts and the query hasn't been executed yet.
We do have the current page ID however. So we can still solve this, by looking into the WordPress option register for an option called page_on_front, which returns the ID of the page the user set as frontpage.
(For an overview of all WordPress options, just visit <yourwordpressinstallation>/wp-admin/options.php in your browser.)
Which makes for the following solution as suggested by Ijaas:
add_action("pre_get_posts", "custom_front_page");
function custom_front_page($wp_query) {
// Compare queried page ID to front page ID.
if(!is_admin() && $wp_query->get("page_id") == get_option("page_on_front")) {
// Set custom parameters (values based on Isaacs question).
$wp_query->set("post_type", "album");
$wp_query->set("posts_per_page", -1);
// WP_Query shouldn't actually fetch the page in our case.
$wp_query->set("page_id", "");
}
}
You might have to alter a few conditional tags to make sure all plugins still work, depending on how heavily the query gets altered.
Hope this helps someone.
Update: as noted below, add !is_admin() to the if-statement to make sure the function only runs on the frontend. If you only want this action to run for the initial query, you could also add the main query check $wp_query->is_main_query().
In response to Robberts solution:
answered May 6 '13 at 12:04
adding && !isAdmin() to the if function other wise it replaces the post type query for all admin pages as well.
Just in case anyone has issues with this.
edit:
also adding && $wp_query->is_main_query() to the if statement stops it affecting widgets and the menu
so total code I have
if($wp_query->get("page_id") == get_option("page_on_front") && !isAdmin() && $wp_query->is_main_query()) {}
In order to get that query to work, you're going to have to add that code to a page template, create a page, set your template as the template for the page you just created, and then set that page as the home page in Settings => Reading in the admin area.
By the way, the is_front_page() function only returns true if you're on a page that's been set as the home page from the admin menu.
The other option would be to modify index.php, but if you did that, is_front_page() would always return false. In that case, you'd want to use is_home() instead.
I hope that helps.
Isaac, you are correct, I didn't thoroughly read your question and I made the assumption that you were looking to do this the "easy" way.
Anyway, I put your code on my test site and, indeed, it didn't work. I looked at my SQL log and it turns out that your code produces this in the query wp_posts.post_status = 'private'.
So, I tried adding the line $query->set('post_status', 'public'); to your function, and it worked just fine.
In summary, try this:
add_filter('pre_get_posts', 'my_get_posts');
function my_get_posts($query){
global $wp_the_query;
if(is_front_page()&&$wp_the_query===$query){
$query->set('post_type','album');
$query->set('posts_per_page',-1);
$query->set('post_status', 'public');
}
return $query;
}

How to get id of post inside of plugin

I want to retrive post id inside plugin.
I tried
global $post;
$a_Id=$post->ID;
and
global $wp_query;
$thePostID = $wp_query->post->ID;
and
var_dump(get_the_ID()); //shows just null
How i can retrieve it?
The idea is to get language of post from Custom Fields
and feed it into Global Translator plugin as a BASE LANG
EDIT:
I can retrive id from $_GET['p'] on development server but on production i
have pretty urls so i dont have it.
Assuming that you know what the ID is for an particular post you could use
var_dump(get_defined_vars());
to show a listing of anything that you can get your hands on.
Look through the output for the ID that you know and then use the path that it shows to get there.
What are you doing with the post ID? When exactly do you need it? I'm guessing you are using this very early in your plugin file, when the query is not yet parsed. The query is parsed after the hook parse_query is fired.

Getting Post Information Outside the Wordpress Loop

I know there are functions to like is_single() that will return data about the page, but I'm looking for a way to get the following information outside of the loop:
The category of the single post.
AND
The title of the single post.
All I would really need is the post ID in question and I could get all the other information. I've looked through the functions reference in the codex, but I haven't found anything. Is this impossible because the script doesn't even get that information 'til the Loop runs?
(I would need this information in both the header and footer, so before and after the PHP script for the loop, if that is a problem.)
Hopefully someone can offer some insight.
EDIT: To clarify: I want the information to be from the post that is loaded in the loop on the "single" page. (AKA the post they are viewing.) So how would I get this ID in the first place? Basically, when viewing a post, I want to get its category or title, but not while the loop is going.
This is actually quite simple.
// Gets an array of post objects.
// If this is the single post page (single.php template), this should be an
// array of length 1.
$posts = get_posts();
// The post object contains most/all of the data that is accessible through the
// normal functions like `the_ID()`, `the_author()`, etc
var_dump($posts[0]->ID);
This can be performed outside of and it doesn't affect the normal loop. For example, my single.php template looks like this (line numbers included):
1. <?php
2. get_header();
3. $posts = get_posts();
4. var_dump($posts[0]->ID);
5. ?>
6. <div id="post">
You could execute your own query and return a $post object and then access it's attributes through something like
echo $post->title;
Read about $wpdb and Custom Queries on the Codex. Basically you could run a SQL query using the ID as a where filter through its $wpdb object.
Another option, more WP-like, would be to use a Custom Query Post, where you could define another loop, returning only your post using its id:
query_posts('p=2010'); // 2010 being the post's ID
Then you could run the alternative loop and use the similar $post object to display some information.
This is what I use inside the loop to run an new query; I just tried it outside the loop and it works, on a single.php template page. This will give the title of the latest post in mycategory. I don't know how to pull the category ID, though.
$my_query = new WP_Query('category_name=mycategory&showposts=1');
while($my_query->have_posts()):
$my_query->the_post();
the_title();
endwhile;
After the query has run, try running:
global $wp_query;
var_dump( $wp_query );
The information you are looking for is probably in $wp_query->query_vars or $wp_query->post
You can use the $wp_query global object, and address all returned posts like this
$wp_query->posts ; // contains an array of posts.
Then, if for instance you need to know if the first post is of a certain post_type, you can do this:
$first_post_type = $wp_query->posts[0]->post_type;
Couldn't you store the $post information in a separate variable on the page, then just echo the data you need out later when you need it (ie, outside the loop)?
This is predicated on needing the data after the initial loop has run.
The usual thing is to create "second loop" which would extract needed post, hence your needed data.

Categories