As with many others who are now viewing this post, I have been reading various blogs, forums, and discussion groups to learn and improve my WordPress skills. Over the past 12 months I have been on a mission to substitute my use of plugins by adding code to my functions.php file instead.

While I completely agree that plugins are very useful in many situations, my experience proved that in 90% of usage cases although a plugin might exist, actually utilizing it could create unnecessary complications and compatibility issues. Additionally in a great deal of cases such plugins added menus and other admin elements which I don't want or need.

More often than not I have found that by analyzing the code of plugins I was able to strip out the piece of code I wanted and hard code it into my functions.php. This provided me with the exact functionality I needed without having to include unnecessary elements.

So, the purpose of this post is my attempt to engage you, the reader/admin/developer, to share with me and other here any code bits which you find useful and have added to your theme's function.php file to extend or enhance WordPress without utilizing a plugin.

When you submit a response here please kindly give each code bit a title, let us know if with what version of WordPress you know its compatible with, include whatever description you feel best describes its function and (if applicable) include a link to the original plugin or source where you found the information.

I am looking forward to all your responses and will of course continually add my own new finds whenever I find them.

Please vote on the question and any answers you find useful by clicking on the up arrow on the left hand side of the question or answer.

  • 13
    Considering the first 5 answers were by the OP and the question seems more geared at collecting an array of responses rather than a single, definitive answer, this should be a community wiki.
    – EAMann
    Commented Sep 9, 2010 at 14:43
  • 17
    All answers not related to a theme should be removed. This thread is a good example for bad coding practices.
    – fuxia
    Commented Jun 13, 2011 at 12:09
  • 17
    I think it'd be better to encourage people to create a custom functionality plugin instead of using their theme's functions.php
    – Ian Dunn
    Commented Jan 16, 2012 at 18:49
  • 3
    @NetConstructor.com The pure number of page views is not an indicator for quality. We should encourage specific questions with specific answers and good coding practices. This thread is the opposite.
    – fuxia
    Commented Feb 22, 2012 at 2:44
  • 6
    @NetConstructor.com Discuss it on Meta where people can see your arguments better. :)
    – fuxia
    Commented Feb 24, 2012 at 17:10

108 Answers 108


Include custom post types in "Right Now" admin dashboard

This will include your custom post types and the post counts for each type in the "Right Now" dashboard widget.

function wph_right_now_content_table_end() {
 $args = array(
  'public' => true ,
  'show_ui' => true ,
  '_builtin' => false
 $output = 'object';
 $operator = 'and';
 $post_types = get_post_types( $args , $output , $operator );
 foreach( $post_types as $post_type ) {
  $num_posts = wp_count_posts( $post_type->name );
  $num = number_format_i18n( $num_posts->publish );
  $text = _n( $post_type->labels->singular_name, $post_type->labels->name , intval( $num_posts->publish ) );
  if ( current_user_can( 'edit_posts' ) ) {
   $num = "<a href='edit.php?post_type=$post_type->name'>$num</a>";
   $text = "<a href='edit.php?post_type=$post_type->name'>$text</a>";
  echo '<tr><td class="first b b-' . $post_type->name . '">' . $num . '</td>';
  echo '<td class="t ' . $post_type->name . '">' . $text . '</td></tr>';
 $taxonomies = get_taxonomies( $args , $output , $operator ); 
 foreach( $taxonomies as $taxonomy ) {
  $num_terms  = wp_count_terms( $taxonomy->name );
  $num = number_format_i18n( $num_terms );
  $text = _n( $taxonomy->labels->singular_name, $taxonomy->labels->name , intval( $num_terms ));
  if ( current_user_can( 'manage_categories' ) ) {
   $num = "<a href='edit-tags.php?taxonomy=$taxonomy->name'>$num</a>";
   $text = "<a href='edit-tags.php?taxonomy=$taxonomy->name'>$text</a>";
  echo '<tr><td class="first b b-' . $taxonomy->name . '">' . $num . '</td>';
  echo '<td class="t ' . $taxonomy->name . '">' . $text . '</td></tr>';
add_action( 'right_now_content_table_end' , 'wph_right_now_content_table_end' );
  • Suddenly, there was a post type "WooFramework Internal Container" appearing in the RightNow widget! . . . one extra argument is needed 'show_ui' => true and it's all K now
    – brasofilo
    Commented Apr 4, 2012 at 0:37
  • This is the same exact thing I had posted above.
    – jaredwilli
    Commented Dec 9, 2012 at 17:52

New Media Library Column to Re-Attach Images

This code adds a new column to the Media Library Page allowing you to re-attach images

add_filter("manage_upload_columns", 'upload_columns');
add_action("manage_media_custom_column", 'media_custom_columns', 0, 2);

function upload_columns($columns) {
    $columns['better_parent'] = "Parent";
    return $columns;
function media_custom_columns($column_name, $id) {
    $post = get_post($id);
    if($column_name != 'better_parent')
        if ( $post->post_parent > 0 ) {
            if ( get_post($post->post_parent) ) {
                $title =_draft_or_post_title($post->post_parent);
            <strong><a href="<?php echo get_edit_post_link( $post->post_parent ); ?>"><?php echo $title ?></a></strong>, <?php echo get_the_time(__('Y/m/d')); ?>
            <br />
            <a class="hide-if-no-js" onclick="findPosts.open('media[]','<?php echo $post->ID ?>');return false;" href="#the-list"><?php _e('Re-Attach'); ?></a>
        } else {
            <?php _e('(Unattached)'); ?><br />
            <a class="hide-if-no-js" onclick="findPosts.open('media[]','<?php echo $post->ID ?>');return false;" href="#the-list"><?php _e('Attach'); ?></a>

Add a codex search form to the dashboard header

This is a simple way to add a codex search form to the dashboard header, on the top-right next to the quicklinks drop-down.

function wp_codex_search_form() {
    echo '<form target="_blank" method="get" action="http://wordpress.org/search/do-search.php" class="alignright" style="margin: 11px 5px 0;">
        <input type="text" onblur="this.value=(this.value==\'\') ? \'Search the Codex\' : this.value;" onfocus="this.value=(this.value==\'Search the Codex\') ? \'\' : this.value;" maxlength="150" value="Search the Codex" name="search" class="text"> <input type="submit" value="Go" class="button" />

if( current_user_can( 'manage_plugins' )) {
// The number 11 needs to be a 10 for this to work!
    add_filter( 'in_admin_header', 'wp_codex_search_form', 11 );
  • can you update this code to show how this only gets displayed to users with a specific role (specifically administrators)? Commented Feb 22, 2011 at 20:19
  • 1
    @NetConstructor.com I edited it to show if current_user_can manage plugins, then add the filter. It's that simple.
    – jaredwilli
    Commented Feb 23, 2011 at 0:56
  • 1
    Does this still work in the current WP version... I couldn't get it to work Commented Feb 15, 2012 at 17:06
  • I encapsulated the add_filter in this action call: add_action('plugins_loaded', 'pluginInit');, and then function pluginInit(){if...add_filter(...)} - - i'm running this in WP 3.4-alpha, and had to use in_admin_footer
    – brasofilo
    Commented Apr 2, 2012 at 11:28

Themed custom loop using shortcodes

Arguments are the same as the ones from query_posts. The content wrapped between the query tag is the template.

add_shortcode('query', 'shortcode_query');

function shortcode_query($atts, $content){
  extract(shortcode_atts(array( // a few default values
   'posts_per_page' => '10',
   'caller_get_posts' => 1,
   'post__not_in' => get_option('sticky_posts'),
  ), $atts));

  global $post;

  $posts = new WP_Query($atts);
  $output = '';
  if ($posts->have_posts())
    while ($posts->have_posts()):

      // these arguments will be available from inside $content
      $parameters = array(
        'PERMALINK' => get_permalink(),
        'TITLE' => get_the_title(),
        'CONTENT' => get_the_content(),
        'COMMENT_COUNT' => $post->comment_count,
        'CATEGORIES' => get_the_category_list(', '),
        // add here more...

      $finds = $replaces = array();
      foreach($parameters as $find => $replace):
        $finds[] = '{'.$find.'}';
        $replaces[] = $replace;
      $output .= str_replace($finds, $replaces, $content);

    return; // no posts found

  return html_entity_decode($output);


[query post_type=page posts_per_page=5]
Listing some pages:    
<p><a href="{PERMALINK}">{COMMENT_COUNT} comments</a></p>

(will make a query for 5 pages)

Inserting pre-configured widgets anywhere using shortcodes

(some ideas from http://webdesign.anmari.com/shortcode-any-widget)

add_action('widgets_init', 'create_arbitrary_sidebar');
function create_arbitrary_sidebar(){
    'name' => __('Arbitrary Widgets'),
    'id' => 'arbitrary',
    'description' => sprintf(__('Widgets from this area can added into posts/pages using the %1$s or %2$s shortcodes.'), '[widget ID]', '[widget Name]'),
    'before_widget' => '<div class="block"><div class="block-content block-%2$s clear-block" id="instance-%1$s">',
    'after_widget' => '</div></div>',
    'before_title' => '<h3 class="title">',
    'after_title' => '</h3>'

add_action('in_widget_form', 'widget_shortcodes_info', 10, 3);
function widget_shortcodes_info($widget, $return, $instance){
  if(!is_numeric($widget->number)) return; // wp-save bug :( widget needs to be saved first...

  global $wp_registered_widgets;

  // get the active widgets from all sidebars
  $sidebars_widgets = wp_get_sidebars_widgets();

  // prepare matches
  $matches = array();
  foreach($wp_registered_widgets as $i => $w)
    if($w['name'] == $widget->name) $matches[] = $w['id'];

  // find out the widget position (number)
  $number = 0;
  $is_arbitrary = false;
    foreach($sidebars_widgets['arbitrary'] as $i => $value):
      if(in_array($value, $matches) && !$is_arbitrary) $number = $number +1;
      if($value == $widget->id) $is_arbitrary = true;

  echo '<div style="background:#eee; padding: 5px;">To include this widget into your posts or pages use one of the following shortcodes: <br />';
  echo '<code>[widget '.substr(md5($widget->id), 0, 8).']</code> <br /> <code>[widget "'.$widget->name.'"'.(($number > 1) ? ' number='.$number : null).']</code></div>';

add_shortcode('widget', 'shortcode_widget');
function shortcode_widget($atts){
  global $wp_registered_widgets, $wp_registered_sidebars;
    'number' => false,        // only taken in consideration if the 1st argument is the "Widget Name" (not the hashed ID)
    'title' => true,          // show titles?
    'area' => 'arbitrary'     // sidebar to search
  ), $atts));

  // get 1st parameter (assuming this is the target widget id or name)
  if (!empty($atts[0])) $widget = esc_attr($atts[0]); else return;

  $sidebar = esc_attr($area);
  $number = intval($number);

  $callback = false;
  $possible_matches = array();
  $sidebars_widgets = wp_get_sidebars_widgets();
  if((empty($sidebars_widgets[$sidebar]) || empty($wp_registered_widgets)) && (current_user_can('edit_themes')))
    return "no valid active widgets in {$sidebar}";

  // assuming we get the md5 hashed ID
  foreach ($wp_registered_widgets as $i => $w)
    if ($widget == substr(md5($w['id']), 0, 8)):
      $callback = ($w['callback']);
      $widget = $w['id']; // real widget ID

    // compare widget names as well, and build a array with the possible widget matches array
    // (which is used later if ID match fails)
    elseif($widget == $w['name']):
      $possible_matches[] = $w['id'];


  // nothing found, assume it's the "Widget Name".
    $valid_matches = array();
    foreach($sidebars_widgets[$sidebar] as $i => $w)
      foreach($possible_matches as $id) if($id == $w) $valid_matches[] = $w;

    if(!empty($valid_matches)) $widget = $number ? $valid_matches[$number-1] : $widget = $valid_matches[0];
    if($widget && isset($wp_registered_widgets[$widget]['callback'])) $callback = $wp_registered_widgets[$widget]['callback'];

  // yey. we found it

    $params = array_merge(array(array_merge($wp_registered_sidebars[$sidebar], array('widget_id' => $widget, 'widget_name' => $wp_registered_widgets[$widget]['name']))), (array)$wp_registered_widgets[$widget]['params']);

    $classname_ = '';
    foreach ((array)$wp_registered_widgets[$widget]['classname'] as $cn)
      if (is_string($cn)) $classname_ .= '_'.$cn; elseif (is_object($cn)) $classname_ .= '_'.get_class($cn);
    $classname_ = ltrim($classname_, '_');
    $params[0]['before_widget'] = sprintf($params[0]['before_widget'], $widget, $classname_);
    $params = apply_filters('dynamic_sidebar_params', $params);

    if (is_callable($callback)) call_user_func_array($callback, $params);
    $output = ob_get_clean();

    // remove h3 if title = false
    if(!$title) $output = preg_replace('#<h3 class="title">(.*?)</h3>#', '', $output);
    return $output;
   return "widget instance not found: ".esc_attr($atts[0]);


Drop a widget in the "arbitrary widgets" sidebar, save it and you'll get the shortcodes :)

Get a custom field value through shortcodes

add_shortcode('field', 'shortcode_field');

function shortcode_field($atts){
   'post_id' => NULL,
  ), $atts));

  if(!isset($atts[0])) return;
  $field = esc_attr($atts[0]);

  global $post;
  $post_id = (NULL === $post_id) ? $post->ID : $post_id;

  return get_post_meta($post_id, $field, true);


  • [field "my_key"]
  • [field "my_key" post_id=1]

Get the TinyURL of a link through shortcodes

add_shortcode('tinyurl', 'shortcode_tinyurl'); 

function shortcode_tinyurl($atts){
   'url' => get_permalink(),
   'title' => '',
   'rel' => 'nofollow'
  ), $atts));
  if(!$title) $title = $url;

  if (FALSE === ($cache = get_transient('tinyurl_'+md5($url)))):
    $cache = wp_remote_retrieve_body(wp_remote_get('http://tinyurl.com/api-create.php?url='.$url));

    set_transient('tinyurl_'+md5($url), $cache, 60*60*24); // 1 day cache, could be incresed

  return '<a href="'.esc_url($cache).'" rel="'.esc_attr($rel).'">'.esc_attr($title).'</a>';


  • [tinyurl]
  • [tinyurl url="http://google.com" title="google"]
  • You'd better to use Javascript: <a href="javascript:window.open('http://tinyurl.com/api-create.php?url='+location.href"> Get ShorLink </a> (to avoid unnecessary HUNDREDS OF page open QUERIES(by bots or etc) to TinyUrl ...
    – T.Todua
    Commented Jan 23, 2015 at 10:22

Set Editor Defaults to WYSIWYG or HTML

function my_default_editor() {
    $r = 'tinymce'; // html or tinymce
    return $r;
add_filter( 'wp_default_editor', 'my_default_editor' );

Here is how to remove the HTML Editor

jQuery(document).ready(function($) {

UPDATED here is another way to set the default editor to HTML

add_filter('wp_default_editor', create_function('', 'return "html";'));

Quickly Determine Server & Environment Details

If you have multiple servers and multiple environments such as development, QA, and production environments, this can be very useful.

For my systems, environment is determined by the first 3 letters of the hostname, but this could easily be changed to whatever suits your needs.

add_action( 'admin_notices', 'report_environment_status', 3 );

// Report on which server and environment details
function report_environment_status() {
    $server = php_uname('n');
    switch (strtolower(substr($server,0,3))) {
        case 'pXX':
            $msg = "PRODUCTION";
        case 'qXX':
            $msg = "QA";
        case 'dXX':
            $msg = "DEVELOPMENT";
        default :
            $msg = 'UNKNOWN';
    echo "<div id='update-nag'>";
    echo "<b>You are in the $msg environment. (Server: $server)</b>";
    echo "</div>";

This has saved me many times from making updates to the wrong environment.

You can also turn this into a plugin and network activate it so all sites get the notification.

  • thanks for this piece. Could you please elaborate a bit more on this and different usage cases? I think it would also be VERY helpful to me and others if you could possibly include any other code which you utilize when your running different development versions of code. Also, if you utilize a slick way of moving a site from development to production or migrate from one domain to a different one. All these things are very helpful. Finally, do you use any type of subversion client when updating your files? If so, is there anything specific you do for this? Commented Nov 5, 2010 at 21:28
  • Please don't mark this as the answer. Otherwise this listing won't work.
    – hakre
    Commented Nov 6, 2010 at 17:41
  • 1
    I think it'd be better to use different CSS classes on the message, so that the messages could have different background colors in environments in addition to just having slightly different text. Otherwise I think you'd stop noticing the text differences pretty quickly.
    – Ian Dunn
    Commented Jan 16, 2012 at 19:01

Remove Author Metabox/Options & Move to Publish MetaBox

Tested on: Wordpress 3.0.1

One of the things that drive me crazy is a cluttered Wordpress Admin area. One of the elements which I now always setup from the start in my functions.php file is removing the Author MetaBox and Screen Options and then adding the option into the publish metabox. In my opinion this just makes sense and keep things clean. This also respects applicable permissions.

To achieve this goal, just copy and past the following code into your functions.php file.

If you feel there is a better way of doing this please suggest.


add_action( 'admin_menu', 'remove_author_metabox' );
add_action( 'post_submitbox_misc_actions', 'move_author_to_publish_metabox' );
function remove_author_metabox() {
    remove_meta_box( 'authordiv', 'post', 'normal' );
function move_author_to_publish_metabox() {
    global $post_ID;
    $post = get_post( $post_ID );
    echo '<div id="author" class="misc-pub-section" style="border-top-style:solid; border-top-width:1px; border-top-color:#EEEEEE; border-bottom-width:0px;">Author: ';
    post_author_meta_box( $post );
    echo '</div>';
  • It doesn't add the Author Metabox to my Publish Box. I figured it was because there was no add_action for the move_author_to_publish_box function so I added add_action('admin_menu', 'move_author_to_publish_box'); but that gave me a "Fatal error: Call to undefined function post_author_meta_box()"
    – matt
    Commented Dec 5, 2010 at 5:02
  • what version of wordpress are you using? Commented Dec 6, 2010 at 17:21
  • And how would you add the author to publish? On admin_init or on admin_menu wouldn't work.
    – kaiser
    Commented Feb 1, 2011 at 7:42
  • 1
    @NetConstructor: I just gave it a test yesterday (3.0.4) and yes, the author box is gone, but not moved to the publish box. When looking at the code i can't see any way, because the function is no where triggered... you just added the remove_author_box() fn to admin_menu action hook, but not the move_author_to_publish_box() fn.
    – kaiser
    Commented Feb 1, 2011 at 18:55
  • 1
    @kaiser -- your right, after reviewing this I did noticed the issue. I updated the code in my answer so just delete everything you included from this before hand and just past in the full code above. Let me know if this fixes things. Vote up the question and answer if it fixes the problem - CH :) Commented Feb 1, 2011 at 22:29

Fixed: Remove Default Wordpress Meta Boxes

This was very handy but had some errors

function remove_default_post_screen_metaboxes() {
 remove_meta_box( 'postcustom','post','normal' ); // Custom Fields Metabox
 remove_meta_box( 'postexcerpt','post','normal' ); // Excerpt Metabox
 remove_meta_box( 'commentstatusdiv','post','normal' ); // Comments Metabox
 remove_meta_box( 'trackbacksdiv','post','normal' ); // Talkback Metabox
 remove_meta_box( 'slugdiv','post','normal' ); // Slug Metabox
 remove_meta_box( 'authordiv','post','normal' ); // Author Metabox

function remove_default_page_screen_metaboxes() {
 global $post_type;
 remove_meta_box( 'postcustom','page','normal' ); // Custom Fields Metabox
 remove_meta_box( 'postexcerpt','page','normal' ); // Excerpt Metabox
 remove_meta_box( 'commentstatusdiv','page','normal' ); // Comments Metabox
 remove_meta_box('commentsdiv','page','normal'); // Comments
 remove_meta_box( 'trackbacksdiv','page','normal' ); // Talkback Metabox
 remove_meta_box( 'slugdiv','page','normal' ); // Slug Metabox
 remove_meta_box( 'authordiv','page','normal' ); // Author Metabox

Remove Auto Linking of URLs in WordPress Comments

remove_filter('comment_text', 'make_clickable', 9);
  • Nice! I was looking for that make_clickable() function to apply it to the_content! Why didn't they do it in the first place? It's as simple as adding add_filter( 'the_content', 'make_clickable'); Alternatively it could be done when the post is saved by using a different hook
    – fregante
    Commented Jan 11, 2014 at 0:57

Extending Auto Logout Period

Tested on: Wordpress 3.0.1

Using the code below you can increase the time cookies are kept and therefor users who are logged in remain logged in longer:

function keep_me_logged_in_for_1_year( $expirein ) {
   return 31556926; // 1 year in seconds
add_filter( 'auth_cookie_expiration', 'keep_me_logged_in_for_1_year' );

Add a "Settings" link for plugins on the plugin list page

Set "Settings" link for plugins on plugin-page in WordPress backend, easy to use jump to settings for users (the code is also with an solution for WordPress version smaller 2.9)

// plugin definitions
define( 'FB_BASENAME', plugin_basename( __FILE__ ) );
define( 'FB_BASEFOLDER', plugin_basename( dirname( __FILE__ ) ) );
define( 'FB_FILENAME', str_replace( FB_BASEFOLDER.'/', '', plugin_basename(__FILE__) ) );
function filter_plugin_meta($links, $file) {
  /* create link */
  if ( $file == FB_BASENAME ) {
      sprintf( '<a href="options-general.php?page=%s">%s</a>', FB_FILENAME, __('Settings') )
  return $links;

global $wp_version;
if ( version_compare( $wp_version, '2.7alpha', '>' ) ) {
    add_filter( 'plugin_action_links_' . FB_WM_BASENAME, 'filter_plugin_meta', 10, 2);
} else {
    add_filter( 'plugin_action_links', 'filter_plugin_meta', 10, 2 );
  • I have attempted to use this code but it seem that it does not work on wordpress 3.1. Can you confirm and update Commented Feb 22, 2011 at 20:37
  • @NetConstructor.com I have update a little bid from one of my free plugins, on all my plugins works fine this
    – bueltge
    Commented Feb 28, 2011 at 17:23
  • I wish all plugin authors would do this (for the plugins that have settings pages, of course) so this kind of code wouldn't be necessary.
    – JimmyPena
    Commented Dec 6, 2011 at 19:00

Add page template filter to page listing

Tested on: WP 3.1

Adds a page template filter to the page listing, so you can view a list of pages that have a given template attached.

class Page_Template_Filter {
    private $templates = array();
    public function __construct() {
        // If it's not the admin area or the current user can't edit pages let's just bail here
        if( !is_admin() || !current_user_can('edit_pages') )
        add_action( 'parse_query',           array( $this, 'pt_parse_query' ) );
        add_action( 'restrict_manage_posts', array( $this, 'pt_restrict_manage_posts' ) );
    public function pt_parse_query( $query ) {
        global $pagenow, $post_type;
        if( 'edit.php' != $pagenow )

        switch( $post_type ) {
            case 'post':

            case 'page':
                $this->templates = get_page_templates();

                if( empty( $this->templates ) )

                if( !$this->is_set_template() )

                $meta_group = array( 'key' => '_wp_page_template', 'value' => $this->get_template() );
                set_query_var( 'meta_query', array( $meta_group ) );
    public function pt_restrict_manage_posts() {
        if( empty( $this->templates ) )
    private function get_template() {
        if( $this->is_set_template() )
            foreach( $this->templates as $template ) {
                if( $template != $_GET['page_template'] )
                return $template;
        return '';
    private function is_set_template() {
        return (bool) ( isset( $_GET['page_template'] ) && ( in_array( $_GET['page_template'], $this->templates ) ) );
    private function template_dropdown() {
        <select name="page_template" id="page_template">
            <option value=""> - no template - </option>
            <?php foreach( $this->templates as $name => $file ): ?>
            <option value="<?php echo $file; ?>"<?php selected( $this->get_template() == $file ); ?>><?php _e( $name ); ?></option>
            <?php endforeach;?>

add_action('admin_init', 'load_ptf');
function load_ptf() {
    $Page_Template_Filter = new Page_Template_Filter;

Requires at least 3.1 to work, though the meta_query could be replaced with the older meta_key and meta_value for 3.0.

  • 1
    works flawlessly, tested in 3.4-alpha
    – brasofilo
    Commented Apr 2, 2012 at 13:01

Only show posts and media of the logged-in Author & fix the post/media counts on the filter bars.

Tested on: Wordpress 3.4.1

By default, WordPress allows Authors to see the titles of other users posts, unpublished drafts, and all media, even though they cannot be edited.

Use this code to only allow posts and media of the currently logged in Author to be displayed.

Unlike other solutions, this also fixes the post/media count on the filter bars (All|Published|Draft|Pending|Trash; All|Images|Videos|Unattached).

// Show only posts and media related to logged in author
add_action('pre_get_posts', 'query_set_only_author' );
function query_set_only_author( $wp_query ) {
    global $current_user;
    if( is_admin() && !current_user_can('edit_others_posts') ) {
        $wp_query->set( 'author', $current_user->ID );
        add_filter('views_edit-post', 'fix_post_counts');
        add_filter('views_upload', 'fix_media_counts');

// Fix post counts
function fix_post_counts($views) {
    global $current_user, $wp_query;
    $types = array(
        array( 'status' =>  NULL ),
        array( 'status' => 'publish' ),
        array( 'status' => 'draft' ),
        array( 'status' => 'pending' ),
        array( 'status' => 'trash' )
    foreach( $types as $type ) {
        $query = array(
            'author'      => $current_user->ID,
            'post_type'   => 'post',
            'post_status' => $type['status']
        $result = new WP_Query($query);
        if( $type['status'] == NULL ):
            $class = ($wp_query->query_vars['post_status'] == NULL) ? ' class="current"' : '';
            $views['all'] = sprintf(__('<a href="%s"'. $class .'>All <span class="count">(%d)</span></a>', 'all'),
        elseif( $type['status'] == 'publish' ):
            $class = ($wp_query->query_vars['post_status'] == 'publish') ? ' class="current"' : '';
            $views['publish'] = sprintf(__('<a href="%s"'. $class .'>Published <span class="count">(%d)</span></a>', 'publish'),
        elseif( $type['status'] == 'draft' ):
            $class = ($wp_query->query_vars['post_status'] == 'draft') ? ' class="current"' : '';
            $views['draft'] = sprintf(__('<a href="%s"'. $class .'>Draft'. ((sizeof($result->posts) > 1) ? "s" : "") .' <span class="count">(%d)</span></a>', 'draft'),
        elseif( $type['status'] == 'pending' ):
            $class = ($wp_query->query_vars['post_status'] == 'pending') ? ' class="current"' : '';
            $views['pending'] = sprintf(__('<a href="%s"'. $class .'>Pending <span class="count">(%d)</span></a>', 'pending'),
        elseif( $type['status'] == 'trash' ):
            $class = ($wp_query->query_vars['post_status'] == 'trash') ? ' class="current"' : '';
            $views['trash'] = sprintf(__('<a href="%s"'. $class .'>Trash <span class="count">(%d)</span></a>', 'trash'),
    return $views;

// Fix media counts
function fix_media_counts($views) {
    global $wpdb, $current_user, $post_mime_types, $avail_post_mime_types;
    $views = array();
    $_num_posts = array();
    $count = $wpdb->get_results( "
        SELECT post_mime_type, COUNT( * ) AS num_posts 
        FROM $wpdb->posts 
        WHERE post_type = 'attachment' 
        AND post_author = $current_user->ID 
        AND post_status != 'trash' 
        GROUP BY post_mime_type
    ", ARRAY_A );
    foreach( $count as $row )
        $_num_posts[$row['post_mime_type']] = $row['num_posts'];
    $_total_posts = array_sum($_num_posts);
    $detached = isset( $_REQUEST['detached'] ) || isset( $_REQUEST['find_detached'] );
    if ( !isset( $total_orphans ) )
        $total_orphans = $wpdb->get_var("
            SELECT COUNT( * ) 
            FROM $wpdb->posts 
            WHERE post_type = 'attachment' 
            AND post_author = $current_user->ID 
            AND post_status != 'trash' 
            AND post_parent < 1
    $matches = wp_match_mime_types(array_keys($post_mime_types), array_keys($_num_posts));
    foreach ( $matches as $type => $reals )
        foreach ( $reals as $real )
            $num_posts[$type] = ( isset( $num_posts[$type] ) ) ? $num_posts[$type] + $_num_posts[$real] : $_num_posts[$real];
    $class = ( empty($_GET['post_mime_type']) && !$detached && !isset($_GET['status']) ) ? ' class="current"' : '';
    $views['all'] = "<a href='upload.php'$class>" . sprintf( __('All <span class="count">(%s)</span>', 'uploaded files' ), number_format_i18n( $_total_posts )) . '</a>';
    foreach ( $post_mime_types as $mime_type => $label ) {
        $class = '';
        if ( !wp_match_mime_types($mime_type, $avail_post_mime_types) )
        if ( !empty($_GET['post_mime_type']) && wp_match_mime_types($mime_type, $_GET['post_mime_type']) )
            $class = ' class="current"';
        if ( !empty( $num_posts[$mime_type] ) )
            $views[$mime_type] = "<a href='upload.php?post_mime_type=$mime_type'$class>" . sprintf( translate_nooped_plural( $label[2], $num_posts[$mime_type] ), $num_posts[$mime_type] ) . '</a>';
    $views['detached'] = '<a href="upload.php?detached=1"' . ( $detached ? ' class="current"' : '' ) . '>' . sprintf( __( 'Unattached <span class="count">(%s)</span>', 'detached files' ), $total_orphans ) . '</a>';
    return $views;
  • good snippet, only one drawback, if no media items are in the library it spits out errors cause the result isnt an array.
    – chrismccoy
    Commented Feb 25, 2012 at 0:38
  • I defined $_num_posts as an array. This should fix the errors you get when no media items are in the library.
    – Paul
    Commented Aug 16, 2012 at 21:02
  • I know it's quite long time to ask about it, but I tried with my cpt and the post count seem not work although I've changed all the tour type to my cpt. Also, are there any way to apply the filter for terms in my cpt too? By the way, thank you so much for your code. Commented Feb 14, 2020 at 0:06

Enable oEmbed in Text/HTML Widgets

add_filter( 'widget_text', array( $wp_embed, 'run_shortcode' ), 8 );
add_filter( 'widget_text', array( $wp_embed, 'autoembed'), 8 );

I use this for youtube video widgets and flickr stuff.


Collection of quick function.php edits

I have a few awesome tweaks in functions.php as well. Found most of these by searching for them over the years.

Excerpt Ending

function new_excerpt_more($more) {
    return '...';
add_filter('excerpt_more', 'new_excerpt_more');

Replace WP Admin Logo

function new_admin_logo() {
  echo '<style type="text/css">#header-logo { background-image: url('.get_bloginfo('template_directory').'/images/admin_logo.png) !important; }</style>';
add_action('admin_head', 'new_admin_logo');

Custom Favicon WP-Admin

function admin_favicon() {
 echo '<link rel="shortcut icon" type="image/x-icon" href="' . get_bloginfo('template_directory') . '/images/favicon.ico" />';
add_action( 'admin_head', 'admin_favicon' );

Custom Admin Footer

function custom_admin_footer() {
echo 'Welcome to my blog! No More Documentation Links!';
add_filter('admin_footer_text', 'custom_admin_footer');
  • thanks but these have already been added. Commented Nov 8, 2010 at 15:12
  • could you please go through these and ensure there are no duplicate entires and split each one up into its own answer within the next few weeks? Commented Jan 26, 2011 at 14:30

Return the number of comments

This is like count_user_posts(), but returns the number of comments instead:

function count_user_comments($id) {
global $wpdb;
$users = $wpdb->get_var("
        SELECT COUNT( * ) AS total
        FROM $wpdb->comments
        WHERE comment_approved = 1 
        AND user_id = $id");
return $users;

More: Count User's posts (including custom post types) or comments:

function atom_count($user_id, $what_to_count = 'post') {
  global $wpdb;    
  $where = $what_to_count == 'comment' ? "WHERE comment_approved = 1 AND user_id = {$user_id}" : get_posts_by_author_sql($what_to_count, TRUE, $user_id);
  $from = "FROM ".(($what_to_count == 'comment') ? $wpdb->comments : $wpdb->posts);    
  $count = $wpdb->get_var($wpdb->prepare("SELECT COUNT(*) {$from} {$where}"));
  return $count;

Usage examples:

<?php echo atom_count(1, 'movie'); // displays 'movie' post type count ?>

<?php echo atom_count(1, 'comment'); // displays comment count ?>


Remove XML-RPC when not in use for performance boost

Tested on: Wordpress 3.0.1

WordPress uses a CURL operation to test for SSL capability for XML-RPC. If you're using XML-RPC but not using, then you can remove the filter. This is a small performance boost (since basically WP does a cURL GET on the https url and either 1) gets a denied message, or 2) times out, and it can take upwards of 5 seconds), but in our case it actually prevented a gateway timeout where a proxy was timing out before the cURL GET was timing out rendering XML-RPC unusable.

// Prevents WordPress from testing ssl capability on domain.com/xmlrpc.php?rsd
  • Thanks for the code suggestion. One question, if you are using XML-RPC but not using the SSL capabilities would the including of this code speed things up at all? If not, in what situations would the inclusion of this code serve a benefit? Commented Sep 14, 2010 at 2:37
  • It has a minuscule effect on performance for XML-RPC calls, since they no longer have to check for SSL capability via an HTTP request.
    – gabrielk
    Commented Sep 19, 2010 at 17:57

Grab all custom fields globally

function get_custom_field($key, $echo = FALSE) {
    global $post;
    $custom_field = get_post_meta( $post->ID, $key, true );
    if ( $echo == false ) 
        return $custom_field;
    echo $custom_field;

Then call the field with a single line

<?php get_custom_field('custom-field-name', TRUE); ?>
  • Why would someone use this? What's the benefit?
    – matt
    Commented Dec 5, 2010 at 5:10
  • 2
    for sites / themes that use a lot of custom fields (which I use often for client work) it allows for less code in the theme, and also for adding conditionals on whether or not to display the field at all.
    – Norcross
    Commented Dec 10, 2010 at 22:44

Remove Private and Protected Prefix

This function removes the "Privite:" prefix from posts and pages marked private. Useful for content only visible to logged in users or groups.

function the_title_trim($title) {
$title = attribute_escape($title);
$findthese = array(
$replacewith = array(
    '', // What to replace "Protected:" with
    '' // What to replace "Private:" with
$title = preg_replace($findthese, $replacewith, $title);
return $title;
add_filter('the_title', 'the_title_trim');

EDIT: Updated to include the removal of Protected: as well.


Custom excerpt length

function excerpt($num) {
    $limit = $num+1;
    $excerpt = explode(' ', get_the_excerpt(), $limit);
    $excerpt = implode(" ",$excerpt)."... (<a href='" .get_permalink($post->ID) ." '>Read more</a>)";
    echo $excerpt;

Limit the length of the displayed excerpt by writing in the theme: excerpt('20');

Example: <?php excerpt('22'); ?> This will limit the excerpt to 22 characters.

The excerpt will be interupted with ... (Read More)


Loading scripts conditionally

Here is a way to load scripts only if a particular shortcode or widget is present. source: Loading scripts only if a particular shortcode or widget is present

function has_my_shortcode($posts) {
    if ( empty($posts) )
        return $posts;
    $found = false;
    foreach ($posts as $post) {
        if ( stripos($post->post_content, '[my_shortcode') )
            $found = true;
    if ($found){
        $urljs = get_bloginfo( 'template_directory' ).IMP_JS;
    wp_register_script('my_script', $urljs.'myscript.js' );
    return $posts;
add_action('the_posts', 'has_my_shortcode');

And here is how to load scripts only if a certain widget is present

To load the script in the page where the widget is loaded only, you will have to add the is_active_widget() code, in you widget class. E.g., see the default recent comments widget (wp-includes/default-widgets.php, line 602):

class WP_Widget_Recent_Comments extends WP_Widget {
    function WP_Widget_Recent_Comments() {
        $widget_ops = array('classname' => 'widget_recent_comments', 'description' => __( 'The most recent comments' ) );
        $this->WP_Widget('recent-comments', __('Recent Comments'), $widget_ops);
        $this->alt_option_name = 'widget_recent_comments';
        if ( is_active_widget(false, false, $this->id_base) )
        add_action( 'wp_head', array(&$this, 'recent_comments_style') );
        add_action( 'comment_post', array(&$this, 'flush_widget_cache') );
        add_action( 'transition_comment_status', array(&$this, 'flush_widget_cache') );

Custom Dashboard CSS

/* Change WordPress dashboard CSS */
function custom_admin_styles() {
    echo '<style type="text/css">#wphead{background:#069}</style>';
add_action('admin_head', 'custom_admin_styles');

You can add any changes to the css between the tags.


Post Word Count

Tested on: Wordpress 3.0.1

(Originally extracted from the Post Word Count plug-in by Nick Momrick)

Adds a count of total published words to the bottom of the "Right Now" box on the admin dashboard. Useful if you're using your blog as an outlet for something like NaNoWriMo or if you just want to keep track of how prolific your blogging skills have become.

function post_word_count() {
    $count = 0;
    $posts = get_posts( array(
        'numberposts' => -1,
        'post_type' => array( 'post', 'page' )
    foreach( $posts as $post ) {
        $count += str_word_count( strip_tags( get_post_field( 'post_content', $post->ID )));
    $num =  number_format_i18n( $count );
    // This block will add your word count to the stats portion of the Right Now box
    $text = _n( 'Word', 'Words', $num );
    echo "<tr><td class='first b'>{$num}</td><td class='t'>{$text}</td></tr>";
    // This line will add your word count to the bottom of the Right Now box.
    echo '<p>This blog contains a total of <strong>' . $num . '</strong> published words!</p>';

// add to Content Stats table
add_action( 'right_now_content_table_end', 'post_word_count');
// add to bottom of Activity Box
add_action('activity_box_end', 'post_word_count');

Kudos to Rarst for the query-free cleanup of the code!

  • Thanks for the assist, Rarst. I typically don't like to include direct database queries in plug-in function.php code, but like I said it was originally taken from someone else's plug-in.
    – EAMann
    Commented Sep 15, 2010 at 16:56
  • np, I tried this long time ago and it was a mess. :) Now with upgraded skills it was time to do it right. Why left old output part? I think it makes sense to display it with rest of stats. btw this version gives different total (comparing to explode), this is probably because of filters along the way and such when fetching via API.
    – Rarst
    Commented Sep 15, 2010 at 17:05
  • The difference in post count is a result of filters ... but using get_posts() will likely be a more accurate word count anyway. I left the old output line simply because that's how I've been using it ... more a difference of opinion than anything else ... I'll re-add your example to add it to the stats so people can pick.
    – EAMann
    Commented Sep 15, 2010 at 17:17

Add parent page slug to body_class

* Function body_class_section
* Add the top level page to the body class for coloured sections


function body_class_section($classes) {
    global $wpdb, $post;
    if (is_page()) {
        if ($post->post_parent) {
            $parent  = end(get_post_ancestors($current_page_id));
        } else {
            $parent = $post->ID;
        $post_data = get_post($parent, ARRAY_A);
        $classes[] = 'section-' . $post_data['post_name'];
    return $classes;

This filter adds a unique body class based on the highest level parent of the current page. I use this for sites that have specific colours or layouts for each section of the site. It works best with sites based around pages. CSS examples:

.section-about { background: red; }
.section-portfolio { background: blue; }

Your theme must also make use of the body_class function.

Fix oEmbed flash objects

* Function my_oembed_wmode
* Fix oEmbed window mode for flash objects

add_filter('embed_oembed_html', 'my_oembed_wmode', 1);

function my_oembed_wmode( $embed ) {
    if ( strpos( $embed, '<param' ) !== false ) {
        $embed = str_replace( '<embed', '<embed wmode="transparent" ', $embed );
        $embed = preg_replace( '/param>/', 'param><param name="wmode" value="transparent" />', $embed, 1);
    return $embed;

I have had problems in the past where oEmbed Flash objects collide with drop down navigation menus. This filter fixes that problem by adding a transparent window mode to the embeds.

Remove the "comments" column from Admin page list

* Function custom_pages_columns
* Remove "comments" from pages overview (rarely use comments on pages)

add_filter('manage_pages_columns', 'custom_pages_columns');

function custom_pages_columns($defaults) {
    return $defaults;

I hardly ever make use of commenting on pages and this helps keep things tidy in the WordPress dashboard.


Display Posts from Different Custom Post Types on homepage

By dropping the following code on the bottom of this post into your functions.php file you can get wordpress to automatically display posts from different custom post types you have created. Currently by default wordpress only display posts which belong to the default "posts" post type.

In the example provided below you will need to change the section which calls:

$query->set( 'post_type', array('post', 'page', 'services', 'attachment'));

With your own custom post types which you would like to include in the homepage post list results. In this case we are asking wordpress to return to us all posts belonging to the default "post" and "page" post_type then asking wordpress to also include the custom post type we created for "services" and finally the default wordpress post type of "attachment" which just means that anytime something is added to the media library it will automatically get displayed on the homepage as a separate entry.

// make sure to edit the post types you wanted included in the list below
add_filter( 'pre_get_posts', 'my_homepage_post_list' );
function my_homepage_post_list ( $query ) {
    if ( is_home() && false == $query->query_vars['suppress_filters'] )
        $query->set( 'post_type', array('post', 'page', 'services', 'attachment'));
    return $query;

You can also utilize this custom query in different locations, such as in a custom feed through something like this

if (( is_home() && false == $query->query_vars['suppress_filters'] ) || is_feed())

Enable Numeric Pagination

Tested on: Wordpress 3.0.1

/* Numeric Pagination ********************************************/

function numeric_pagination ($pageCount = 9, $query = null) {

 if ($query == null) {
  global $wp_query;
  $query = $wp_query;

 if ($query->max_num_pages <= 1) {

 $pageStart = 1;
 $paged = $query->query_vars['paged'];

 // set current page if on the first page
 if ($paged == null) {
  $paged = 1;

 // work out if page start is halfway through the current visible pages and if so move it accordingly
 if ($paged > floor($pageCount / 2)) {
  $pageStart = $paged - floor($pageCount / 2);

 if ($pageStart < 1) {
  $pageStart = 1;

 // make sure page start is
 if ($pageStart + $pageCount > $query->max_num_pages) {
  $pageCount = $query->max_num_pages - $pageStart;

 <div id="archive_pagination">
 if ($paged != 1) {
 <a href="<?php echo get_pagenum_link(1); ?>" class="numbered page-number-first"><span>&lsaquo; <?php _e('<< First', 'global'); ?></span></a>
 // first page is not visible...
 if ($pageStart > 1) {
  //echo 'previous';
 for ($p = $pageStart; $p <= $pageStart + $pageCount; $p ++) {
  if ($p == $paged) {
  <span class="numbered page-number-<?php echo $p; ?> current-numeric-page"><?php echo $p; ?></span>
<?php } else { ?>
  <a href="<?php echo get_pagenum_link($p); ?>" class="numbered page-number-<?php echo $p; ?>"><span><?php echo $p; ?></span></a>

 // last page is not visible
 if ($pageStart + $pageCount < $query->max_num_pages) {
  //echo "last";
 if ($paged != $query->max_num_pages) {
  <a href="<?php echo get_pagenum_link($query->max_num_pages); ?>" class="numbered page-number-last"><span><?php _e('>> Last', 'global'); ?> &rsaquo;</span></a>
<?php } ?>


Display Specific Content only for logged in users

Tested on: Wordpress 3.0.1

function content_only4logged_in($content) {

    if ( is_user_logged_in() &&
            !is_null($content) &&
         ) {
        return $content;
    } else {
        $content  = wp_html_excerpt( $content, 80 );
        $content .= ' …';
        $content .= __( 'Sorry, more of this content is only available for logged users.', FB_TEXTDOMAIN );
        return $content;
add_action( 'the_content', 'content_only4logged_in' );

more possibilities and informations on the post http://wpengineer.com/2046/control-the-wordpress-content-via-userrights-or-time/

  • I can't get this to display altered content for non-logged in users... the first part works fine, but it the user is not logged in and the page is marked private, I just get served the regular 404? Commented Feb 9, 2011 at 20:58

Check if a post has embedded content.

Check if a post has embedded content, works inside the loop using the current post's ID, or alternatively can be passed an ID to determine the post to check for embedded content.

function has_embed( $post_id = false ) {
    if( !$post_id ) $post_id = get_the_ID();
    else $post_id = absint( $post_id );
    if( !$post_id ) return false;

    $post_meta = get_post_custom_keys( $post_id );
    $post_meta = array_map( 'trim' , $post_meta );

    foreach( $post_meta as $meta ) {
        if( '_oembed' != substr( $meta , 0 , 7 ) )
        return true;
    return false;

You'd use the function in the same way you check if a post has a tag..

if( has_embed() ) {
   // do whatever

Function returns true if an embed is found, false on fail.

  • Interesting, but I'm wondering, why would you use it? What kind of applications does it have?
    – matt
    Commented Dec 5, 2010 at 5:08
  • Checking if a post has an embed on a page that displays excerpts would be one use(and it's the original use case i wrote it for). Other possible use cases would be with users who write their own theme templates and want to provide functionality dependant on whether a post(or type) has embedded content, without the need for a filter on the_content or numerous get_post_custom_keys calls.
    – t31os
    Commented Dec 5, 2010 at 9:34

Pre-populating post types

Here is one for this collection.

// This auto populates post types and posts.

add_filter( 'default_content', 'my_editor_content' );

function my_editor_content( $content ) {

    global $post_type;

    switch( $post_type ) {
        case 'your_post_type_here': //auto populate
            $content = 'The content you want to pre-populate the post type with.';

    return $content;

This can come in handy for when you need to post the same info over and over again with slight differences.

  • Nice one! I like this simple option. Can you expand this by possible showing ways of automatically populating custom fields or other criteria/options or possibly even the means of auto-inserting media? Commented Nov 11, 2011 at 23:09
  • I can definitely see about expanding it. I have not really tried taking it further yet.
    – Nicole
    Commented Nov 14, 2011 at 14:31
  • Would love to see ways to expand this
    – JasonDavis
    Commented Apr 11, 2012 at 9:09

Make your Shortlinks Shorter by Removing WWW

Tested on: Wordpress 3.0.1

Make your shortlinks shorter if you include www. in your domain. Via scratch99.com:

function sjc_alter_shortlink($shortlink) {
    $shortlink = preg_replace('/^(https?:\/\/)?(www\.)/','$1',$shortlink);
    return $shortlink;
  • 3
    A check should be added to make sure the string "www." is only removed if it is found at the very beginning of the domain part of the original URL. Naively replacing it anywhere in the URL will lead to bugs if it had been used on a domain like owww.com (which actually appears to be running WordPress) :)
    – Ingve
    Commented May 28, 2012 at 21:30
  • @Ingve I fixed it, now it will remove only the initial www
    – fregante
    Commented Jan 11, 2014 at 1:04

Not the answer you're looking for? Browse other questions tagged or ask your own question.