nav-left cat-right
cat-right

An Exercise in WordPress Integration, or Why WordPress Sucks

I'd like to prefix my upcoming rant with the fact that WordPress is good at what it does: making basic blogs and publishing content. I use it, many other people use it, it works. Heck, I'm using it right now. But from a technical standpoint, WordPress sucks. I'm going to relate my experience here trying write a quick function to store post output to a file, to be used by a separate application on the same server.

I started off to write a function (let's call it a caching function for simplicity) that stores some HTML from the most recently published post. Sounds easy enough. I should be able to just put a function into the functions.php file of the custom template set I'm using. That's seems to be where the "userland" custom functions go.

So I check the function reference first. Hey, wp_get_recent_posts(). Looks promising, so I give it a shot. It goes ahead and gets the most recent post just fine. Things are ok so far.

A problem appears

storm-at-sea

Now, I want to output the post exactly as it would appear in the blog, and save that output to a file on disk. Surely there's a basic function that will output a post's content? You know… take the post_content field from the database record and format it properly? Suddenly, the skies darken. Evil laughter booms out. Ha ha ha! WordPress mocks the folly of simplistic functional thinking!

The template files use functions like the_content() and the_title().  Just in case you can't tell from the excellent naming scheme, these actually produce echoed output. Checking out the_content(), we see it dutifully calls get_the_content(), then runs a couple of lines of formatting stuff on the results.  So how about using get_the_content() for my caching function? I could run the other few formatting bits manually after that. Should be ok, right? After all, the doc comment for get_the_content() says the following:

/**
* Retrieve the post content.
*

So, I can go ahead assume it simply retrieves the basic post content then? Ha ha. NO. WHY WOULD IT DO THAT? Instead, it takes a bunch of globals that get set who-the-hell-knows-where, runs through a bunch of crap seemingly unrelated to the content of a post, and does a whole lot of textual modifications to some kind of content. Reading through the function is like jabbing red-hot fire pokeys into your eyes. Here's a portion of it:

[php]$content = $pages[$page-1];
if ( preg_match('/<\!--more(.*?)?-->/', $content, $matches) ) {
$content = explode($matches[0], $content, 2);
if ( !empty($matches[1]) && !empty($more_link_text) )
$more_link_text = strip_tags(wp_kses_no_null(trim($matches[1])))

$hasTeaser = true;
}[/php]

$pages is some kind of global that doesn't seem to have any relation to a post. Then apparently we're looking for HTML comments of <!--more something -->, and replacing them with… well, something. I'd hate to think what would happen if I ever wrote a post with an HTML comment in it that happened to hit on whatever random content markers WordPress has decided to use. (Oh wait! That just happened to me while I was trying to publish the above code fragment!) I didn't even bother to look into things like wp_kses_no_null. It probably involves dark rituals with live chicken sacrifice. Why is there so much going on in a function called get_the_content()?

In the end, it seems that get_the_content() will eventually get the content of a post, but only if you set a half-a-dozen or so globals before you call it.  And what the hell post is it even getting?

"The Loop"

the-broken-chain1

Digging further, it's clear that the template functions for output are all like that. They don't take any kind of parameters; they just operate on globals! There's no way to take the post data that I just retrieved with wp_get_recent_posts(), and format it using these functions. You have to be in "The Loop" in order to do that. And "The Loop" sucks. It's not a catchy, easy-to-use method of handling posts, despite WordPress's efforts to pass it off as something neat or fun. It's a mish-mash of global functions with random naming and variable schemes (incidentally, just like the rest of WordPress). You can only use "The Loop" if you're accessing WordPress in a "normal", web-requested-and-template-loaded kind of way. It doesn't work if you're outside a template file (such as in functions.php before a template gets loaded).

So back to square one. Unfortunately, it appears that if I want to have the regular blog-formatted output, I need to harness "The Loop" somehow, and clearly you can't do that on your own (ie. outside of a template file) without knowing about every global variable in the system.

After some quick googling, I came across the query_posts() function, which you can use to set up "The Loop". Reading the documentation on it, you can find this little gem:

"The query_posts function overrides and replaces the main query for the page. To save your sanity, do not use it for any other purpose."

To paraphrase: "We've created a public API function that is pretty much useless except in a very specific page-dependent situation. Please enjoy how useless it is.  But don't use it."

The fact that there is a "main query" for a page is another indicator of just how global-happy WordPress is, and that in turn gives you an insight into why it has so many security holes. How do you keep track of so many globals across so many functions?

A solution… sort of.

Fortunately, the query_posts() doc page links to the WP_Query docs, which is marginally more helpful, and provides the path for a solution. Using WP_Query sets up the wacky global stuff necessary to use "The Loop", which means we can hack our way through to getting some formatted post content. While technically feasible, you have to emulate a bunch of $_REQUEST parameters to the query() method.  I ended up with this:

[php]function cacheMostRecentPost()
{
$featuredPosts = new WP_Query();
$featuredPosts->query('showposts=1');
while ($featuredPosts->have_posts())
{
$featuredPosts->the_post();
ob_start();
//do output with stuff like the_title() and the_content()
$str = ob_get_contents();
ob_end_clean();
//write $str to cache fragment
}
}

//set up hooks for this file when a post is changed or deleted
add_action('save_post', 'cacheMostRecentPost');
add_action('deleted_post', 'cacheMostRecentPost');
[/php]

So despite relying on a specific set up of incoming HTTP parameters (as a string) for the most part, at least you can pass paramters to the query if you know the right ones. In this case, "showposts=1" seems to be the total number of posts fetched, and they appear to come back ordered by posting date, most recent first. This works for what I want it to do, but guess what? It doesn't work if you try to run it anywhere that's not one of those action hooks, because "The Loop" overwrites all the globals necessary for doing output later! So I can't use that function, say, at the top of the index.php template file if I wanted to. If I do, thanks to the overwritten globals, WordPress decides that I actually want the "Archive" page instead of the index page(!), and switches templates accordingly. So while I achieved my goal of being able to cache a post to a file with this function, it's certainly not portable, and it's certainly not elegant.

Wharrgarbl

wharrgarbl

The entire code flow is mind-boggling. Basing the output functions around a bunch of globals reminds me of code someone would have written in PHP 3 a decade ago, or something a very inexperienced programmer would write. Definitely not something you would expect in an application used by what is probably now millions of people. What's wrong with having some data fetching functions, and some output functions? You could, and I know I'm talking crazy here, but you could fetch some data, and then pass it to the output functions. Then (bear with me here), you could probably fetch posts (or whatever) at any time, and get some formatted output at any time, without overwriting some important global that might be used later in the code flow. Revolutionary, I know. Sorry if I went too fast on that. I'll repeat it louder and/or slower for any WordPress core developers that happen to be reading.

So, WordPress? How about something like:

$postObjects = getRecentPostsByDate(1);
$output = formatPostContent($postObject[0]);

The mere concept of having individual posts exist inside their own little encapsulated world would make the APIs a hundred times more useful (and easier to understand). You could even keep those crap the_title() and the_content() and the_something_lol_naming_scheme_lol() functions if you wanted. Just make them take parameters. Better yet, put them inside a formatting object, or even the post object itself. $post->the_content() would still work, but it would have context!

The reason this gets me worked up is not that it's so frustrating to use (although that helps). I've had to deal with a lot of frustrating code in my career. It's more the fact that it's this kind of thing that gives PHP programmers a bad name. The code is just bad. The design is random. The API functions are random. The naming schemes are random. Functions don't do what their name (or their doc comment) indicates they should do. Integrating wordpress into another application or site is next to impossible (try it, I dare you), and the other way around, integrating another application or site into wordpress is much more difficult than it should be. Global usage is rampant and ridiculous to follow.

You don't have to look any farther than a single WordPress code file to understand why there have been so many security holes over the last couple of years. And there's a lot of PHP code out there that's the quality of WordPress, or worse.

To re-iterate my opening, if you don't need to get anything special out of it, WordPress does the job. They've filled their market niche well, and it's encouraging that development is ongoing and releases occur often. I've worked with it on occasion over the last few years, and the improvements are obvious, interface-wise especially, and to some extent code-wise as well (the WP_Query object is a step forward).  But working with the code is not fun.  Even modifying the template files is an exercise in counter-intuitiveness.

I'm sure there are reasons the code is what it is at this point, and I'm equally as sure I don't have the full picture to go with my condemnations. I guess I should just be thankful that I don't have to maintain it.

Be Sociable, Share!

42 Responses to “An Exercise in WordPress Integration, or Why WordPress Sucks”

  1. AMB says:

    Great post. I am dealing with my own WordPress frustrations right now. Something you left out is how almost all the documentation out there is written for total n00bs and says stuff in it like:

    "There are four fields and a button that make up your
    garden-variety WordPress comment form: Name, Email,
    Website, Comment, and Submit. Seems easy enough, but
    the HTML markup for such forms is some of the most
    verbose and strange HTML imaginable."

    Um, if you find forms verbose and strange perhaps you shouldn't be building friggin websites, and you definitely shouldn't be writing books about anything to do with web development. Reading almost any WordPress tutorial is an exercise in intellectual regression.

  2. jake says:

    So what (free) open source CMS / Blogging alternative would you suggest?

    I have come to grips with WordPress (more or less) out of necessity as a GUI designer with constant need to deliver complete solutions without relying on coders or commercial solutions.

    But I am all ears if there is another solution you can recommend?

    cheers

    jake

  3. Andrew says:

    It sounds to me as though you might enjoy Habari.

    Habari is a much newer system that would make far more sense to you.

  4. Aaron Jorbin says:

    Doing what you want actually isn't that hard in wordpress. You can run the loop using an output buffer and that would give you the output exactly how you wanted it in a way that you could do anything you want with it.

    You alternatively could have your external script load the WordPress API (and thus make it easy for it to do it's own loop) by requiring wp-load.php (assuming your external script is a php script).

  5. While I agree that WordPress could be much more user friendly for beginners. I personally struggled with it for a while until I figured out what was going on and how to customize and installation. To simplify your example a bit, I would suggest that you read up on the get_posts() function for retrieval of post data.
    http://codex.wordpress.org/Template_Tags/get_posts

    And as for returning formatted content, this bit of code (used inside the loop) is the best possible solution that I can offer:

    $content = apply_filters( 'the_content', $post->content );

    The documentation on filters is a very important read as well.
    http://codex.wordpress.org/Plugin_API/Filter_Reference

    Best wishes,
    -Mike

  6. Ron says:

    I think the main 2 reasons for the functions with no parameters & no encapsulation/abstraction of posts/content are:

    -the functions perform the way they did when introduced into WordPress (ex. the_post() does what it always has) resulting in a theme from WP 1.X still working in WP 2.9 (with depreciated WP functionality).

    -the WP templating system makes it relatively easy for someone with HTML/CSS knowledge to build a theme without knowing or learning any programming.

    There are varying opinions on whether that's the best approach or not. From the 5 years I've been working with it, I would say the second reason has been the biggest contributing factor to the growth in WP usage as a web publishing platform.

  7. To be fair, this post made me a lol a little in my mouth. ;-)

    Really though… As a dev, you should be able to grok what the parameters are that can and should be passed to WP_Query. We haven't done a great job of making that well documented and if you weren't a dev, I'd understand your frustration…. but you are a dev and so I wonder why you're not able to do what I do all the time myself… refer to the code.

    Incidentally, you can use get_the_content() outside the loop. Feed it a post ID as a first argument.

    $post = get_the_content( 12345 );
    echo $post;

  8. Aaron get_the_content() doesn't work like that, which he clearly states in the beginning of the post. It uses globals which are set in the loop.
    Line 181 http://core.trac.wordpress.org/browser/trunk/wp-includes/post-template.php
    I'm curious as to where you get the idea that it can be used like you suggest. The code surely doesn't like it behave like that. There is no post or content retrieving code in the function other than the declaration of the globals. Which are not set in the function.
    I'm confused.

  9. You're right. My bad. I'd do…

    $post = get_post( 1234 );
    echo $post->post_content;

  10. jobob says:

    dude wordpress is mediocre at what it does at best. Yeah it's free, but that is no excuse. The only reason it is popular is because people who don't know how to put an echo statement in an html page can use it.

  11. Morgan says:

    Really though… As a dev, you should be able to grok what the parameters are that can and should be passed to WP_Query. We haven't done a great job of making that well documented and if you weren't a dev, I'd understand your frustration…. but you are a dev and so I wonder why you're not able to do what I do all the time myself… refer to the code.

    It sounds like you're saying that there is no excuse be frustrated with bad design if you're a dev. This just puts my back up, I'm sorry to say. Just because your target audience is developers is no excuse to write a poor API and force them to spend hours they shouldn't need to spend if your API was discoverable and intuitive.

    Sure, you can "refer to the code", but the point is that you shouldn't have to. The fact that you're doing it all the time yourself is irrelevant, and just means you're wasting time as well, being victimized by your own API. Your brushoff of this being a real problem lends incredible justification to this post.

  12. Tsalagi says:

    I had a good laugh while reading this article. Especially "Reading through the function is like jabbing red-hot fire pokeys into your eyes."

    Now I've became slightly disappointed reading this. I've spent the last 3 weeks picking and digging and learning the code of WordPress. The get_post, query_post and WP_Query post have been quite frustrating to learn because of the different methods and parameters each will take. Anyway, I picked WordPress specifically because it uses PHP as it's framework and that is my primary goal. To learn PHP. Now I'm thinking that I"m wasting my time or learning bad programming techniques. I'm also wondering if my ability to learn the code has to do with my learning curve or the way WordPress uses PHP.

    Now what? I enjoy the satisfaction when I get something to work in WordPress but it does seem to take a lot of digging. Is there any other program someone could suggest I work with to learn PHP? Feeling lost now.

  13. Tsalagi says:

    One other thought. Is learning a system like WordPress or Drupal or Joomla the best way to learn PHP?

  14. Well WordPress has bad code in it and some things are not that well thought out.
    If you want to see good PHP code you can look at another blogplatform called Habari habariproject.org. It ain't as usable as wordpress and not that popular though but the code is wonderful =).
    My suggestion if you want to learn to code is to start with a goal in mind. "I want to make a page that displays twitter posts and emails them to me" or something like that.
    Thats how I learn at least.

    Blogs to read
    http://planetozh.com/blog/
    http://markjaquith.wordpress.com/
    http://wptavern.com check the forum if you need help.

    Get the book: WordPress Plugin Development: Beginner’s Guide
    PHP Best practice: http://www.odi.ch/prog/design/php/guide.php

  15. c.cobb says:

    I too was hoping to learn PHP through using and modifying WP, and was looking forward to "Hacking the Loop," but after looking, it's definitely not something I want to clutter up my head with. At least I now have a blog to show for the effort.

    After over thirty years in Silicon Valley, I've seen (and written!) enough cr@p code for this lifetime, but have never seen more cr@p than in PHP. It's due to PHP lowering the entry bar such that any fool can start spewing code without bothering with the basics.

    Reminds me of something I heard long ago: If a person makes the effort to learn a martial art they usually learn the discipline to use it wisely along the way, while any fool can pick up a gun and create mayhem without any thought involved.

    Thank you for this post…it helped release some steam last night when trying to figure out a simple change to how author comments are displayed. Can't use existing methods on Post and Comment objects to compare the author's email…of course not! You have to use global functions. Except that the methods do work *some* of the time, just enough to tease you into thinking there may be solution if you keep looking. Not! Whadda mess.

    I will always from here on equate reading PHP code with "jabbing red-hot fire pokeys into [my] eyes." Cheers,

  16. Aaron Jorbin says:

    @c.cobb – If you think the code is so crappy, why don't you write a patch and try to improve it? As far as looking for author comments, the WordPress function wp_list_comments automatically adds the class "bypostauthor" to all comments by the post author, making it easy for you to style author comments differently.

  17. c.cobb says:

    Patch all existing PHP code? That defines a new level in Dante's Inferno, when what's lacking is a Tenth Circle for the willfully ignorant. And patching kludges built on hacks is not generally productive but merely compounds the error, as wp_list_comments so aptly demonstrates. At least WP looks nice on the outside and works well, but the end does not justify…etc.

  18. Denis says:

    Your post sounds like the story of my life as a WP dev… Even after 5 years of using it, I'm still amazed by the garbage code-base I end up using on a daily basis. It's sick that there are no other CMS' with a half-decent GUI around…

  19. Habari Enthusiast says:

    Welcome to Habari. I went through the same wrenching emotional turmoil when I abandoned WordPress a while back. Habari doesn't have everything I yet, but it's awesome and WordPress sucks.

  20. EnjoyCMS says:

    @Tsalagi Here is a user-friendly and fun way tp learn PHP
    http://www.mybboard.net/
    MyBB is primarily a forum, and it can also be a powerful, easy to use CMS.

  21. Blake, I totally agree with you, man.
    It seams that WP was coded by someone new to PHP and never heard about classes, objects, hierarchy, naming standards. The worst part is that it created a new (bad) way of coding. And most of the plugins are also crappy coded.

    Sure it's fine for people who doesn't have to customize it by hand. But for us, developers, it can become a nightmare most of the times.

  22. Joe Lee says:

    I agree with most of the comments above, WordPress is a great blogging system and the cost of the success is some bad design in this case. There is an opportunity cost of backwards compatibility and legacy in any system, the architectural decisions becomes even harder as time progresses so on one part I feel for the system designer.

    On the other hand, I have tried to do some basic customisation as well and damn it was painful!

    wordpress seems to me always meant to be "designer" friendly and I rarely find a sensual plugin in wordpress which is why I give up and use Modx, both designer AND dev friendly by a long shot (as long as you get over the inital eval hang up)

    check out my short presentaion on it as well ;)
    http://www.slideshare.net/callmejoe/choosing-a-web-cms-and-intro-to-modx

  23. Daniel says:

    WP started with PHP 4 if I am right, I believe currently it can be ran with both php4 and 5. I don't remember how many times I felt like starting to write my own blogging engine after fighting with various wordpress issues.

    Why I believe it will not just vanish although it should:
    – Most of the users don't know any programming at all, they install wp automatically using the hosting tools and then they just use it
    – One usually only replaces the theme with another one. That means uploading some folder contents and changing some settings
    – There is a lot of support for it – a lot of people still keep writing new themes and plugins

    Personally I believe I will still start writing my own blogging engine someday, except at this moment I don't have the time, therefore till then will have to stick to wordpress :).

  24. I think the biggest problem with WordPress (at code level) is the fact that most things are procedural – terrible namespace and lack of a proper class structure.
    It would have been great if WP engine was Object Orientated – then it could have had nice things like:
    $Post->getContent(..); or $Post->getTitle(..) etc.

    And why they haven't used proper namespace beats me – start you function names with the entity name followed by the action, for crying out loud! – post_get(), post_set() and not get_post() and the post_set() – keep it standardized.

  25. Güncel Blog says:

    thanks wonderfull post

  26. Brian says:

    Great post! The first time I had to dive into the WordPress codebase I was appalled. It's no wonder plugins are constantly breaking when WP updates are released. I will never use WP again unless the blog/site that I'm creating is trivial, and in those cases I would suggest a service like Squarespace to the client instead.

  27. Brett says:

    I can very much relate to this. I don't understand how things such as wordpress, and forum software can often tie themself up so completely, often sacrificing code quality and readability in order to get their version out.

  28. SalmanAbbas007 says:

    haha noobs, wordpress <3

  29. ian says:

    I'm in the middle of a WP-based project and I just wanted to say that this blog has the worst code I've seen in my life.

    Probably even osCommerce is better. It's a festival of design mistakes (if there even was designed) implemented by 13-year old boys who just learned programmers and write their first 'big project'.

    Sorry for the rant, but I'm after a 7hr session of resolving problems caused by morons who even can't comment their code properly.

  30. Peter says:

    Again I am faced with a terrible decision involving WP. It never works for me, costs me hours of hair pulling, crashes when updating, looks to european, is inflexible, is extremely graphics and media format unfriendly, and uses insane conventions that make no sense to anyone but MW! The little weasel! Should be shot! WP definitely sucks!

  31. Mike D says:

    Absolutely Love the post, and I kinda liked wordpress until I looked at the code. Anyone who defends the wordpress codebase is just plain ignorant.

    All you need is a new blog engine and a wordpress template stripper that works from some default wordpress install with tokenized content.

    Presto your new well architected engine now has access to tens of thousands of templates!!!

  32. Laurie says:

    I got a WP site cuz I thought it would be EZ to use for a non-developer… all I kept hearing is WP WP WP!. I hate it.

  33. Sheldon says:

    This post is summarizing up my frustrations exactly. My CMS and blog of choice to date has been Drupal, but I kept hearing all these great things about WordPress and how it's so much easier to use and work with than Drupal.

    Granted, Drupal is not and never will be the picture of simplicity, but at least the coding conventions make sense. All I see when I dig into WordPress code is one big nasty snarled ball of procedural code "Wharrgarbl" as you put it so succinctly. I am so pissed about this "THE LOOP" B.S. and all the globals that I have to run around trying to find anytime I want to do anything.

    Another thing about the stupid "THE LOOP" is that it makes it near impossible for you to separate out your code from your HTML. Thanks to the awesome "THE LOOP", I can't scan understand my own damn HTML because there's so much garbage that I'm forced to mix in there to keep the page from breaking down.

    WordPress, it's like coding with a blindfold on.

  34. Look, for sure WP codebase is a nightmare – however in the area of marketing I work in, we are seeing more and more clients want to use it.

    This might be considered a good thing – as it is encouraging marketers to consider a website as more than an 'online brochure'.

    It might also be a very bad thing – as they are starting to thing 'Wordpress' is synonymous for 'website'.

    We will see…

  35. Emad Ha. says:

    Did you see this function ? to output a widget?

    You can only output a widget with that!, with a damn condition! and the oposite to human mind!
    if NOT function_exists('dynamic_sidebar') THEN RUN that function! AT the SAME TIME check the function value, and NOT.

  36. Emad Ha. says:

    the function is
    if ( !function_exists('dynamic_sidebar') || !dynamic_sidebar("footer") )

    endif;

  37. Dani says:

    I've had a lot of fun reading this post, as well as the comments. As the author points out, I just feel sorry for people out there having to work with this piece of crap.

  38. Chris says:

    How to get the content formatted and all…

    $post = get_post($some_post_id);
    $content = apply_filters('the_content', $post->post_content);

  39. […] has all of the blogging features I could want. However, under the hood, I'd heard it was a mess. After poking around a bit, I didn't really find anything that was discouraging, but I did […]

  40. Roland says:

    Thank you for this post. I took over a WP site from a "design studio" and have been thinking of moving it away from WP to my preferred CMS, Joomla. The code base of WP is absolutely dreadful and does not make any sense.
    Not saying that Joomla is the best but at least the developers use a strict object oriented approach and – from a dev point of view – there is a well thought out structure.
    Oh, and saying that the dev should be able to figure things out by reading the code is just plain ignorant.

  41. […] Tras darme de cabezazos contra la pared durante una jornada laboral más, me he topado con este artículo que define bastante bien lo que está ocurriendo: An Exercise in WordPress Integration, or Why WordPress Sucks. […]

  42. A fascinating discussion is worth comment. I think that you need to publish more on this subject matter, it may not be a taboo matter but typically folks don't discuss such subjects. To the next! Many thanks!!

  43. Valina says:

    I use a system called hero framework and find it much easier to design for. What takes me days to figure aout and write for Granted it has its bug or two every now and then, but what doesn't?

    I find it to be clean and simple to use. It is free and open source, and is easy for my clients to use.

    I wrote more about it here http://geekygraphicgirl.com/blog/why-is-hero-framework-an-awesome-cms

  44. I'm going to attempt to respond to a number of issues mentioned in this article.

    1. Userland custom functions should not go into a themes functions.php file. Even more so if you wish to use the code with other themes. Here's a link to an excellent article concerning the matter.

    http://wpcandy.com/teaches/how-to-create-a-functionality-plugin/

    2. Brush up on OOP techniques in PHP, function overloading and overriding can become your best friend. There's some other powerful Ninja Kung Foo things you can do.

    3. WordPress is not the best thing to RIP apart to learn PHP, especially third-party plug-in's. You may or may not be learning best practices when looking at the code. One of the worse things one can do is accidentally pick up Bad Habits or poor coding techniques from other programmers. The Quality of code in many WordPress themes and plug-ins tends to become rather questionable quickly. Some even create security holes.

    4. The last time I was at Barnes and Noble bookstore, I browsed through two Excellent WordPress books from SmashingMagazine. I'm not certain which ones they were; "Smashing WordPress", "Wordpress Essentials", "Mastering WordPress","WordPress Tutorials". There were some other Books at the store on WordPress. However, I was most impressed with how well written and organized the SmashingMagazine Books were. In fact, it will save you from countless hours of digging through the WordPress Codex and chasing down articles (of questionable quality posted on the internet). A Great Book will save you a lot of time and headache.

    5. There are a number of rants I personally have about the structure and code underneath WordPress. WordPress is not the "Be All End All" of everything.

Leave a Reply