The more customization I make to WordPress the more I start thinking about if I should be organizing this file or splitting it up.

More specifically, if I have a bunch of custom functions which only apply to the admin area and others which just apply to my public website is there any reason to possibly include all admin functions within their own file or group them together?

Would splitting them up into separate files or grouping them together possibly speed up a WordPress website or does WordPress/php automatically skip over functions which have an is_admin code prefix?

What's the best way to deal with a large functions file (mine is 1370 lines long).

link|improve this question

feedback

2 Answers

up vote 19 down vote accepted

If you are getting to the point where the code in your theme's functions.php is starting to overwhelm you I would definitely say you are ready to consider splitting it up into multiple files. I tend to do that almost by second nature at this point.

Use Include Files in your Theme's functions.php File

I create a subdirectory called "includes" under my theme directory and segment my code into include files organized by what makes sense to me at the time (which means I'm constantly refactoring and moving code around as a site evolves.) I also rarely put any real code in functions.php; everything goes in the include files; just my preference.

Just to give you an example here's my test install that I use to test my answers to questions here on WordPress Answers. Every time I answer a question I keep the code around in case I need it again. This isn't exactly what you'll do for a live site but it shows the mechanics of splitting up the code:

<?php 
/*
 * functions.php
 * 
 */
require_once('includes/null-meta-compare.php');
require_once('includes/older-examples.php');
require_once('includes/wp-admin-menu-classes.php');
require_once('includes/admin-menu-function-examples.php');
require_once('includes/cpt-filtering-in-admin.php'); // WA: Adding a Taxonomy Filter to Admin List for a Custom Post Type?http://wordpress.stackexchange.com/questions/578/
require_once('includes/category-fields.php');
require_once('includes/post-list-shortcode.php');
require_once('includes/car-type-urls.php');
require_once('includes/buffer-all.php');
require_once('includes/get-page-selector.php');
require_once('includes/top-5-posts-per-category.php'); // http://wordpress.stackexchange.com/questions/907/
require_once('includes/alternate-category-metabox.php');  // http://wordpress.stackexchange.com/questions/951/
require_once('includes/remove-status.php');  // http://lists.automattic.com/pipermail/wp-hackers/2010-August/034384.html
require_once('includes/301-redirects.php');  // http://wordpress.stackexchange.com/questions/1027/removing-the-your-backup-folder-might-be-visible-to-the-public-message-generate

Or Create Plugins

Another option it to start grouping your code by function and create your own plugins. For me I start coding in the theme's functions.php file and by the time I get the code fleshed out I've moved most of my code into plugins.

However NO Significant Performance Gain From PHP Code Organization

On the other hand structuring your PHP files is 99% about creating order and maintainability and 1% about performance, if that (organizing .js and .css files called by the browser via HTTP is a completely different case and has huge performance implications.) But how you organize your PHP code on the server pretty much doesn't matter from a performance perspective.

And Code Organization is Personal Preference

And last but not least code organization is personal preference. Some people would hate how I organize code just as I might hate how they do it too. Find something you like and stick with it, but allow your strategy to evolve over time as you learn more and get more comfortable with it.

link|improve this answer
Nice answer, I just arrived to this point where i need to split the functions file. When do you think it's handy to move from frunctions.php to a plugin. You said in your answer: by the time I get the code fleshed out I've moved most of my code into plugins. I do not understand that fully, what do you mean with fleshed out. – Saif Bechan Aug 16 '11 at 7:02
+1 for "or create plugins". More specifically, "functionality plugins" – Ian Dunn Apr 18 at 21:29
feedback

in terms of breaking it up, in my boiler plate I use a custom function to look for a folder called functions in the theme directory, if it is not there it creates it. Then is creates an array of all the .php files it finds in that folder (if any) and runs an include(); on each of them.

That way, each time I need to write some new functionality, I just add a PHP file to the functions folder, and don't have to worry about coding it into the site.

<?php
/* 
FUNCTIONS for automatically including php documents from the functions folder.
*/
//if running on php4, make a scandir functions
if (!function_exists('scandir')) {
  function scandir($directory, $sorting_order = 0) {
    $dh = opendir($directory);
    while (false !== ($filename = readdir($dh))) {
      $files[] = $filename;
    }
    if ($sorting_order == 0) {
      sort($files);
    } else {
      rsort($files);
    }
    return ($files);
  }
}
/*
* this function returns the path to the funtions folder.
* If the folder does not exist, it creates it.
*/
function get_function_directory_extension($template_url = FALSE) {
  //get template url if not passed
  if (!$template_url)$template_url = get_bloginfo('template_directory');


  //replace slashes with dashes for explode
  $template_url_no_slash = str_replace('/', '.', $template_url);

  //create array from URL
  $template_url_array = explode('.', $template_url_no_slash);

  //--splice array

  //Calculate offset(we only need the last three levels)
  //We need to do this to get the proper directory, not the one passed by the server, as scandir doesn't work when aliases get involved.
  $offset = count($template_url_array) - 3;

  //splice array, only keeping back to the root WP install folder (where wp-config.php lives, where the front end runs from)
  $template_url_array = array_splice($template_url_array, $offset, 3);
  //put back togther as string
  $template_url_return_string = implode('/', $template_url_array);
  fb::log($template_url_return_string, 'Template'); //firephp

  //creates current working directory with template extention and functions directory    
  //if admin, change out of admin folder before storing working dir, then change back again.
  if (is_admin()) {
    $admin_directory = getcwd();
    chdir("..");
    $current_working_directory = getcwd();
    chdir($admin_directory);
  } else {
    $current_working_directory = getcwd();
  }
  fb::log($current_working_directory, 'Directory'); //firephp

  //alternate method is chdir method doesn't work on your server (some windows servers might not like it)
  //if (is_admin()) $current_working_directory = str_replace('/wp-admin','',$current_working_directory);

  $function_folder = $current_working_directory . '/' . $template_url_return_string . '/functions';


  if (!is_dir($function_folder)) mkdir($function_folder); //make folder, if it doesn't already exist (lazy, but useful....ish)
  //return path
  return $function_folder;

}

//removed array elements that do not have extension .php
function only_php_files($scan_dir_list = false) {
  if (!$scan_dir_list || !is_array($scan_dir_list)) return false; //if element not given, or not array, return out of function.
  foreach ($scan_dir_list as $key => $value) {
    if (!strpos($value, '.php')) {

      unset($scan_dir_list[$key]);
    }
  }
  return $scan_dir_list;
}
//runs the functions to create function folder, select it,
//scan it, filter only PHP docs then include them in functions

add_action('wp_head', fetch_php_docs_from_functions_folder(), 1);
function fetch_php_docs_from_functions_folder() {

  //get function directory
  $functions_dir = get_function_directory_extension();
  //scan directory, and strip non-php docs
  $all_php_docs = only_php_files(scandir($functions_dir));

  //include php docs
  if (is_array($all_php_docs)) {
    foreach ($all_php_docs as $include) {
      include($functions_dir . '/' . $include);
    }
  }

}
link|improve this answer
3  
@mildfuzz: Nice trick. I personally wouldn't use it for production code because it does for every page load what we could easily do once when we launch the site. Also, I'd add in some way to omit files, like not loading anything starting with an underscore so I could still store works in progress in the theme directory. Otherwise, nice! – MikeSchinkel Sep 6 '10 at 19:55
love the idea but I agree this might possibly lead to unnecessary loading for each request. Any idea if there would be a simple way to have the final functions.php file being generated automatically cached with some type of update if/when new files are added or at a specific time interval? – NetConstructor.com Sep 7 '10 at 4:27
Nice but it leads to inflexibilities, also what happens if an attacker manages to drop their code in there? And what if the ordering of includes is important? – Tom J Nowell Sep 7 '10 at 12:09
1  
@MikeSchinkel I just call my working files foo._php, then drop the _php when I want it to run. – Mild Fuzz Sep 10 '10 at 15:25
@NetConstructor: Would be interested in some sollution too. – kaiser Feb 1 '11 at 7:35
show 2 more comments
feedback

Your Answer

 
or
required, but never shown

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