WordPress lumps posts and static pages together in one database table, but they need to be handled quite differently.
At least for the time being, I’m leaving them in the same table.
First, in the Post
model, a different permalink is needed for static pages and for posts:
def permalink
if post_type == 'page'
post_name
else
post_date.strftime("%Y/%m/%d") + (post_name.empty? ? '' : "/#{post_name}")
end
end
Then, also in the Post
model, I have several scopes:
scope :published_posts, where(:post_status => 'publish', :post_type => 'post').order('post_date DESC')
scope :published_pages, where(:post_status => 'publish', :post_type => 'page')
scope :pages, where(:post_type => 'page')
scope :not_pages, where('post_type != page')
Then two different methods to find posts, depending on whether the user is logged in or not (see below):
def self.find_by_permalink(permalink)
if permalink !~ /\//
pages.find(:first, :conditions => ["post_name = ?", permalink])
else
year, month, day, name = permalink.split('/')
name ||= ''
not_pages.find(:first, :conditions => ["YEAR(post_date) = ? AND MONTH(post_date) = ? AND DAYOFMONTH(post_date) = ? AND post_name = ?", year.to_i, month.to_i, day.to_i, name])
end
end
def self.find_published_by_permalink(permalink)
if permalink !~ /\//
published_pages.find(:first, :conditions => ["post_name = ?", permalink])
else
year, month, day, name = permalink.split('/')
name ||= ''
published_posts.find(:first, :conditions => ["YEAR(post_date) = ? AND MONTH(post_date) = ? AND DAYOFMONTH(post_date) = ? AND post_name = ?", year.to_i, month.to_i, day.to_i, name])
end
end
Then, in PostController
, the show
method becomes a bit more advanced (or messy):
def show
# Show all posts if logged in, otherwise restrict to published posts
if User.find_by_ID(session[:user_id])
@post = Post.find_by_permalink(params[:id]) || not_found
else
@post = Post.find_published_by_permalink(params[:id])
if not @post
# Check if post _would_ be visible if logged in; ask to log in if so
if Post.find_by_permalink(params[:id])
session[:return_to] = request.url
redirect_to login_url, :notice => "Please log in"
return
else
not_found
end
end
end
...
end
The not_found
method is in ApplicationController
(see here):
def not_found
raise ActionController::RoutingError.new('Not Found')
end
routes.rb
needs to be changed, to route (say) .../about
to the appropriate page, with the following line going after all the other routing information (but before the root
statement):
resources :posts, :only => [:show, :update, :destroy, :edit], :path => '', :id => /\d{4}\/\d{2}\/\d{2}(\/[0-9a-z\-_]+)?|[0-9a-z\-_]+/
And there are some changes to the post view, to hide details that are not relevant to static pages (such as date and comments).