Hide WordPress Post from All Queries

Problem: you want to create a variation of a page but you don’t want it to show up on the home page or in any archives or anything. You just need a direct link so you can share it with someone.

Solution:

add_action('pre_get_posts', 'hide_hidden_posts');
function hide_hidden_posts($query) {
  if ( is_admin() ) {
    return $query;
  }

  if ( is_single() AND $query->is_main_query() ) {
    return $query;
  }
  $ids = wp_cache_get('hidden_posts', 'posts');
  if ( !$ids ) {
    global $wpdb;
    $ids = $wpdb->get_col("SELECT post_id FROM {$wpdb->prefix}postmeta WHERE meta_key = 'hide_post'");
    wp_cache_set('hidden_posts', $ids, 'posts');
  }
  $query->set('post__not_in', $ids);
  return $query;
}

This function will modify all WordPress’ frontend queries to exclude any posts with a custom field “hide_post”, except in the case that the query is the main query on a single post page.

Caveat: This will only be functional for plugins and themes using the WP_Query api. Custom queries will not be modified.

Block hacker attacks on WordPress’ xmlrpc.php

It you’re getting a ton of POST requests to your WordPress xmlrpc.php file, here’s a quick way to block all the bad ips via iptables. In my case I’m using nginx and php-fpm, but something very similar would also work for apache.

First, recognize the signature. Your access logs will look something like this:

5.135.68.51 - - [13/May/2015:12:14:59 -0400] "POST /xmlrpc.php HTTP/1.0" 499 0 "-" "Mozilla/5.0 (compatible; Googlebot/2.1;  https://www.google.com/bot.html)"
185.61.138.72 - - [13/May/2015:12:14:59 -0400] "POST /xmlrpc.php HTTP/1.0" 499 0 "-" "Mozilla/5.0 (compatible; Googlebot/2.1;  https://www.google.com/bot.html)"
185.11.147.17 - - [13/May/2015:12:14:59 -0400] "POST /xmlrpc.php HTTP/1.0" 404 168 "-" "Mozilla/5.0 (compatible; Googlebot/2.1;  https://www.google.com/bot.html)"
185.11.147.17 - - [13/May/2015:12:14:59 -0400] "POST /xmlrpc.php HTTP/1.0" 499 0 "-" "Mozilla/5.0 (compatible; Googlebot/2.1;  https://www.google.com/bot.html)"
185.62.188.76 - - [13/May/2015:12:15:01 -0400] "POST /xmlrpc.php HTTP/1.0" 499 0 "-" "Mozilla/5.0 (compatible; Googlebot/2.1;  https://www.google.com/bot.html)"
185.62.188.76 - - [13/May/2015:12:15:01 -0400] "POST /xmlrpc.php HTTP/1.0" 499 0 "-" "Mozilla/5.0 (compatible; Googlebot/2.1;  https://www.google.com/bot.html)"
185.62.188.76 - - [13/May/2015:12:15:01 -0400] "POST /xmlrpc.php HTTP/1.0" 499 0 "-" "Mozilla/5.0 (compatible; Googlebot/2.1;  https://www.google.com/bot.html)"
185.61.138.72 - - [13/May/2015:12:15:01 -0400] "POST /xmlrpc.php HTTP/1.0" 404 168 "-" "Mozilla/5.0 (compatible; Googlebot/2.1;  https://www.google.com/bot.html)"
5.135.68.51 - - [13/May/2015:12:15:02 -0400] "POST /xmlrpc.php HTTP/1.0" 499 0 "-" "Mozilla/5.0 (compatible; Googlebot/2.1;  https://www.google.com/bot.html)"
5.135.68.51 - - [13/May/2015:12:15:02 -0400] "POST /xmlrpc.php HTTP/1.0" 404 168 "-" "Mozilla/5.0 (compatible; Googlebot/2.1;  https://www.google.com/bot.html)"

Googlebot will NOT be POSTing your xmlrpc.php like that. Next the trick is to figure out which IP addresses are harassing you. Run this in your terminal:

$> grep xmlrpc /var/log/nginx/access.log | cut -d' ' -f1 | sort | uniq -c | sort -rn | head
  29200 185.11.147.17
  17182 185.62.188.76
  10657 185.61.138.72
   8183 5.135.68.51
   1914 192.227.175.122
   1738 195.154.185.116
   1198 43.252.228.132
    501 205.234.152.218
    155 86.105.212.68
    103 141.138.157.95

Most likely all of these are hackers since it would be unlikely even Jetpack or some other WordPress service would hit your xmlrpc.php that frequently. But you can decide where the cut off should be by adding -n# the the head request above. In my case I chose head -n8 like so:

$> grep xmlrpc /var/log/nginx/access.log | cut -d' ' -f1 | sort | uniq -c | sort -rn | head -n8
  29200 185.11.147.17
  17182 185.62.188.76
  10657 185.61.138.72
   8183 5.135.68.51
   1914 192.227.175.122
   1738 195.154.185.116
   1198 43.252.228.132
    501 205.234.152.218

Sooo …. now you just need to wrap that in a loop that will create the iptable rules to block traffic from the ips:

$> for ip in $(grep xmlrpc /var/log/nginx/access.log | cut -d' ' -f1 | sort | uniq -c | sort -rn | head -n8 | awk '{print $2}'); do iptables -A INPUT -s $ip -j DROP; done

No more hackers.