[Edit: I've added a more concrete example below]

I need to convert a custom PHP site to WordPress. The site has 60,000+ media items along with a ton of metadata, all of which needs to carry over to the new site. The media data is accessed via a local API and I've already figured out how to access the API in WordPress, so that's not a problem.

What I can't figure out is how to write a plugin so that

  1. the URL parameters determine what to show (ideally via mod_rewrite); and
  2. how and where to expose the plugin in WordPress.

In other words, how can I write a plugin so that the URLs /albums/12345 or /authors/23456 resolve to pages showing only the correct content?

I would be really happy for a simple RTFM, if you can tell me where in the documentation to look. It's been about 10 years since I last did anything with WP, so everything is pretty new to me now. I'm not even sure where to look.

Edit Here's a more concrete example:

Say I want to put up a constantly updating podcast feed from RSS, or a list of Tweets from the Twitter API or something like that. Basically the source is accessed by a well-defined API (and I can easily handle the logic to load, parse and format that stuff); the data is all there, ready for reading.

What do I need to do to have that content show up in response to specific URL requests?

For example, if someone goes to /podcasts/pages/1, how do I make the page content show the first page of podcast titles. And if they go to /podcasts/items/oct-31-2015-wordpress, how do I get the podcast metadata to show up?

Do I use an action or filter? What hooks do I need to use? Do I use a custom post type instead?

  • 1
    I guess the add_rewrite_rule() might help here, though I'm not sure what you're looking for specifically. A more detailed example might help others answering this? Here's an article in the Codex on how to write a plugin if that helps regarding part 2.
    – birgire
    Commented Nov 8, 2015 at 10:18
  • Sorry. I will modify my question. I originally said '1. the URL parameters determine what to show (ideally via mod_rewrite)', but that's not actually important to this question (I will use mod_rewrite to make things more human-readable, but I'll figure out that later). I am more interested in how to intercept URL params and use them to build a custom 'page'.
    – Andrew
    Commented Nov 8, 2015 at 10:25
  • @birgire -- I should have mentioned that your suggestion actually will be useful to me later on. Thanks for that.
    – Andrew
    Commented Nov 8, 2015 at 10:29
  • Hopefully you can make progress on this. There's also the handy add_rewrite_endpoint(). Just remember to flush the rewrite rules (they're stored in the database) when testing the add_rewrite_* functions, e.g. by visiting the Permalinks settings page.
    – birgire
    Commented Nov 8, 2015 at 10:40
  • 1
    I am not sure to understand your question but it looks like you need to write a migrating script to import the 60k medias into the WP media library. Commented Nov 8, 2015 at 14:19

1 Answer 1


There are a few approaches to this that could work. If you look around here for questions regarding "virtual pages" you might find some options that could work for you.

One quick way to implement this-

1) Create a page under Pages in WordPress admin. This will be the page that's loaded in the main query, and will be used as the target for rewrite rules you'll add later. The content of the page isn't important, you don't need to output it if you don't want to, it's just so that WordPress can successfully run a main query.

2) Add whatever query vars you'll need to extract data from the URLs. For example, album_id, podcast_id, etc.. Make sure they are sufficiently unique to not clash with WordPress's own query vars. There's a likely not complete list of those vars on the register taxonomy codex page. Example:

function wpd_my_query_vars( $qvars ) {
    $qvars[] = 'album_id';
    $qvars[] = 'podcast_id';
    return $qvars;
add_filter( 'query_vars', 'wpd_my_query_vars' , 10, 1 );

3) Add the rewrite rules you need for the various requests you want to serve. Your rules will target the page you created in step 1, and set the query vars you added in step 2. Example:

function wpd_rewrite_rules(){
add_action( 'init', 'wpd_rewrite_rules', 10, 0 );

Note that rewrite rules need to be flushed whenever new rules are added. You can also do this by visiting the Settings > Permalinks page in admin.

4) This last step is optional. You could handle all of these types of requests with a single page template. If you want to separate the various requests into their own templates, add a filter to page_template to load a different one for each. Note that WordPress sees all of these requests as the single page you targeted, and is otherwise unable to detect any other differences on its own that you've created with your own rules and query vars. Example:

function wpd_page_template( $template = '' ) {
    global $wp_query;
    if( ! array_key_exists( 'album_id', $wp_query->query_vars ) ) return $template;

    $template = locate_template( 'album-template.php' );
    return $template;
add_filter( 'page_template', 'wpd_page_template' );

You can expand this to check for the presence of various query vars you've added in order to load other templates. You can access your custom query vars directly from $wp_query as above, or if you're morally opposed to globals, with get_query_var. You can also target this filter to just one page or array of pages via the is_page conditional tag.

There may be a few other bits you want to clean up in this approach. For example, you may want to remove rel_canonical from the wp_head action on these pages, and add your own function to output canonical meta tags for this content.

  • after some experimentation, this is exactly what I need. Thank you. Can you think of any way to make this so that I don't need to depend on a hard-coded post id? I can't imagine having to keep dev, staging and production in sync. I suppose I can query the database for a title to find the ID and set that as an environment variable (or some other static global).
    – Andrew
    Commented Nov 9, 2015 at 3:15
  • You can set pagename to a page slug instead of page_id, it's just a bit slower than looking up a page by ID. You could also grab the ID from an option to use when the rules are generated, so you could change it by updating the option value without having to touch the code.
    – Milo
    Commented Nov 9, 2015 at 3:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.