Opened 17 months ago
Last modified 3 months ago
#19958 new enhancement
Allow custom post types as "home" and get_posts() to return results for more than one post type
| Reported by: |
|
Owned by: | |
|---|---|---|---|
| Priority: | normal | Milestone: | Awaiting Review |
| Component: | Administration | Version: | 3.3.1 |
| Severity: | major | Keywords: | has-patch needs-testing needs-codex |
| Cc: | sooskriszta, pbearne@…, jarrod@…, info@…, travis@…, navjotjsingh@… |
Description
In
Wordpress admin > Settings > Reading
there is an option to define what the home page or the front page should be
Front page displays
Radio button
A static page (select below)
is followed by a dropdown containing a list of all pages.
I would request that custom page types be allowed in this dropdown. This way, I could make my bbPress forums or my All-in-one event calendar, etc my homepage.
Attachments (3)
Change History (25)
comment:1
pbearne
— 8 months ago
- Cc pbearne@… added
- Severity changed from normal to major
- Type changed from enhancement to defect (bug)
comment:2
SergeyBiryukov
— 8 months ago
- Type changed from defect (bug) to enhancement
Related: #16379
comment:3
jpyper
— 7 months ago
- Cc jarrod@… added
What about instead putting a filter on the arguments for the wp_dropdown_pages call that produces the list of pages to choose from (line 96 in wp-admin/options-reading.php)? A developer could then use :
function filter_my_cpt($args) {
$args[post_type] = 'cpt-slug';
to also maintain pages: $args[post_type] = 'pages, cpt-slug'
}
add_filter('options-front-page' , filter_my_cpt');
add_filter('options-posts-page' , filter_my_cpt');
comment:4
pbearne
— 7 months ago
Yes feels that it would work
wp_dropdown_pages() call's get_pages() just passing the args through and get_pages() takes in post_type
And if we update the custom post/page type page to inform how to add this
I don't see the need to add it to the posts page as this is just a place holder so remove that from the code.
Added (untested) code to make the filter work with any number of filters so that this call can be part of custom post/page type page setups.
function filter_my_cpt($args) {
// pass through current value if any to allow for other filters
if(count($args[post_type])>0){
$args[post_type] = array_push($args[post_type],'cpt-slug');
}else{
$args[post_type] = 'cpt-slug';
}
}
add_filter('options-front-page' , filter_my_cpt');
so the change to options-reading.php would just a filter around the front page $args array
I that feel we should break this out a bit to make readable but this looks like the code we need.
117<ul>
<li><label for="page_on_front"><?php printf( __( 'Front page: %s' ), wp_dropdown_pages(apply_filters('options-front-page', array( 'name' => 'page_on_front', 'echo' => 0, 'show_option_none' => __( '— Select —' ), 'option_none_value' => '0', 'selected' => get_option( 'page_on_front' ) ) ) ) ); ?></label></li>
<li><label for="page_for_posts"><?php printf( __( 'Posts page: %s' ), wp_dropdown_pages( array( 'name' => 'page_for_posts', 'echo' => 0, 'show_option_none' => __( '— Select —' ), 'option_none_value' => '0', 'selected' => get_option( 'page_for_posts' ) ) ) ); ?></label></li>
</ul>
Does this all make sense?
Paul
comment:5
jpyper
— 7 months ago
Yes, that's a better idea for a function to utilize the filter and makes sense to me.
comment:6
jpyper
— 7 months ago
I was doing some testing and I think I see a further problem. WP doesn't seem to properly handle having a CPT as the front page in some aspects.
For instance, the url for the front page doesn't get changed to just website.com, it's website.com/post-type/post-slug. Same goes for when a link to the new "front page" is placed in a menu. Normally the link is changed to just be website.com but it keeps it's full URL.
Part of that problem seems to be in /wp-admin/includes/nav-menu.php about line 726. It checks for a post type name of 'page' before changing the url out for menus. I haven't found where it does the URL change for the URL of the front of the site.
comment:8
pbearne
— 7 months ago
We could just reverse this
if ( 'page' == $post_type_name ) {
becomes
if ( 'post' != $post_type_name ) {
and let the
if ( ! empty( $front_page ) ) {
do it's stuff for all the menu types but this would mean that the code will run more than needed
So the other way would to do a look-up for the page type that is used for the home page test for that setting 'page' as the default as we might not get anything back
$front_page_type = 'page' == get_option('show_on_front') ?
get_post_type((int) get_option( 'page_on_front' )) : 'page';
if($front_page_type == $post_type_name ){
...
If this works it's better and cover all the bases
or this might be even better
$front_page_type = 'page' == get_option('show_on_front') ?
get_post_type((int) get_option( 'page_on_front' )) : null;
if($front_page_type == $post_type_name ){
...
Paul
comment:9
pbearne
— 7 months ago
Hi
I have done some work on this but have not sorted the URL code
So I am just pasting the patch for now
Index: wp-admin/options-reading.php
===================================================================
--- wp-admin/options-reading.php (revision 22831)
+++ wp-admin/options-reading.php (working copy)
@@ -114,7 +114,7 @@
</label>
</p>
<ul>
- <li><label for="page_on_front"><?php printf( __( 'Front page: %s' ), wp_dropdown_pages( array( 'name' => 'page_on_front', 'echo' => 0, 'show_option_none' => __( '— Select —' ), 'option_none_value' => '0', 'selected' => get_option( 'page_on_front' ) ) ) ); ?></label></li>
+ <li><label for="page_on_front"><?php printf( __( 'Front page: %s' ), wp_dropdown_pages( apply_filters('options-front-page',array( 'name' => 'page_on_front', 'echo' => 0, 'show_option_none' => __( '— Select —' ), 'option_none_value' => '0', 'selected' => get_option( 'page_on_front' ) ) ) ) ); ?></label></li>
<li><label for="page_for_posts"><?php printf( __( 'Posts page: %s' ), wp_dropdown_pages( array( 'name' => 'page_for_posts', 'echo' => 0, 'show_option_none' => __( '— Select —' ), 'option_none_value' => '0', 'selected' => get_option( 'page_for_posts' ) ) ) ); ?></label></li>
</ul>
<?php if ( 'page' == get_option( 'show_on_front' ) && get_option( 'page_for_posts' ) == get_option( 'page_on_front' ) ) : ?>
Index: wp-includes/post.php
===================================================================
--- wp-includes/post.php (revision 22831)
+++ wp-includes/post.php (working copy)
@@ -3628,9 +3628,14 @@
$number = (int) $number;
$offset = (int) $offset;
- // Make sure the post type is hierarchical
+ // Make sure we have a valid post type
+ if ( !is_array( $post_type ) )
+ $post_type = explode( ',', $post_type );
+ if ( array_diff( $post_type, get_post_types() ) )
+ return $pages;
+ // Make sure the all post types are hierarchical
$hierarchical_post_types = get_post_types( array( 'hierarchical' => true ) );
- if ( !in_array( $post_type, $hierarchical_post_types ) )
+ if ( array_intersect( $post_type, $hierarchical_post_types ) == count($post_type) )
return $pages;
// Make sure we have a valid post status
@@ -3733,11 +3738,19 @@
if ( $parent >= 0 )
$where .= $wpdb->prepare(' AND post_parent = %d ', $parent);
+ // Check if post_type is an array so that Custom Page types can be added to dropdowns and lists
+ if ( 1 == count( $post_type ) ) {
+ $where_post_type = $wpdb->prepare("post_type = %s" , array_shift( $post_type ) );
+ } else{
+ $post_type = implode( "', '", $post_type );
+ $where_post_type = "post_type IN ('$post_type')";
+ }
+
if ( 1 == count( $post_status ) ) {
- $where_post_type = $wpdb->prepare( "post_type = %s AND post_status = %s", $post_type, array_shift( $post_status ) );
+ $where_post_type .= $wpdb->prepare( " AND post_status = %s", array_shift( $post_status ) );
} else {
$post_status = implode( "', '", $post_status );
- $where_post_type = $wpdb->prepare( "post_type = %s AND post_status IN ('$post_status')", $post_type );
+ $where_post_type .= "AND post_status IN ('$post_status')" ;
}
$orderby_array = array();
the test functions I used where
add_action( 'init', 'create_post_type' );
function create_post_type() {
register_post_type( 'acme_product',
array(
'labels' => array(
'name' => __( 'tests' ),
'singular_name' => __( 'test' )
),
'public' => true,
'has_archive' => true,
'rewrite' => array('slug' => 'tests'),
)
);
}
function filter_my_cpt($args) {
$args['post_type'] = array('page', 'acme_product');
return $args;
}
add_filter('options-front-page' , 'filter_my_cpt');
I will look at the URl code later
And I want to look getting this into the register_post_type() call
comment:10
pbearne
— 7 months ago
I see the bug on the menus I will need to be look for if there is a set home page and then test for that post type add add the Home: XXXXX to the correct list
comment:11
follow-up:
↓ 12
SergeyBiryukov
— 7 months ago
You should attach the patch as a file instead of pasting it in the comment box.
comment:12
in reply to:
↑ 11
pbearne
— 7 months ago
Replying to SergeyBiryukov:
You should attach the patch as a file instead of pasting it in the comment box.
even if its not complete?
I have more work to do before finished.
comment:13
SergeyBiryukov
— 7 months ago
Yes, just leave a note about what's already implemented and what else needs to be done.
It's easier to follow the discussions and development when patches are in separate files.
comment:14
pbearne
— 7 months ago
Just added a patch this works OK but WP has "page" hard coded in a few places so I need to provide patch's so that we do a look-up for the page type for the home page see nav-menu.php line 729 and jpyper comment above for example.
We also need to find and recode the rewrite rule that hides the path/filename when loading a homepage
I also what to have look at what changes would be needed to make this a switch in the register_post_type function and not a extra filter step
And it would be good to check that we keep "page" in the $args!['post_type'!] array
comment:15
pbearne
— 7 months ago
Notes to self
check that removing $wpdb->prepare have I broken SQL santation
this looks OK as we check for valid values before using them
check this 3639
if ( array_intersect( $post_type, $hierarchical_post_types ) == count($post_type) )
return $pages;
this should be a not the same return need to check the output of array_intersect maybe use array_diff
comment:16
pbearne
— 7 months ago
- Summary changed from Allow custom post types as "home" to Allow custom post types as "home" and get_posts() to return results for more than one post type
comment:17
pbearne
— 7 months ago
- Keywords has-patch needs-testing needs-codex added
This now all works
Apart from if a custom post type is set as a home page it does get servered as the root page eg. Domain.com rather at the URL of domain.com/customPostType/pagename the code for this looks like its somewhere in query.php so might be better if someone else who knows that code looks at that.
And I haven't add code to register_post_type make this a feature but will look at that this week
comment:18
toscho
— 7 months ago
- Cc info@… added
comment:19
wpsmith
— 6 months ago
- Cc travis@… added
comment:20
SergeyBiryukov
— 6 months ago
#23100 was marked as a duplicate.
comment:21
pbearne
— 5 months ago
Hi All
I need a bit of help to finish this
I have one last bug and need a code review as the function I added to options-reading needs to be move to better location.
The bug: WordPress doesn't render the custom page at the root all I am getting the 404 page
if you look at line 109 in query.php you will see I have remove the hardcoded "page" and pass in the current page type.
Without this change the custom page loads but with the URL of /pagetype/pagename and not at the root /
With this change I am getting the 404 so there is an additional change needed somewhere
I am sure that this will come back for some rework on variable name etc.
use this function to test, Note the 'show_in_home_page_list'=> true, which how I am declaring that this custom post should be added to the list
add_action( 'init', 'create_post_type' );
function create_post_type() {
register_post_type( 'acme_product',
array(
'labels' => array(
'name' => __( 'tests' ),
'singular_name' => __( 'test' )
),
'public' => true,
'has_archive' => true,
'rewrite' => array('slug' => 'tests'),
'hierarchical' => true,
'show_in_home_page_list'=> true,
)
);
}
I have tried to remove all the hard code strings so in itself will an improvement.
All and any help to finish this gratefully accepted.
comment:22
navjotjsingh
— 3 months ago
- Cc navjotjsingh@… added
This is needed or / and an option to push / block it in the custom post type config / setup