I’d like to add a page that does not appear anywhere on the site (especially not in the header or wherever your pages are listed) unless the URL is typed in directly. Additionally, the page/post should be password-protected.
I know how to add a password, but I found no way to remove the page from being listed.
Hi @mafutrct:
There are a lot of ways to do this; picking one is actually the challenge! I’m going to suggest a few options and let you explore (the ones at the top look most promising):
I’m assuming your are using
wp_list_pages()
for your menus? If so consider moving to the new menus in v3.0 where you’ll get full control of what appears in those menus:By design, wordpress does not have a property per post or page that would signal the application to not use the page in queries of the standard controller
WP_Query
as you asked for.However, it’s not that this scenario is something too far away. Let’s look what wordpress has to offer instead.
WordPress Post Statuses
Posts can have some status, or more precisely, they have a status. That is what you might know already. I list them with their string identifier, their naming and context if any. Every post has one of these:
publish
(Published, post)future
(Scheduled, post)draft
(Draft, post)pending
(Pending, post)private
(Private, post)trash
(Trash, post)auto-draft
(auto-draft)inherit
(inherit)Next to those, you can register your own post status. The API function to do that is called
register_post_status()
(WordPress Codex) which is an undocumented function. You find it documented into source:register_post_status()
(WordPress Source). To get a post’s status, you can use theget_post_status()
(WordPress Codex) function.It’s not very well documented, I assume because the concept of post statuses was not introduced as a fixed feature set but on best try and then having a look. So expect this to be a bit fragile and it’s unknown if it can be used to actually solve your issue. But I would nevertheless stick to it, because it’s a built-in feature which is to be expected, like custom-post-types, to be integrated more and more with each release. CPT’s for example are not introduced since 2.8 IIRC and still not complete. It just takes some time.
This post status registration function is documented as being available since 3.0.0, so it’s quite new. It was introduced in 12719, related Ticket is #9674.
You can imagine, that the concept is not well integrated so far.
But it’s worth to take a look at that end, because it looks like it contains all ingredients which are important for your feature request. Post statuses have properties that are used in the controllers and models decisions to fetch content – that’s basically why you like to control. Let’s look what’s in before I continue with what’s not working / buggy:
TRUE
/FALSE
– Known to beTRUE
for Published posts. So post statuses with thepublic
-property set toTRUE
are assume to behave like published posts.TRUE
/FALSE
– Known to beTRUE
for Private posts. Comparable to thepublic
-property.TRUE
/FALSE
– Protected most certainly stands for “password protected”.TRUE
/FALSE
– Example for internal post statuses are: Trash; auto-draft and inherit.TRUE
/FALSE
– If not explicitly set, all public statuses are publicly queryable.TRUE
/FALSE
– Assumed to be like the property name suggests.TRUE
/FALSE
– Same.TRUE
/FALSE
– Same.TRUE
/FALSE
– Something special, probably worth to look into for your question.Those post status properties are not designed to work with each other. The concept more or less is that everyone of those is
FALSE
by default and you can set some for them toTRUE
. The data-structure in wordpress is a standard class with some global accessible properties. It is added to the$wp_post_statuses
global variable which acts like a singleton registry in the global namespace per request, ready to be used after init. So if you would like to see, what has been defined, add a hook at the end ofinit
for debugging purposes:With something like that you can see what’s in for the moment. As those are standard classes with public properties, nothing is guaranteeing data consistency here. So take care as usual with the wordpress API. Some of those most probably interfere with the functionality of others but how and when is only defined by code which is likely to change. Just take a bit care and double check with the source.
Limitations so far
So as it looks good so far to make use of post statuses, let’s take a look for the expected to be limitations this comes with.
The admin lacks of options to make own post states available in the publish box for example. that means, you need to either patch the existing display routine or create your own UI so far for it. Patching core might be more probable as it allows you to offer code for an existing feature request (Ticket #12567) and an own post edit meta box might be interactively be interfering with the concept of the publish box.
I suggest some lightweight patch to introduce a new filter that allows to change the listing of radios. The lighter your approach is, the more likely you will get this in. I smell that core developers fear a bit to introduce any changes to that part because of it’s complexitiy. So the less complex your changes are, the better this is.
Additionally, even if my list above suggest that there is some context for post or page, you can not setup a post status for a specific post type AFAIK. So expect that your post status is available to any custom post type as well or at least the behavior needs to be researched for any of those and properly tested on your concrete site.
So to learn about the deficiencies, it’s always good to peek what’s reported in trac to learn about limitations upfront. I do this by searching for the function name (and I use google to search trac next to trac search):
register_post_status
inline docs are inaccurateI think this will give you an image.
Defining your own Post Status
So one option might be to define your own post status. That would enable you to re-use existing status and their functionality (namely drafting and trashing) while maintaining your own type for your hiding purposes.
I would setup one as
public = TRUE;
but withpublicly_queryable = FALSE;
. Then I don’t know your needs regarding URL design, so using a numeric ID might be okay. This could short-circuit all the permalinks hassles this concept might have. Instead, if identified as single request with a numeric ID, you can introduce some code, that sets public_queryable to true on for the single request (single means here, the page-data is requested directly and not for a listing). Some pseudo code:Set within the right place which would be prior to the actual fetching of the models from the database but after you are able to identify the type of request (see WordPress 3.0 Program Flow (Toolpress PDF) with the need to trace hooks in WP_Query and related), this can work.
It would offer a quite lightweight integration for your feature while making use of core elements to integrate it. Probably some of the plugins listed by Mike are already making use of custom post statuses, so there would already be example code.
You can do this with the new Menu System, or you can exclude a page with Exclude Pages plugin and then add a Password to your Page.
But my opinion is to use the new Custom Menu system to include only the pages/categories you want and nothing else.