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
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:
In the end, it seems that 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 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? Fortunately, the 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. 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: 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 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.
$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()?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"
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).A solution... sort of.
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:
Wharrgarbl
$postObjects = getRecentPostsByDate(1);
$output = formatPostContent($postObject[0]);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!