custom post types link hierarchy - php

I have to independet custom post types:
course
lesson
So one course can have many lesson and one lesson can be used in many courses. It is a m:n relation.
Now I've content that should be only visible on the lesson page, if it is viewed from a specific course.
Actually the link structure is like that:
Go to course: example.org/my-first-course
I see all lessons, that related to this course
Click on a lesson. Link structure is: example.org/great-lesson
My problem at this stage is, that I don't know from which course the lesson i called.
One thing I can do is to attach the course id as a get parameter to the link:
example.org/great-lesson/?course_id=123
But I would like to have a link structure more like that:
example.org/my-first-course/great-lesson
How can I do this?
.:: UPDATE: SOLUTION ::.
Here is my solution, maybe it'll help someone.
If you use "add_rewrite_rule", don't forget to change the slug (slug-custom-post-type) for your custom post type and the query var (cpt-query-var) of it.
I've tried to use index.php?name=$matches[1], but it will redirect to the custom post type and all other information in the URL will be lost. So it is important to use the custom post type query var instead.
To access the 'course' you have to use the get_query_var function:
echo get_query_var('course', '');
function my_rewrite_rules() {
add_rewrite_rule( '^slug-custom-post-type/([^/]*)/?', 'index.php?cpt-query-var=$matches[1]&course=$matches[2]', 'top' );
}
add_action('init', 'my_rewrite_rules');
function my_query_vars($qvars) {
$qvars[] = 'course';
return $qvars;
}
add_filter( 'query_vars', 'my_query_vars' );

I think you should use,
example.org/great-lesson/my-first-course
instead of using
example.org/my-first-course/great-lesson
as the great-lesson will be static here and the id or slug is dynamic which shows detailed course/lesson.
And to add custom rewrite rule you can use,
function custom_rewrite_basic() {
add_rewrite_rule('^great_lesson/(.*)', 'index.php?page_id=$matches[1]', 'top');
}
add_action('init', 'custom_rewrite_basic');
Then get the slug from url and write code according to it. Read more about add_custom_rule

Related

Wordpress add_filter('query_vars', 'my_new_vars'); not working as expected

I have an issue with Wordpress (there's a shocker), where it removes my get parameter, which i understand thats a WP feature for security and some other reasons.
What i'm trying to achieve is the following:
Load product page
When customer clicks book now they are redirected to an enquire now form
On enquire now form there is widget that retrieves what product the customer was looking at and using a GET parameter i can retrieve this product
I've tried to add the get parameter as follows:
# functions.php
function gpd_register_query_vars($vars)
{
$vars[0] = 'my_product_id';
return $vars;
}
add_filter('query_vars', 'gpd_register_query_vars');
Within my widget
class GPD_Get_Product_Widget extends WP_Widget
{
// ...
function widget($args, $instance)
{
global $wp_query;
var_dump($wp_query->query_vars['my_super_unique_var']);
extract($instance);
//output code
echo $args['before_widget'];
include 'widget.php';
echo $args['after_widget'];
}
}
//function to register the widget
function gpd_get_product_widget()
{
register_widget('GPD_Get_Product_Widget');
}
add_action('widgets_init', 'gpd_get_product_widget');
However, whenever i try to get the parameter it doesn't exist.
Wordpress isn't the easiest to navigate or work with. I'm really confused to why WP has made such a simple thing such as $_GET params so difficult.
Any help is much appreciated.
I found the answer and not entirely sure why this is but if you pass 2 params in your URL like so /my-page?a=1&b=2 and then use a plain old $_GET, you'll find that the the first element is a q and the second is your b param.
array(2) {
'q' =>
string(29) "/request-a-quote/a=1"
'b' =>
integer(1) "2"
}
It looks like the first param is occupied by q (reserved var) by Wordpress and anything after that is additional params which are yours (unless they are reserved by WP).
So if I was to build my URL like so:
add_query_arg(['type' => 'holiday', 'product_id' => 12345], get_permalink($page_id) );
You have to add a first param that will be ignored and then the second will be available as a $_GET.
I might be doing something wrong but this works for me for now. Any help and pointers to what I'm doing wrong would be great - as this feels wrong but works.

Magento 2/Wordpress/Fishpig related posts

I am currently trying to retrieve a list of related posts on the post article page (post single). I have created a new function within /Block/Post/ListPost.php
public function getRelatedPosts()
{
$posts = $this->getPosts();
die($this->getCategoryId());
return $this->_postCollection;
}
However when I try and output getCategoryId, I get nothing. I'm also unsure how I apply a category filter to the post collection.
Can anyone advise here?
I'm not sure where you have got the getCategoryId method from but this is not part of the ListPost block class so will not work. You cannot just invent methods like this.
You should check the block class for what methods are available. An easy way to do that without even loading the file is to add the following PHP to the class:
echo sprintf('<pre>%s</pre>', print_r(get_class_methods($this)));
exit;
You don't specify in what way the posts should be related but I'm guessing you want to get posts from the same category. One option to do this would be to load the primary category of the post and then get a post collection based on this. If you look in the Post class file, you will see the getParentTerm($taxonomy) method.
if ($category = $post->getParentTerm('category')) {
$relatedPosts = $category->getPostCollection();
// Remove the current post from the collection
$relatedPosts->addFieldToFilter('ID', array('neq' => $post->getId()));
}
You should always look at the class file's you're working with. That is the beauty of open source. You can literally see what methods are available for each object and you can even see how they work.

Trouble passing arguments to WordPress pre_get_posts

I need your help! I am having trouble passing arguments to a function using pre_get_posts.
Purpose of passing arguments:
I have a custom taxonony-$taxonomy.php page which I use to list posts related to a particular category within the specified taxonomy. On this page I also retrieve & setup tags assigned to each post from a custom non hierarchical taxonomy and list them as links on the side. I have another taxonomy-$taxonomy.php (for the custom non hierarchical taxonomy mentioned above) setup so when a user chooses a link he/she clicks on a tag it will direct them to this taxonomy page. This is all working fine.
However, here's where I'm having issues. The posts listed on the non hierarchical taxonomy page are those associate to a particular tag but from multiple categories. What I’m trying to achieve is to list posts associates to the tag chosen and from the category previously being viewed. So for example: Lets say the user clicks on category ‘Accounting’, then chooses the tag ‘Creative Services’. All posts listed should not only be associated with ‘Creative Services’ must also be assigned to only the ‘Accounting’ category. This is where I’ve been trying to pass arguments to the function used by pre_get_posts.
How have I tried passing arguments?:
1- Setup globals: This way no arguments have to be past via the function being invoked. It did not work because the timing is off. The globals are not yet set when the action is called. Below is my code with example post_type and taxonomy. Notice $category is the global variable which hold the category within that taxonomy.
// Alter main query on doc_tag taxonomy templates
function only_query_doc_tag_posts( $query ) {
global $category;
if ( is_tax(array('doc_tag')) && !is_admin() ) {
if($query->is_main_query()) {
$query->set( 'post_type', 'post_type' );
$query->set( 'taxonomy', 'taxonomy_array' );
$query->set( 'taxonomy_name', $category ); //global
}
}
}
add_action( 'pre_get_posts', 'only_query_doc_tag_posts' );
Results:
When I view the main query it shows all the changes except the one using the global. If I manually insert the value into the function, instead of using the a global variable then it works. However, I'd like to be able to change this on the fly. Just so you're aware I do get the posts related to the tag but not those only associated to the category indicated by the global (when using the global).
2- do_action:
// Alter main query on doc_tag taxonomy templates
function only_query_doc_tag_posts( $query,
$post_types, //array
$taxonomies, //array
$category //global var
) {
global $category;
if ( is_tax(array('doc_tag')) && !is_admin() ) {
if($query->is_main_query()) {
$query->set( 'post_type', $post_types );
$query->set( 'taxonomy', $taxonomies );
$query->set( 'taxonomy_name', $category ); //global
}
}
}
add_action( 'pre_get_posts', 'only_query_doc_tag_posts', 10, 4 );
Then on the custom non hierarchical taxonomy page template I add the following:
do_action( 'pre_get_post', $post_types, $taxonomies, $category );
I have a feeling my second approach is not technically but I could be wrong, which is why I'm posting it here in hopes that someone can provide some direction. If I missed information that would help you help me please let me know.
Thank you in advance for helping me with this.
FYI: I've read these posts but did not get find a solution. Maybe it's there and I missed it? Please let me know.
Wordpress pre_get_posts and passing arguments
WordPress pre_get_posts not working
wp_query not filtering tax_query correctly in pre_get_posts
Passing arguments with add_action and do_action throwing error 'First argument is expected to be a valid callback'
Wordpress, filter posts if custom query variables are present. (pre_get_posts, add_vars)
Wordpress pre_get_posts category filter removes custom menu items
passing argument using add_action in wordpress!
I think I understand what you try to do.
Long in short - no, you can not do (do_action) by yourself, it is called by wp query parts.
If you try to pass arguments, you need look into [$query->query_vars].
I think a proper solution, for you need, is write a proper url rewrite rules, it can auto pick the taxonomy, and put it into url list, then values can auto show in [$query->query_vars] .
Which is [add_filter('rewrite_rules_array', 'set_url_rule');]
You may also need install plugin [rewrite-rules-inspector] to help you inspect the rewrite status.
Anyway, it could take you an afternoon to find the logical behind it, but then, it all makes sense.
If you just looking for a quick solution, you can inject some code into query_vars, you just need to :
add_filter('query_vars', 'insert_query_vars');
function insert_query_vars( $vars ){
array_push($vars, 'c_type');
array_push($vars, 'c_tax');
array_push($vars, 'c_term');
return $vars;
}

How to apply codeigniter's URL_TITLE value to the URL

I'm completely new to ci,
I have a url something like this:
http://localhost/mvc/post/prod_id/1
And I want it to be:
http://localhost/mvc/post/my-best-product
So far I'm able to manage to route all that to home/post/ and learned the segment function also.
But my question is how do I really get the url_title out to the actual url.
I couldn't find any information on this particular subject. All I could find is how to use the url_title and how to route in ci. But they don't explain how we can actually change the base url name.
Please guide me to the right direction.
solution Example:
public function my_method($product_slug)
{
$product1 = "training-for-recruitment";
$product2 = "training-for-od";
if($product_slug==$product1)
{
$this->load->view('prod1');
}else if($product_slug==$product2)
{
$this->load->view('prod2');
}else{
show_404();
}
}
This is not what exactly I'm going to do. It is just for others to understand the workaround of Slugs.
Generate a unique slug for each of your product. Add a field for it on product table and every time, while selecting a product from table, use that slug instead of getting the product from primary id.
So, your function becomes like:
function product($product_slug)
{
//get product by slug from database
//load view page
}
Now, in config/routes.php
$route['your_controller_name/(:any)'] = "your_controller_name/product/$1";
You need to do this:
Set up some logic that translates "my-best-product" to "1"
Set up routing in CI that calls your 'prod_id' controller and passes the URI vars

Dynamic routing

I want to be able to choose a controller based on data gathered form the uri.
I have a categories table and a subcategories table. Basically I have a URL in the following format (:any)/(:any). The first wildcard is a city slug (i.e edinburgh) and the second is going to be either a category or a subcategory slug.
So in my route I search for categories with that route, if I find it, I want to use controller: forsale and method: get_category. If it's not a category I'll look up subcategories, if I find it in there I want to use controller: forsale and method: get_subcategory. If it's not a subcategory I want to continue looking for other routes.
Route::get('(:any)/(:any)', array('as'=>'city_category', function($city_slug, $category_slug){
// is it a category?
$category = Category::where_slug($category_slug)->first();
if($category) {
// redirect to controller/method
}
// is it a subcategory?
$subcategory = Subcategory::where_slug($category_slug)->first();
if($subcategory) {
// redirect to controller/method
}
// continue looking for other routes
}));
First off I'm not sure how to call a controller/method here without actually redirecting (thus changing the url again).
And secondly, is this even the best way to do this? I started using /city_slug/category_slug/subcategory_slug. But I want to only show city_slug/category|subcategory_slug but I need a way to tell which the second slug is.
Lastly, there may be other URL's in use that follow (:any)/(:any) so I need it to be able to continue looking for other routes as well.
Answer to your questions in order:
1. Instead of using different controller#action's you could use a single action and based on the second slug (category or subcategory), render a different view (although I don't like this approach, see #2 and #3):
public class Forsale_Controller extends Base_Controller {
public function get_products($city, $category_slug) {
$category = Category::where_slug($category_slug)->first();
if($category) {
// Do whatever you want to do!
return View::make('forsale.category')->with(/* pass in your data */);
}
$subcategory = Subcategory::where_slug($category_slug)->first();
if($subcategory) {
// Do whatever you want to do!
return View::make('forsale.sub_category')->with(/* pass in your data */);
}
}
}
2. I think /city_slug/category_slug/subcategory_slug is way better than your method! You should go with this one!!
3. Again, you should revise your routes. I always try to make my routes in a way that they don't confuse me, neither Laravel!! Something like /products/city/category/subcategory is much more clear!
Hope it helps (my code is more like a psudocode, it's not been tested )!

Categories