From 46b701d830e6172091d8aab486a97cbd741e1058 Mon Sep 17 00:00:00 2001 From: Ryan Boren Date: Mon, 1 Feb 2010 23:12:26 +0000 Subject: [PATCH] Permalinks for custom post types. Props prettyboymp. see #9674 git-svn-id: https://develop.svn.wordpress.org/trunk@12923 602fd350-edb4-49c9-b593-d223f7449a82 --- wp-includes/classes.php | 53 ++++++++++++++++++++++------------- wp-includes/link-template.php | 41 ++++++++++++++++++++++++++- wp-includes/post.php | 49 ++++++++++++++++++++++++++++---- 3 files changed, 116 insertions(+), 27 deletions(-) diff --git a/wp-includes/classes.php b/wp-includes/classes.php index 62fbee2c13..f804cebaa6 100644 --- a/wp-includes/classes.php +++ b/wp-includes/classes.php @@ -26,7 +26,7 @@ class WP { * @access public * @var array */ - var $public_query_vars = array('m', 'p', 'posts', 'w', 'cat', 'withcomments', 'withoutcomments', 's', 'search', 'exact', 'sentence', 'debug', 'calendar', 'page', 'paged', 'more', 'tb', 'pb', 'author', 'order', 'orderby', 'year', 'monthnum', 'day', 'hour', 'minute', 'second', 'name', 'category_name', 'tag', 'feed', 'author_name', 'static', 'pagename', 'page_id', 'error', 'comments_popup', 'attachment', 'attachment_id', 'subpost', 'subpost_id', 'preview', 'robots', 'taxonomy', 'term', 'cpage'); + var $public_query_vars = array('m', 'p', 'posts', 'w', 'cat', 'withcomments', 'withoutcomments', 's', 'search', 'exact', 'sentence', 'debug', 'calendar', 'page', 'paged', 'more', 'tb', 'pb', 'author', 'order', 'orderby', 'year', 'monthnum', 'day', 'hour', 'minute', 'second', 'name', 'category_name', 'tag', 'feed', 'author_name', 'static', 'pagename', 'page_id', 'error', 'comments_popup', 'attachment', 'attachment_id', 'subpost', 'subpost_id', 'preview', 'robots', 'taxonomy', 'term', 'cpage', 'post_type'); /** * Private query variables. @@ -144,7 +144,7 @@ class WP { // Fetch the rewrite rules. $rewrite = $wp_rewrite->wp_rewrite_rules(); - if (! empty($rewrite)) { + if ( ! empty($rewrite) ) { // If we match a rewrite rule, this will be cleared. $error = '404'; $this->did_permalink = true; @@ -203,12 +203,11 @@ class WP { // If the requesting file is the anchor of the match, prepend it // to the path info. - if ((! empty($req_uri)) && (strpos($match, $req_uri) === 0) && ($req_uri != $request)) { + if ( (! empty($req_uri)) && (strpos($match, $req_uri) === 0) && ($req_uri != $request) ) $request_match = $req_uri . '/' . $request; - } - if (preg_match("#^$match#", $request_match, $matches) || - preg_match("#^$match#", urldecode($request_match), $matches)) { + if ( preg_match("#^$match#", $request_match, $matches) || + preg_match("#^$match#", urldecode($request_match), $matches) ) { // Got a match. $this->matched_rule = $match; @@ -225,10 +224,10 @@ class WP { // If we're processing a 404 request, clear the error var // since we found something. - if (isset($_GET['error'])) + if ( isset($_GET['error']) ) unset($_GET['error']); - if (isset($error)) + if ( isset($error) ) unset($error); break; @@ -236,14 +235,14 @@ class WP { } // If req_uri is empty or if it is a request for ourself, unset error. - if (empty($request) || $req_uri == $self || strpos($_SERVER['PHP_SELF'], 'wp-admin/') !== false) { - if (isset($_GET['error'])) + if ( empty($request) || $req_uri == $self || strpos($_SERVER['PHP_SELF'], 'wp-admin/') !== false ) { + if ( isset($_GET['error']) ) unset($_GET['error']); - if (isset($error)) + if ( isset($error) ) unset($error); - if (isset($perma_query_vars) && strpos($_SERVER['PHP_SELF'], 'wp-admin/') !== false) + if ( isset($perma_query_vars) && strpos($_SERVER['PHP_SELF'], 'wp-admin/') !== false ) unset($perma_query_vars); $this->did_permalink = false; @@ -256,17 +255,21 @@ class WP { if ( $t->query_var ) $taxonomy_query_vars[$t->query_var] = $taxonomy; - for ($i=0; $ipublic_query_vars); $i += 1) { + foreach ( $GLOBALS['wp_post_types'] as $post_type => $t ) + if ( $t->query_var ) + $post_type_query_vars[$t->query_var] = $post_type; + + for ( $i = 0; $i < count($this->public_query_vars); $i += 1 ) { $wpvar = $this->public_query_vars[$i]; - if (isset($this->extra_query_vars[$wpvar])) + if ( isset($this->extra_query_vars[$wpvar]) ) $this->query_vars[$wpvar] = $this->extra_query_vars[$wpvar]; - elseif (isset($GLOBALS[$wpvar])) + elseif ( isset($GLOBALS[$wpvar]) ) $this->query_vars[$wpvar] = $GLOBALS[$wpvar]; - elseif (!empty($_POST[$wpvar])) + elseif ( !empty($_POST[$wpvar]) ) $this->query_vars[$wpvar] = $_POST[$wpvar]; - elseif (!empty($_GET[$wpvar])) + elseif ( !empty($_GET[$wpvar]) ) $this->query_vars[$wpvar] = $_GET[$wpvar]; - elseif (!empty($perma_query_vars[$wpvar])) + elseif ( !empty($perma_query_vars[$wpvar]) ) $this->query_vars[$wpvar] = $perma_query_vars[$wpvar]; if ( !empty( $this->query_vars[$wpvar] ) ) { @@ -274,14 +277,24 @@ class WP { if ( in_array( $wpvar, $taxonomy_query_vars ) ) { $this->query_vars['taxonomy'] = $taxonomy_query_vars[$wpvar]; $this->query_vars['term'] = $this->query_vars[$wpvar]; + } elseif ( in_array( $wpvar, $post_type_query_vars ) ) { + $this->query_vars['post_type'] = $post_type_query_vars[$wpvar]; + $this->query_vars['name'] = $this->query_vars[$wpvar]; } } } + // Limit publicly queried post_types to those that are publicly_queryable + if ( isset( $this->query_vars['post_type']) ) { + $queryable_post_types = get_post_types( array('publicly_queryable' => true) ); + if ( ! in_array( $this->query_vars['post_type'], $queryable_post_types ) ) + unset( $this->query_vars['post_type'] ); + } + foreach ( (array) $this->private_query_vars as $var) { - if (isset($this->extra_query_vars[$var])) + if ( isset($this->extra_query_vars[$var]) ) $this->query_vars[$var] = $this->extra_query_vars[$var]; - elseif (isset($GLOBALS[$var]) && '' != $GLOBALS[$var]) + elseif ( isset($GLOBALS[$var]) && '' != $GLOBALS[$var] ) $this->query_vars[$var] = $GLOBALS[$var]; } diff --git a/wp-includes/link-template.php b/wp-includes/link-template.php index 7e094851de..fabb50efeb 100644 --- a/wp-includes/link-template.php +++ b/wp-includes/link-template.php @@ -104,8 +104,10 @@ function get_permalink($id = 0, $leavename = false) { if ( $post->post_type == 'page' ) return get_page_link($post->ID, $leavename, $sample); - elseif ($post->post_type == 'attachment') + elseif ( $post->post_type == 'attachment' ) return get_attachment_link($post->ID); + elseif ( in_array($post->post_type, get_post_types( array('_builtin' => false) ) ) ) + return get_post_link($post); $permalink = get_option('permalink_structure'); @@ -159,6 +161,43 @@ function get_permalink($id = 0, $leavename = false) { } } +/** + * Retrieve the permalink for a post with a custom post type. + * + * @since 3.0.0 + * + * @param int $id Optional. Post ID. + * @param bool $leavename Optional, defaults to false. Whether to keep post name. + * @param bool $sample Optional, defaults to false. Is it a sample permalink. + * @return string + */ +function get_post_link( $id = 0, $leavename = false, $sample = false ) { + global $wp_rewrite; + + $post = &get_post($id); + + if ( is_wp_error( $post ) ) + return $post; + + $post_link = $wp_rewrite->get_extra_permastruct($post->post_type); + + $slug = $post->post_name; + + if ( !empty($post_link) && ( ( isset($post->post_status) && 'draft' != $post->post_status && 'pending' != $post->post_status ) || $sample ) ) { + $post_link = ( $leavename ) ? $post_link : str_replace("%$post->post_type%", $slug, $post_link); + $post_link = home_url( user_trailingslashit($post_link) ); + } else { + $post_type = get_post_type_object($post->post_type); + if ( $post_type->query_var && ( isset($post->post_status) && 'draft' != $post->post_status && 'pending' != $post->post_status ) ) + $post_link = "?$post_type->query_var=$slug"; + else + $post_link = "?post_type=$post->post_type&p=$post->ID"; + $post_link = home_url($post_link); + } + + return apply_filters('post_type_link', $post_link, $id); +} + /** * Retrieve permalink from post ID. * diff --git a/wp-includes/post.php b/wp-includes/post.php index b4599abdca..8cba327e41 100644 --- a/wp-includes/post.php +++ b/wp-includes/post.php @@ -16,20 +16,26 @@ */ function create_initial_post_types() { register_post_type( 'post', array( 'label' => __('Posts'), + 'publicly_queryable' => true, 'exclude_from_search' => false, '_builtin' => true, '_edit_link' => 'post.php?post=%d', 'capability_type' => 'post', 'hierarchical' => false, + 'rewrite' => false, + 'query_var' => false, 'supports' => array('post-thumbnails', 'excerpts', 'trackbacks', 'custom-fields', 'comments', 'revisions') ) ); register_post_type( 'page', array( 'label' => __('Pages'), + 'publicly_queryable' => true, 'exclude_from_search' => false, '_builtin' => true, '_edit_link' => 'post.php?post=%d', 'capability_type' => 'page', 'hierarchical' => true, + 'rewrite' => false, + 'query_var' => false, 'supports' => array('post-thumbnails', 'page-attributes', 'custom-fields', 'comments', 'revisions') ) ); @@ -38,7 +44,9 @@ function create_initial_post_types() { '_builtin' => true, '_edit_link' => 'media.php?attachment_id=%d', 'capability_type' => 'post', - 'hierarchical' => false + 'hierarchical' => false, + 'rewrite' => false, + 'query_var' => false, ) ); register_post_type( 'revision', array( 'label' => __('Revisions'), @@ -46,7 +54,9 @@ function create_initial_post_types() { '_builtin' => true, '_edit_link' => 'revision.php?revision=%d', 'capability_type' => 'post', - 'hierarchical' => false + 'hierarchical' => false, + 'rewrite' => false, + 'query_var' => false, ) ); register_post_status( 'publish', array( 'label' => _x('Published', 'post'), @@ -686,7 +696,8 @@ function get_post_types( $args = array(), $output = 'names' ) { * * label - A descriptive name for the post type marked for translation. Defaults to $post_type. * public - Whether posts of this type should be shown in the admin UI. Defaults to false. - * exclude_from_search - Whether to exclude posts with this post type from search results. Defaults to true. + * exclude_from_search - Whether to exclude posts with this post type from search results. Defaults to true if the type is not public, false if the type is public. + * publicly_queryable - Whether post_type queries can be performed from the front page. Defaults to whatever public is set as. * inherit_type - The post type from which to inherit the edit link and capability type. Defaults to none. * capability_type - The post type to use for checking read, edit, and delete capabilities. Defaults to "post". * hierarchical - Whether the post type is hierarchical. Defaults to false. @@ -701,19 +712,27 @@ function get_post_types( $args = array(), $output = 'names' ) { * @param array|string $args See above description. */ function register_post_type($post_type, $args = array()) { - global $wp_post_types; + global $wp_post_types, $wp_rewrite, $wp; - if (!is_array($wp_post_types)) + if ( !is_array($wp_post_types) ) $wp_post_types = array(); // Args prefixed with an underscore are reserved for internal use. - $defaults = array('label' => false, 'exclude_from_search' => true, '_builtin' => false, '_edit_link' => 'post.php?post=%d', 'capability_type' => 'post', 'hierarchical' => false, 'public' => false, '_show' => false, 'supports' => array()); + $defaults = array('label' => false, 'publicly_queryable' => null, 'exclude_from_search' => null, '_builtin' => false, '_edit_link' => 'post.php?post=%d', 'capability_type' => 'post', 'hierarchical' => false, 'public' => false, '_show' => false, 'rewrite' => true, 'query_var' => true, 'supports' => array()); $args = wp_parse_args($args, $defaults); $args = (object) $args; $post_type = sanitize_user($post_type, true); $args->name = $post_type; + // If not set, default to the setting for public. + if ( null === $args->publicly_queryable ) + $args->publicly_queryable = $args->public; + + // If not set, default to true if not public, false if public. + if ( null === $args->exclude_from_search ) + $args->exclude_from_search = !$args->public; + if ( false === $args->label ) $args->label = $post_type; @@ -735,6 +754,24 @@ function register_post_type($post_type, $args = array()) { unset($args->supports); } + if ( false !== $args->query_var && !empty($wp) ) { + if ( true === $args->query_var ) + $args->query_var = $post_type; + $args->query_var = sanitize_title_with_dashes($args->query_var); + $wp->add_query_var($args->query_var); + } + + if ( false !== $args->rewrite && '' != get_option('permalink_structure') ) { + if ( !is_array($args->rewrite) ) + $args->rewrite = array(); + if ( !isset($args->rewrite['slug']) ) + $args->rewrite['slug'] = $post_type; + if ( !isset($args->rewrite['with_front']) ) + $args->rewrite['with_front'] = true; + $wp_rewrite->add_rewrite_tag("%$post_type%", '([^/]+)', $args->query_var ? "{$args->query_var}=" : "post_type=$post_type&name="); + $wp_rewrite->add_permastruct($post_type, "/{$args->rewrite['slug']}/%$post_type%", $args->rewrite['with_front']); + } + $wp_post_types[$post_type] = $args; return $args;