Category: Geek Stuff

  • Never-Ending Pagination in WordPress

    Never-Ending Pagination in WordPress

    Take your site’s slideshows to the next level with the following:

    // Slightly different way of getting a previous post than get_adjacent_post(), this 
    // function will grab a post in a SINGLE specific category. We'll go ahead and 
    // return it as a permalink since that's ultimately what we want anyways. 
    function rdc_get_prev_url_in_category( $in_category ) {
    	global $post, $wpdb;
    	
    	// Convert category to id if it's a slug
    	if ( ! is_numeric( $in_category ) )
    		$in_category = get_category_by_slug( $in_category )->term_id;
    
    	// This query will grab the preceding post id in $in_category
    	$query = $wpdb->prepare( "
    		SELECT p.ID FROM $wpdb->posts AS p 
    		INNER JOIN $wpdb->term_relationships AS tr ON p.ID = tr.object_id 
    		INNER JOIN $wpdb->term_taxonomy tt ON tr.term_taxonomy_id = tt.term_taxonomy_id 
    		AND tt.taxonomy = 'category' 
    		AND tt.term_id IN (%d) 
    		WHERE p.ID < %d 
    		AND p.post_type = 'post' 
    		AND p.post_status = 'publish' 
    		ORDER BY p.ID DESC LIMIT 1 
    	", $in_category, $post->ID );
    	
    	// Formulate cache key and see if it exists
    	$query_key = 'rdc_previous_post_' . md5( $query );
    	$result = wp_cache_get( $query_key );
    
    	// Cache key exists so lets use it
    	if ( false !== $result ) {
    		if ( $result )
    			$prev_post = get_post( $result );
    		return get_permalink( $prev_post->ID );
    	}
    	
    	// Cache key didn't exist, lets run a new query
    	$result = $wpdb->get_var( $query );
    
    	// Query failed for some reason, probably this is
    	// the first post in the category. Go home instead.
    	if ( null === $result )
    		return get_bloginfo( 'home' );
    	
    	// Save query result for use later
    	wp_cache_set( $query_key, $result );
    	
    	// Return the permalink of the resulting post id
    	if ( $result ) {
    		$prev_post = get_post( $result );
    		return get_permalink( $prev_post->ID );
    	}
    	
    	// Something crazy happened to get here, but you 
    	// never know ...
    	return get_bloginfo( 'home' );	
    }

    The next part actually filters the wp_link_pages arguments and decides where to put a next button where one didn’t previously exist. I also threw in an additional previous button, which uses some javascript to take the user back to the previous page. There’s probably some creative logic you can write to do it without javascript, but that’s probably unnecessary in today’s world.

    function rdc_filter_wp_link_pages_args( $r ) {
    	global $page, $numpages;
    	
    	// These links should match the design of your existing links
    	// and you should change 12345 to your slideshow category
    			
    	// If last page of a slideshow, show a "next" button where there wouldn't normally be one
    	if ( $r['next_or_number'] == 'next' &amp;&amp; $page == $numpages &amp;&amp; '' == $r['previouspagelink'] ) {
    		$repl_next_link = '<a href="' . rdc_get_prev_url_in_category( 12345 ) . '">NEXT &amp;raquo;</a>';
    		echo $r['before'] . $repl_next_link . $r['after'];
    	}
    		
    	// If first page of a slideshow, showing "back" button where there wouldn't normally be one 
    	if ( $r['next_or_number'] == 'next' &amp;&amp; $page == 1 &amp;&amp; '' == $r['nextpagelink'] ) {
    		$repl_prev_link = '<a onclick="window.history.back();">&amp;laquo; PREVIOUS</a>';
    		echo $r['before'] . $repl_prev_link . $r['after'];
    	}
    		
    	return $r;
    }
    add_filter( 'wp_link_pages_args', 'rdc_filter_wp_link_pages_args' );
  • Relating a MySQL Process to Server Process

    All of this assumes LAMP (specifically CentOS 6, MySQL server 5.5, Apache 2+ with mod-status enabled)

    On mysql server:

    watch -n 1 "mysql -e 'show processlist';"

    Look for sleeping connections that are staying open for a while. Watch for a trend. When you see a connection that you think will stay open for long enough, note it’s port number. Open second shell. Do the following:

    netstat -lnap | grep 12345

    – where the 12345 is the port number from the mysql process list. If/when you get a result, note the number to the right, next to “ESTABLISHED”. Next – open a web browser. Navigate to http://yourserver.com/server-status and do a search for that number (that’s the PID (process id). The highlighted line is now the process that caused the long-running MySQL thread.

    Repeat this process a bunch of times until you have a good overview of what’s causing problems. Viola! Debug success, and it’s time for beers!

    ( This week, we’re drinking Sam Adams Boston Lager for our friends in Boston )

  • SQL_CALC_FOUND_ROWS and no_found_rows

    SQL_CALC_FOUND_ROWS and no_found_rows

    By default, the WordPress SQL query that selects posts from the database will use “SELECT SQL_CALC_FOUND_ROWS …”. This is mainly for pagination purposes, to speed up subsequent queries for the next set of results. Writing the query that way certainly helps speed up the site as a whole, but is useless in some circumstances.

    Remedy: Look through your theme and plugin code for WP_Query objects. On queries that don’t need pagination, add a new query variable to the mix that looks like this:

    $a_faster_wp_query = new WP_Query( array(
    	'foo' => 'bar',
    	'more_foo' => 'extra_bar',
    	'no_found_rows' => true,
    ));

    (The magic is on line 4 – it must be passed as an actual boolean, not a string)

    Use this tidbit on every WP_Query that doesn’t need pagination to make WordPress omit the “SQL_CALC_FOUND_ROWS” from it’s query, thus speeding up the post selection query.

  • What Is WordPress?

    What Is WordPress?

    Several people have asked me recently, “What is WordPress“? Those words are searched over 30 million times per month on Google. I have been working with WordPress for years now so I figured I would take a few moments to explain what is WordPress, what it does, and how you can use it.

    So what is WordPress?

    WordPress is the software that powers most of the blogs on the Internet, and a great majority of websites that aren’t blogs. It is open-source, highly adaptive, and fully scalable. WordPress is written with PHP technology and utilizes a database to store it’s content, data and settings. So what does that mean to you? The website you’re looking at right now, and statistically many of the other websites that you have viewed in the past, are run on the WordPress framework.

    Here is where I might confuse you a bit. There are actually two potentially different things someone could be talking about when they say WordPress. There is WordPress.com and self-hosted WordPress. Let’s talk a bit about each.

    What is WordPress.com?

    WordPress was first released in 2003 by a couple of open-source gurus who eventually founded a company by the name of Automattic, who now manages WordPress.com. WordPress.com is where you can go to register a free blog and publish your content without the hassle of setting up your own servers and software. It’s easy and anyone can do it.

    What is WordPress Self-Hosted?

    The down side to WordPress.com is that it doesn’t allow for very much customization. If you need custom functionality, specific design options or your own domain name, you’ll need to register at WordPress VIP ( starting at $3750/month ) or install the free WordPress software on your own servers. Having a self-hosted install gives you the opportunity to modify the system to your liking, install community or self-authored plugins, choose from one of thousands of design themes, and so much more. You name it, and it can probably be done with WordPress.

    So now you know what is WordPress, here’s what it looks like!

    Obviously, you’re looking at it right now. This website is powered by WordPress. But be open minded – the web-facing side of WordPress can look like anything you can dream up. Here are a few screenshots of the back-end of WordPress.

    What is WordPress login screen
    Here is where you enter a username and password, just like you would for email or Facebook
    What is WordPress - WordPress Dashboard
    Once you are successfully logged in, here is what you see. A summary of things you can do or see on the management side of your website.
    What is WordPress Post Page
    To create a new page or post on your website, this is where you are taken. It’s a WYSIWYG editor like Microsoft Word or a similar program. It’s quick and easy to insert text, images, videos, and anything else you want.

    If you need a website that’s easy to manage, secure, and fully-scalable, WordPress is one of the best options. Whether you would like to blog, sell your products, or simply advertise you business, WordPress will do it quickly and easily.

  • UFOs In Florida

    UFOs In Florida

    965786_30141131

    Let me preface this post with this: When I don’t completely write-off an idea, I am just about the world’s biggest skeptic. I don’t believe in ghosts, Earth-visiting aliens, or sasquatch-loch-ness-boogie-men.

    Now that that’s said, I just saw a UFO – a very real, very abnormal, very strange pattern of lights in the sky, fairly close in front of me. And no, I haven’t been drinking or using other mind-altering substances. In fact, this is the second time in my life that I’ve seen a UFO with the last time about six months ago, also here in Florida.

    What I saw tonight was a “swirling” group of lights, like a swarm of 747-size fireflies, moving at around 100 knots parallel to the beach, from the North to the South. The previous thing I saw was a single bright light moving across the horizon at about 1000 knots. The previous object I saw could have possibly been some sort of optical illusion since I was driving at high speed down the highway. Tonight’s occurrance however couldn’t have been mistaken. Very strange.

    Let me also mention that I am an airplane pilot and have studied the skies my whole life. I promise you I cannot explain what I just saw.

    Well, we were on Palm Beach Island. Maybe it was just Donald Trump flying around his house in some sort of rich-guy helicopter.

  • Seriously, Germany, You Can Quit Now

    Seriously, Germany, You Can Quit Now

    howsecure

    American Black-History month must also be Europe’s “Hack the US” month, or something. My blacklist is filling up with users from Germany, Sweden, and London, who have tried to brute force their way into my admin area. Usually it’s Chinese IP addresses with a few African and US addresses thrown in the mix. But someone over in Europe found my blog and has made it their #1 target. Who did I piss off?

    So Europe, listen up. You’re wasting your time. You’re probably not going to hack my site, and you’re almost certainly not going to hack my site at the WordPress level. According to howsecureismypassword.net it will take your crappy Macbook pro 71 quadrillion years (holy crappp) to crack my site.

    Just sayin’, there is NOTHING on this site worth that much time.

    Footnote: When you get blacklisted by one of my filters it will be system-level, and permanent. And by the way, JACKASSES, WordPress does not have an account named “admin”.

  • Merry Christmas, Now Patch Your WordPress Sites!

    Merry Christmas, Now Patch Your WordPress Sites!

    W3 Total Cache WordPress exploit

    Thanks to the release of http://seclists.org/fulldisclosure/2012/Dec/242 on Christmas Eve, I’ve spent my holiday working security for several sites.

    This exploit allows an attacker to take advantage of the “open” nature of W3 Total Cache’s cache files to extract password hashes from the database cache. I agree with Jason on this – why did the author of W3TC keep these directories open? The plugin already modifies .htaccess, why couldn’t they simple add

    "Options -Indexes"

    for the cache directories and keep everything a bit tighter? This security “misconfiguration” was not documented by W3TC or WordPress (that I could find) and it could lead to a catastrophic security breach. Since the potential bug is caused solely by W3TC, I believe it’s their responsibility to add the necessary fix, and not leave it up to site admins.

    After further investigation, the fix suggested by Jason does not work on my servers (don’t know why). Here is my fix, which does the trick and causes w3-total-fail to totally fail.

    Navigate to your /wp-content/w3tc folder and add a new .htaccess. Inside it, add the following:

    <Files *>
    order deny,allow
    deny from all
    </Files>

    Restart your web server for good measure with

    /etc/init.d/httpd restart

    or the equivalent for your server. Jason’s tool will no longer work against your site, but go ahead and check it once again for good measure. The tool should still show “Attempting…” repetitively, but this time it will iterate through the directories at a much faster pace because it can’t access the contents. No more hashes will appear.

    I’ve pondered upon the topic of W3 Total Cache’s security for quite some time, and I’m well aware of this and a few other possible issues with W3TC. I’m surprised that it’s taken this long for someone to have the same thought and attempt to exploit WordPress using this concept.

    Anyways, WP-Admins should download this and check the security of their sites and patch their sites accordingly. Hopefully Frederick Townes will release a self-patching version of W3TC really soon, as many WordPress sites heavily rely on this plugin and I’m sure most admins aren’t even aware of this security threat. Merry Christmas!

  • Rewrite WP Attachment Images on the Fly

    Rewrite WP Attachment Images on the Fly

    server-patch-panel

    At first, this may not seem to have any real-world use, but consider this: You need to set up an independent development environment for your site, and you’d rather not copy gigabytes of files from your production server’s wp-content directory. Without the following function, keeping everything synced could turn into another full-time job, especially if your editorial staff is posting hundreds upon hundreds of articles each day.

    Here’s how it works: This filter interrupts the output of wp_get_attachment_image and replaces the returned image tag’s src attribute with your production server’s url, therefore effectively telling the page to read images from a different server than the page is served from.

    So here’s the WordPress code that makes it all happen. Put it in a file in your development server’s mu-plugins directory so it doesn’t get overwritten with theme synchronizations. Remember to swap out “yourserver.com” and “dev.yourserver.com” with appropriate values.

    <?php
    
    function rewrite_images( $atts ) {
    	$atts['src'] = str_replace( 'dev.yourserver.com', 'yourserver.com', $atts['src'] );
    	return $atts;
    }
    add_filter( 'wp_get_attachment_image_attributes', 'rewrite_images' );
    
    ?>

    What other creative uses can you think of for this snippet? Leave me a comment below!

  • Purge All WordPress Users of a Particular Role

    Purge All WordPress Users of a Particular Role

    Bulk Delete WordPress Users

    I needed to delete all of the subscriber level users on one of my sites recently, and couldn’t find an easy way to do it. My solution? Write some code. It was definitely quicker and easier to run this snippet than to manually delete over 7,700 users from my database. Drop this code into an admin page where you can run it as an administrator, and watch it go to work!

    If you need to delete authors, editors, or some other role, simple switch “subscriber” on line 3 to your chosen role. Note: it must be a valid WordPress role registered in your site. This code leaves users with posts in the database. If you would like to remove users that have posts, remove the conditional on line 7 and it’s corresponding closing bracket on line 13. Be sure to modify the wp_delete_user function call on line 8 with it’s second argument – this will keep those user’s posts online and attribute them to whatever user ID you specify in the second argument.

    <?php 
    
    $all_users = get_users( array( 'role' => 'subscriber' ) );
    
    foreach( $all_users as $single_user ) {
    	$users_posts = get_posts( array( 'author' => $single_user->ID ) );
    	if( !$users_posts ) {
    		if( wp_delete_user( $single_user->ID ) ) {
    			echo 'User ' . $single_user->ID . ' deleted.<br />';
    		} else {
    			echo 'Delete user ' . $single_user->ID . ' failed!<br />';
    		}
    	}
    }
    
    ?>

    Disclaimer: This code is fast and aggressive. There is no “undoing” this operation. Use this at your own risk, data is NOT recoverable. Also, don’t believe everything you read online … you cannot perform the same function with raw MySQL without completely hosing your database – so don’t even try unless you REALLY know what you’re doing.