Alternate version of “The Loop”
September 1, 2010
OK So, most theme developers are aware of what the loop is… it displays your WordPress posts.
The one interesting thing about the loop is that it bounces in and out of the php and straight html output. So, most of the functions that are called do the echoes themselves. But what if need the output in a variable, or want to code it so that the call is part of its own echo function? You simply cannot use the same functions.
Fortunately WordPress provides two versions of each of these core functions. For example there is the_content and get_the_content() also the_permalink() and get_permalink() (yes, that inconsistency has ALWAYS bothered me..)
Here is a version of ”The Loop” which calls all of the alternate versions of the functions:
if (have_posts()) {
while (have_posts()) {
the_post();
echo ‘<div id=”post-’ . the_ID() . ‘”>’;
echo ‘ <div></div>’ . “\n”;
echo ‘ <div>’ . “\n”;
echo ‘ <div>’ . “\n”;
echo ‘ <h2><a href=”‘ . get_permalink() . ‘” rel=”bookmark” title=”Permanent Link to ‘ . the_title_attribute(‘echo=0′) . ‘”>’ . the_title(‘echo=0′) . ‘</a></h2>’ . “\n”;
echo ‘ <small> <!– by ‘ . get_the_author() . ‘ –></small>’ . “\n”;
echo ‘ <div>’ . “\n”;
$content = get_the_content();
$content = apply_filters(‘the_content’, $content);
$content = str_replace(‘]]>’, ‘]]>’, $content);
echo $content . “\n”;
echo ‘ </div>’ . “\n”;
echo ‘ </div>’ . “\n”;
echo ‘ </div>’ . “\n”;
echo ‘ <div></div>’ . “\n”;
echo ‘</div>’ . “\n”;}
echo ‘<div>’ . “\n”;
echo ‘ <div>’ . next_posts_link(‘« Older Entries’) . ‘</div>’ . “\n”;
echo ‘ <div>’ . previous_posts_link(‘Newer Entries »’) . ‘</div>’ . “\n”;
echo ‘</div>’ . “\n”;} else {
echo ‘<h2>Not Found</h2>’ . “\n”;
echo ‘<p>’ . “Sorry, but you are looking for something that isn’t here.” . ‘</p>’ . “\n”;
get_search_form();}
Determining what versions of WordPress you are hosting
August 10, 2010
If you host lots of different sites for people, one of the things you might want to know is what versions of WordPress each site is running.
WordPress stores the version number in a variable named $wp_version which is set in the file version.php.
With that information in hand, you can write a bash command that you run from your /home directory to display all of the WordPress versions you have on your server:
find . -name version.php -type f|xargs grep ^\$wp_version
This is one of the aliases I have in my .bashrc file.
WordPress Security – a plugin done right.
June 22, 2010
It’s rare that I open the source code for a random plugin and see every recommended security measure taken. When looking at Chris Boyd‘s plugin GeoLocation Plugin, I kept digging deeper and deeper and found he’d consistently covered everything. This plugin is a text book example of how to write a secure plugin.
Since he has so many techniques in here, this post wrote itself in my head. It was irresistible.
I strongly recommend you download the plugin and open geolocation.php to follow along
So, here are the security methods I saw him use, there may be more I didn’t catch, if so feel free to add them to the comments:
Use nonces on all input forms
Chances are your plugin will ask for information. A nonce is a security token that helps guarantee that you are getting real data from a real user. In function geolocation_inner_custom_box() Chris calls
echo '<input type="hidden" id="geolocation_nonce" name="geolocation_nonce" value="' . wp_create_nonce(plugin_basename(__FILE__) ) . '" />';
to add the nonce to his input form and then to check this on the processing side in function geolocation_save_postdata he calls:
// Check authorization, permissions, autosave, etc if (!wp_verify_nonce($_POST['geolocation_nonce'], plugin_basename(__FILE__))) return $post_id;
This is very simple code. There’s almost no cost to adding nonces to form processing and you can use that exact code, just changing the name of the field. This will block most bots from abusing your plugin.
Verify the user’s permissions
The user_can functions go hand in hand with the nonces and they work together to block the same kind of attacks. If your plugin does something that just anyone off the street shouldn’t be able to do, verify that the user is allowed to do it. This check is just a little bit further into function geolocation_save_postdata:
if('page' == $_POST['post_type'] ) { if(!current_user_can('edit_page', $post_id)) return $post_id; } else { if(!current_user_can('edit_post', $post_id)) return $post_id; }
This simple check to confirm that the user is allowed to edit a post before the geotagging information is added and ties the plugin directly into all of the security already built into WordPress. It is tremendously powerful.
Configure default values
In programming 101, you learn never to trust the computer to give you a clean value for an uninitialized variable. In web development, there are even more implications to this. Caching is one of those. If you call get_option and WordPress does not have a value, it will access the database to see if there is a value set. Until a value is stored in the database, WordPress has to keep looking for it on every page load. Anything you can do that avoids accessing the database files and quite possibly the hard drives where the information is stored, will make your site run faster. If a value is found, that value will be loaded from the cache automatically. Additionally, if you set your default values, you know what you are getting back. Chris handles this in function default_settings():
function default_settings() { if(get_option('geolocation_map_width') == '0') update_option('geolocation_map_width', '450'); if(get_option('geolocation_map_height') == '0') update_option('geolocation_map_height', '200'); if(get_option('geolocation_default_zoom') == '0') update_option('geolocation_default_zoom', '16'); if(get_option('geolocation_map_position') == '0') update_option('geolocation_map_position', 'after'); }
Use the Settings API and let WordPress do all the work
WordPress 2.7 added a wonderful set of tools called the Settings API. Most plugins do not take advantage of this complex tool set when they could. Chris uses the register_setting API call in function register_settings to enumerate the type of data he wants in each field.
function register_settings() { register_setting( 'geolocation-settings-group', 'geolocation_map_width', 'intval' ); register_setting( 'geolocation-settings-group', 'geolocation_map_height', 'intval' ); register_setting( 'geolocation-settings-group', 'geolocation_default_zoom', 'intval' ); register_setting( 'geolocation-settings-group', 'geolocation_map_position' ); register_setting( 'geolocation-settings-group', 'geolocation_wp_pin'); }
As you can see he specifies that certain values must be integers. Chris doesn’t take full advantage of the API in this plugin. In fact, I’m not convinced that simply calling register_setting on its own does anything. It is meant to be used with other calls. Had he used them all WordPress could have handled all sorts of things for him automatically, including the nonce field and additional checks.
The settings API is POWERFUL but has a steep learning curve. Once you pass the learning curve your input form printing just becomes five lines:
<form action="options.php" method="post"> <?php settings_fields('plugin_options'); ?> <?php do_settings_sections(__FILE__); ?> <input name="Submit" type="submit" value="<?php esc_attr_e('Save Changes'); ?>" /> </form>
This topic is WAAAAAAY to big to cover here and I freely admit, I’m no expert on it. I recommend that you read more: A quick & dirty example or The Whole Shebang
Verify your data
The last two topics are related as the come from the same rule: ALL data that you get from ANY source must be verified. This is where many plugins fail. The assumption is that “if it is in the database, it must be clean” or “it’s from an RSS feed, I know the data is good” or “The variable has INT in the name so it obviously contains an integer” or any of a thousand other gotyas. The way to keep yourself safe from an assumption is to VERIFY.
I want to highlight just two examples of this in Chris’s code.
First, in function display_location, he uses a cast to ensure the data he gets is what he wants from post meta:
$public = (bool)get_post_meta($post->ID, 'geo_public', true);
Second a function clean_coordinates uses regex to ensure the value he receives is what he wants:
$latitude = clean_coordinate($_POST['geolocation-latitude']); [..] function clean_coordinate($coordinate) { $pattern = '/^(\-)?(\d{1,3})\.(\d{1,15})/'; preg_match($pattern, $coordinate, $matches); return $matches[0]; }
Escape all variable data you display
I won’t show specific examples of this as they are everywhere throughout the whole plugin, but this is one of the most important steps you can take to make your plugin secure. It is also one of the areas that has has the most focus in the WordPress core over the years.
If you are displaying a value that isn’t hard coded in your source, you need to first feed it through one of these functions (or something similar):
esc_attr() Cleans HTML attributes for use on screen esc_html() Prepares complete blocks of HTML code esc_js() Special javascript handling of quotes and EOL characters esc_sql() Escapes data for use in a query esc_url() Returns a valid URL if possible esc_url_raw() Prepares an URL to be inserted in a database
This applies to values you are putting into javascript, urls you are displaying on the screen or using for includes, and data used to build image references. All this information must be sanitized. Visit the codex for more information on data validation.
Bonus Tip
If you’ve made it this far in the post, you get one more tip for free. DON’T DO IT ALL YOURSELF. I’d be willing to wager that this plugin was not ‘born’ with all of these security techniques in place. Though this plugin is attributed to Chris in the repository, he lists multiple authors for the plugin. You don’t HAVE to do all of this by yourself. Once your plugin is done, ask people to review it. I can pretty much guarantee that someone will find something. That’s just how it works. But won’t you feel much better if your friend catches the problem before it is discovered because your plugin added an avenue of attack to every site it’s been installed on? Someone will be glad to review it for you it. That’s part of what is great about the WordPress community: people love to help.
Summation
Website security will forever be an on going battle. It is a big, complicated subject with nuances you can miss easily. However, WordPress has been around long enough to have build up quite a collection of tools you have at your disposal as a plugin author. If use the tools WordPress provides, following Chris’s example outlined here, you can rest easy at night knowing you’ve done your job well.
WordPress DB Hacks: Determining the ID of a category parents
June 3, 2010
When manipulating WordPress databases for exports and merges, sometimes it is helpful to get a list of all of the parents for the categories your posts are in.
For the import I am working on right now. The category list is being flattened from 30 categories down to 5 categories. The blog has just over 75 thousand posts in it and doing the conversion manually would be a rather arduous process to say the least.
So, I came up with this little query to give me the parent category for each of the child categories on that site.
It’s fairly simple but I’ve had to write it several times now and thought maybe someone else might need it sometime too:
SELECT `tt1`.`term_taxonomy_id` as 'Child Tax ID', `t1`.`term_id` as 'Child Term ID', `t1`.`name` as 'Child Name', `tt2`.`term_taxonomy_id` as 'Parent Tax ID', t2.`term_id` as 'Parent Term ID', `t2`.`name` as 'Parent Name' FROM `wp_term_taxonomy` `tt1`, `wp_term_taxonomy` `tt2`, `wp_terms` `t1`, `wp_terms` `t2` where `tt1`.`term_id` = `t1`.`term_id` and `tt1`.`parent` = `t2`.`term_id` and `tt1`.`taxonomy` = 'category' and `tt2`.`term_id` = `t2`.`term_id` and `tt2`.taxonomy = 'category';
Now I can just grab it instead of rewriting it again next time. After all, this is The Code Cave…
PS – If you just want to see the top level categories, here’s how:
SELECT `tt1`.`term_taxonomy_id`, `t1`.`term_id`, `t1`.`name` FROM `wp_term_taxonomy` `tt1`, `wp_terms` `t1`where `tt1`.`term_id` = `t1`.`term_id` and `tt1`.`taxonomy` = 'category' and `tt1`.`parent`=0
WordPress 2.8 Beta 1 Released
May 17, 2009
While I was rolling around near comatose yesterday WordPress 2.8 beta 1 hit the streets. We plan to do a thorough review of this project on Thursday at the Ohio WordPress meetup here in Akron, Ohio. So, I figured it would would be a good time to run it officially here in The Code Cave.
The upgrade process is as simple as always. Unzip the file, copy it over the existing files, go to wp-admin upgrade and click continue. When the official release comes out, I plan upgrading my wp-upgrade script as I still think it is useful. Even though WordPress itself has upgrade abilities within it, the full file backup and database backup that my script does, still provides added benefit. So, I’ll keep it around a while longer.
As for WordPress 2.8, you don’t need to fear about learning a totally new system from scratch. There are a number of nice changes and tweaks, but the basic interface remains the same. There are a lot of changes for plugin developers and the like, but the everyday users will see some things like the new widget drop zone that makes it easy to make a widget inactive without loosing its settings. I’ll be testing over the next few weeks to see what I’d consider note worthy for a release post. I used to even do a line by line comparison, but I don’t know if I’ll don’t be returning to that. For now you can read about the changes here.
If there is any part of this upgrade that you definitely think we should cover at the Ohio WordPress Meetup, please let me know so that I don’t miss it!
WordPress Quick Tip: Fixing the number of comments per post
January 7, 2009
For various reasons, sometimes the number of comments shown under the title of the post may not match the number of actual comments displayed under the post.
Here is a simple SQL statement that will resolve the issue:
update `wp_posts` set comment_count = (select count(*) from wp_comments
WHERE `comment_post_ID` = `ID` and comment_approved = '1')
You can use this to verify what would change and where your problems may lie:
SELECT ID, `post_title`, `comment_count`,
(select count(*) from `wp_comments`
WHERE (`comment_post_ID` = `ID`) and (`comment_approved` = '1')) as NewCC
FROM `wp_posts`
WHERE `comment_count` <> (select count(*) from `wp_comments`
WHERE (`comment_post_ID` = `ID`) and (`comment_approved` = '1'))
WordPress 2.6 – Causing waves on Mars: The XMLRPC controversy
June 26, 2008
WordPress 2.6 has been been trouble. There’s been confusion about whether it would be out in July or August. There was one date in the road map, and one in Trac. On Sunday night, Charles Stricklin and I recorded episode 43 of The WordPress Podcast and I stuck with the August date that was in the Trac tool used for development.
Then the next day Ryan Boren sent this reply to the WP Testers mailing list the next day:
On Mon, Jun 23, 2008 at 1:01 PM, Kirk M wrote:
> Do my eyes deceive me or am I seeing a due date of July 7th for the release
> of 2.6 with a fall back for July 14? Any reason for the releasing a month
> early? I’ve barely setup my test sites figuring I had a month to go ye;).[Ryan Boren Replied:]
There was some confusion because the roadmap had July and trac had
August. Given that all of the features went into 2.6 early and that
its been running this whole time on wordpress.com and lots of our
personal blogs, a shorter beta seems doable. I think we can launch
the beta cycle now, pound on it until the 7th and decide if it’s
ready. If not, pound it another week and decide of it’s ready. I
merge 2.6 to wordpress.com almost daily and get tons of feedback in an
instant. I’m pretty confident in being able to finish off 2.6 in a
few weeks. We won’t be adding any more features to 2.6 so there’s no
need to linger for an extra month. Also, a July 2.6 release allows us
to consider an early September 2.7 release that focuses on pulling in
some of the GSoC work. That work would be too much to try to push
into an early August 2.6 release.
Ah, well you win some you lose some. At least I wasn’t the only one who thought it would be August.
Since then a much more controversial debate has arisen. Westi made the announcement that WordPress 2.6 would have the XMLRPC feature turned off. XMLRPC is the technology that allows programs like Windows Live Writer, MarsEdit, ecto and other external blog editors use to communicate with your WordPress blog. Here is what Westi had to say about it in his announcement:
WordPress 2.6 will be more secure out-of-the box including better support for running the admin over SSL and changes to disable the remote publishing protocols by default.
We have choosen to disable Atom Publishing Protocol and the variety of XML-RPC protocols by default as they expose a potential to be a security risk. So from WordPress 2.6 onwards you will need to go into the Settings->Write page and enable them individually if you want to use them.
Mac software developer and MarsEdit creator Daniel Jalkut believes this to be a fundamentally wrong choice. He’s said so on the wp-hackers list and on his website:
WordPress’s decision to shut off remote access by default is analogous to a bank offering unrestricted drive-through access to its cash machines, while requiring pedestrians to ring a bell and wait for a security guard to open the door to the machines.
Also worth considering: if a service is disabled by default for security considerations, what message does that send to people who choose to, or who are encouraged to turn the service back on? It sets up a perception of insecurity which may not even be warranted. If the remote publishing interfaces are insecure, they should be fixed, not merely disabled!
I think that’s somewhat misleading. It makes people think that the switch has to be set over and over again. It is much more like, when you open a savings account, checking either the box that says you want an ATM Debit card and/or the box saying you want to access the account through the online site. Eliminating either of those options would make your money more secure.
I agree that there is an issue with people upgrading and finding that MarsEdit, Livewriter or whatever doesn’t work. That is easily solved by keeping the XML interface off by default on new blogs, but not changing the behaviour for upgrades.
But why not just “fix” the security issues? Well the truth of the matter is that you can no more "fix" all security risk in xmlrpc than you can "fix" it in any software program. It is a moving target. New methods are thought of and software improvements introduce new avenues never thought of, even if there is a layer between the final interface and the database. So even if WordPress was completely clean in 2.6, how can you prove that it is secure in 2.8 or 3.0.
Is xmlRPC secure in WordPress 3.0? I don’t know it doesn’t exist yet. But I do know if it is disabled for new blogs, that the new WordPress 3.0 blogs won’t face an XMLRPC security risk.
Article Series - WordPress 2.6
- WordPress 2.6 – Causing waves on Mars: The XMLRPC controversy
Tip Tuesday: Manipulating Graphics files for your blog
January 22, 2008
When working with graphics files on your blog, it is always smart to optimize their size for their targetted use. A simple corner picture does not need an original size of 8.1 mega pixels. On a windows machine, MS Paint can handle that sort of transformations, with a little pain and bloodshed. I’ve also written and posted here a console app to do the dynamic resizing. Gimp is awesome, but it is over kill.
I strongly encourage Windows users to check out Infranview. You might look at the site and say “Oh it is just a viewer”, but it is soooooo much more than that. Though it is the one of the best picture viewers out there, it also handles basic graphic manipulation better than most other software out there, even the pro stuff.
File resizing is very simple. However following their “It is trying to be simple for beginners and powerful for professionals.” goal, it allows you to, in the advanced menu, choose from various resampling methods in case the image just looks wrong when you resize it. Most programs use the 1 method the programmer preferred and you are stuck with it.
You can get it here:
http://www.irfanview.com/
and once you load the plugins from here:
http://www.irfanview.com/plugins.htm
(I prefer this mirror for downloads.)
You’ve got a powerful graphics manipulation tool that can even accept any photo shop 8bf plugins that you have lying around.
(BTW xnview is a infranview knock off, but it does have pocketPC and Smartphone support and works nicely as a viewer on those platforms)
Eliminating duplicate WordPress content in Google
November 7, 2007
If you are at WordCamp 2007, one of the best sessions was Google’s own Matt Cutts discussion on optimizing your WordPress blog. You can see the whole presentation over on John Pozadzides site’s One Man’s Blog. Here is the link. You can see in Matt’s Whitehat SEO tips for bloggers slide show that one of the things that WordPress “suffers from” is that you can reach the same data from multiple sources.
You can get to the same article by browsing by category, by day, month, year etc. etc. etc. Each time Google sees the same data repeated on your site again, it hurts your site a little bit more.
This bit of code will help fix it. It goes into the header part of your blog and will tell Google that it should ignore all of the pages that are not the orginal source of the article.
Here you go:
[php]
if (is_home() || is_single())
{
echo ““;
}
else
{
echo ““;
}
[/php]
Upgrade to WordPress 2.2 or have your Admin PW stolen
May 24, 2007
OK It’s been a couple days now and this news is only spreading. If you haven’t heard already, there is an attack out there that allows the Admin PW to be compromised for any WordPress 2.1 and 2.0 blog. Only 2.2 and the yet unreleased version of 2.0 are safe and it will stay that way. The 2.1 is not a maintained version. So far, I’ve heard nothing about the plans to release a new 2.1. So at this point, for most people running 2.1, your only choice is to upgrade to 2.2.
I’ve stolen the admin PW of several 2.1 sites under my control and tested the sites of some of my friends to make sure they were safe even though they hadn’t upgraded.
There are two things that may make your 2.1 DB safe:
1. Your user named Admin is NOT user number 1.
2. Your database prefix is NOT wp_
If you want to upgrade safely and quickly, try my script. The latest post about it is always at: http://www.thecodecave.com/EasyWPUpdate
If you want to see how we handled this at b5media, read here:
Guide to Disaster: How The Tech Team Handled WordPress Security Flaw