在WordPress主题的函数.php文件中组织代码?

时间:2010-09-06 作者:NetConstructor.com

我对WordPress进行的自定义越多,我就越开始考虑是否应该组织或拆分此文件。

更具体地说,如果我有一堆只适用于管理区域的自定义功能,以及其他只适用于我的公共网站的自定义功能,是否有任何理由可能将所有管理功能包含在自己的文件中或将它们组合在一起?

将它们拆分成单独的文件或将它们分组可能会加快WordPress网站的速度吗?WordPress/PHP是否会自动跳过具有is\\U管理代码前缀的函数?

处理大型函数文件的最佳方法是什么(我的是1370行)。

8 个回复
最合适的回答,由SO网友:MikeSchinkel 整理而成

如果您的主题中的代码functions.php 我肯定你已经准备好考虑将其拆分为多个文件。在这一点上,我几乎是自然而然地这样做的。

在主题的functions.php 文件

我在我的主题目录下创建了一个名为“includes”的子目录,并将我的代码分割成包含文件,按照当时对我有意义的内容进行组织(这意味着随着网站的发展,我不断地重构和移动代码)我也很少输入任何真正的代码functions.php; 所有内容都包含在include文件中;这正是我的喜好。

这是我的测试安装,用于测试WordPress答案中的问题答案。每次回答问题时,我都会保留代码,以防再次需要它。这并不完全是您将为实时站点所做的,但它显示了拆分代码的机制:

<?php 
/*
 * functions.php
 * 
 */
require_once( __DIR__ . \'/includes/null-meta-compare.php\');
require_once( __DIR__ . \'/includes/older-examples.php\');
require_once( __DIR__ . \'/includes/wp-admin-menu-classes.php\');
require_once( __DIR__ . \'/includes/admin-menu-function-examples.php\');

// WA: Adding a Taxonomy Filter to Admin List for a Custom Post Type?
// http://wordpress.stackexchange.com/questions/578/
require_once( __DIR__ . \'/includes/cpt-filtering-in-admin.php\'); 
require_once( __DIR__ . \'/includes/category-fields.php\');
require_once( __DIR__ . \'/includes/post-list-shortcode.php\');
require_once( __DIR__ . \'/includes/car-type-urls.php\');
require_once( __DIR__ . \'/includes/buffer-all.php\');
require_once( __DIR__ . \'/includes/get-page-selector.php\');

// http://wordpress.stackexchange.com/questions/907/
require_once( __DIR__ . \'/includes/top-5-posts-per-category.php\'); 

// http://wordpress.stackexchange.com/questions/951/
require_once( __DIR__ . \'/includes/alternate-category-metabox.php\');  

// http://lists.automattic.com/pipermail/wp-hackers/2010-August/034384.html
require_once( __DIR__ . \'/includes/remove-status.php\');  

// http://wordpress.stackexchange.com/questions/1027/removing-the-your-backup-folder-might-be-visible-to-the-public-message-generate
require_once( __DIR__ . \'/includes/301-redirects.php\');  
另一个选项是开始按函数对代码分组并创建自己的插件。对我来说,我开始在主题的functions.php 当我把代码充实起来的时候,我已经把大部分代码移到插件中了。

然而,PHP代码组织并没有显著的性能提升,另一方面,构建PHP文件的99%与创建顺序和可维护性有关,1%与性能有关,如果是这样的话(组织.js.css 浏览器通过HTTP调用的文件是完全不同的情况,具有巨大的性能影响。)但是,从性能角度来看,如何在服务器上组织PHP代码并不重要。

代码组织是个人偏好,最后但并非最不重要的代码组织是个人偏好。有些人会讨厌我如何组织代码,就像我可能也讨厌他们如何组织代码一样。找到你喜欢的东西并坚持下去,但随着时间的推移,随着你学习的越来越多,你的策略也会不断发展,你也会越来越适应它。

SO网友:kaiser

迟交的答复

如何以正确的方式包含文件:

function wpse1403_bootstrap()
{
    // Here we load from our includes directory
    // This considers parent and child themes as well    
    locate_template( array( \'inc/foo.class.php\' ), true, true );
}
add_action( \'after_setup_theme\', \'wpse1403_bootstrap\' );
插件也是如此。

如何获得正确的路径或URi还可以查看文件系统API函数,如:

  • home_url()
  • plugin_dir_url()
  • plugin_dir_path()
  • admin_url()
  • get_template_directory()
  • get_template_directory_uri()
  • get_stylesheet_directory()
  • get_stylesheet_directory_uri()
  • 等。如何减少include/require

如果需要从目录中提取所有文件,请使用

foreach ( glob( \'path/to/folder/*.php\' ) as $file )
    include $file;
请记住,这会忽略故障(可能有利于生产使用)/不可加载的文件。

要更改此行为,您可能需要在开发过程中使用不同的配置:

$files = ( defined( \'WP_DEBUG\' ) AND WP_DEBUG )
    ? glob( \'path/to/folder/*.php\', GLOB_ERR )
    : glob( \'path/to/folder/*.php\' )

foreach ( $files as $file )
    include $file;
编辑:OOP/SPL方法当我刚回来看到这个答案越来越多的支持票时,我想我可以展示一下我现在是如何做到的——在一个PHP 5.3+的世界里。以下示例从名为的主题子文件夹加载所有文件src/. 这就是我的库处理某些任务的地方,如菜单、图像等。在加载每个文件时,你甚至不必关心名称。如果此目录中有其他子文件夹,则会忽略它们。

这个\\FilesystemIterator 是PHP 5.3+超级编码器\\DirectoryIterator. 两者都是PHP SPL的一部分。虽然PHP 5.2使关闭内置SPL扩展成为可能(在所有安装中,只有不到1%的安装关闭了内置SPL扩展),但SPL现在是PHP核心的一部分。

<?php

namespace Theme;

$files = new \\FilesystemIterator( __DIR__.\'/src\', \\FilesystemIterator::SKIP_DOTS );
foreach ( $files as $file )
{
    /** @noinspection PhpIncludeInspection */
    ! $files->isDir() and include $files->getRealPath();
}
之前,我仍然支持PHP 5.2。x、 我使用了以下解决方案:A\\FilterIteratorsrc/Filters 仅检索文件(而不是文件夹的点指针)和\\DirectoryIterator 进行循环和加载。
namespace Theme;

use Theme\\Filters\\IncludesFilter;

$files = new IncludesFilter( new \\DirectoryIterator( __DIR__.\'/src\' ) );
foreach ( $files as $file )
{
    include_once $files->current()->getRealPath();
}
The\\FilterIterator 就这么简单:

<?php

namespace Theme\\Filters;

class IncludesFilter extends \\FilterIterator
{
    public function accept()
    {
        return
            ! $this->current()->isDot()
            and $this->current()->isFile()
            and $this->current()->isReadable();
    }
}
除了PHP 5.2现在已经过时(以及5.3),游戏中还有更多的代码和文件,因此没有理由使用后者并支持PHP 5.2。十、

总结

EDIT 显然正确的方法是namespaced代码,准备用于PSR-4 通过将所有内容放在已通过命名空间定义的适当目录中进行自动加载。那就用吧Composer 和acomposer.json 管理您的依赖关系并让它自动构建PHP自动加载程序(只需调用use \\<namespace>\\ClassName). 这是PHP世界中事实上的标准,是最简单的方法,而且通过WP Starter.

SO网友:bueltge

我喜欢使用一个函数来处理文件夹中的文件。这种方法可以在添加新文件时轻松添加新功能。但我总是在类中或使用名称空间编写-让它对函数、方法等的名称空间有更多的控制。

下面是一个小例子;ut也使用与类有关的协议*。php

public function __construct() {

    $this->load_classes();
}

/**
 * Returns array of features, also
 * Scans the plugins subfolder "/classes"
 *
 * @since   0.1
 * @return  void
 */
protected function load_classes() {

    // load all files with the pattern class-*.php from the directory classes
    foreach( glob( dirname( __FILE__ ) . \'/classes/class-*.php\' ) as $class )
        require_once $class;

}
在主题中,我经常使用其他场景。我在支持ID中定义了externel文件的功能,请参见示例。如果我可以轻松地停用externel文件的feture,那么这是很有用的。我使用WP核心功能require_if_theme_supports() 并且仅在支持ID处于活动状态时加载。在下面的示例中,我在加载文件之前在行中定义了这个受支持的ID。

    /**
     * Add support for Theme Customizer
     * 
     * @since  09/06/2012
     */
    add_theme_support( \'documentation_customizer\', array( \'all\' ) );
    // Include the theme customizer for options of theme options, if theme supported
    require_if_theme_supports( 
        \'documentation_customizer\',
        get_template_directory() . \'/inc/theme-customize.php\'
    );
您可以在repo of this theme.

SO网友:Mild Fuzz

至于分解它,在我的boiler plate中,我使用一个自定义函数在主题目录中查找一个名为functions的文件夹,如果它不在那里,它就会创建它。然后is创建一个包含所有。它在该文件夹中找到的php文件(如果有)并运行include();在他们每个人身上。

这样,每次我需要编写一些新功能时,我只需将一个PHP文件添加到functions文件夹中,而不必担心将其编码到站点中。

<?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);
    }
  }

}

SO网友:Patrik Grinsvall

我通过网络安装管理一个站点,该站点有大约50种不同语言的独特自定义页面类型。还有大量插件。

我们被迫在某个时候将其全部拆分。一个包含20-30k行代码的函数文件一点也不好笑。

我们决定彻底重构所有代码,以便更好地管理代码库。默认的wordpress主题结构适用于小型网站,但不适用于大型网站。

我们的新功能。php只包含启动站点所需的内容,但不包含属于特定页面的内容。

我们现在使用的主题布局类似于MCV设计模式,但采用过程编码风格。

例如,我们的member page:

page-member.php. 负责初始化页面。调用正确的ajax函数或类似函数。可能与MCV样式中的控制器部件等效。

functions-member.php. 包含与此页相关的所有函数。这也包含在其他一些需要为我们的成员提供功能的页面中。

content-member.php. 为HTML准备的数据可能与MCV中的模型等效。

layout-member.php. HTML部分。

在我们做了这些更改之后,开发时间轻松减少了50%,现在产品所有者很难给我们分配新任务。:)

SO网友:Brad Dalton

来自子主题函数。php文件:

    require_once( get_stylesheet_directory() . \'/inc/custom.php\' );

SO网友:Imperative Ideas

在功能上。php,调用所需文件的更优雅的方法是:

一旦找到模板(\'/inc/functions/shortcode.php\'),就需要\\u;

SO网友:seangwright

我合并了@kaiser\'s和@mikeschinkel\'s答案。

我在/includes 文件夹中,我将所有内容分解为子文件夹。

我只想/includes/admin 以及在以下情况下应包含的子内容:true === is_admin()

如果文件夹被排除在iterator_check_traversal_callback 通过返回false 然后它的子目录将不会被迭代(或传递给iterator_check_traversal_callback)

/**
 *  Require all customizations under /includes
 */
$includes_import_root = 
    new \\RecursiveDirectoryIterator( __DIR__ . \'/includes\', \\FilesystemIterator::SKIP_DOTS );

function iterator_check_traversal_callback( $current, $key, $iterator ) {
    $file_name = $current->getFilename();

    // Only include *.php files
    if ( ! $current->isDir() ) {
        return preg_match( \'/^.+\\.php$/i\', $file_name );
    }

    // Don\'t include the /includes/admin folder when on the public site
    return \'admin\' === $file_name
        ? is_admin()
        : true;
}

$iterator_filter = new \\RecursiveCallbackFilterIterator(
    $includes_import_root, \'iterator_check_traversal_callback\'
);

foreach ( new \\RecursiveIteratorIterator( $iterator_filter ) as $file ) {
    include $file->getRealPath();
}

结束

相关推荐

WP-ADMIN似乎正在重定向

我的w-admin登录有一个奇怪的问题。这是从我升级到3.0以后才开始的,当我转到wp admin时,登录表单显示正常,但当我输入用户名并通过时,每次都会再次显示登录表单。使用密码恢复功能会导致电子邮件未找到错误。我知道用户名密码和电子邮件是正确的,b/c我可以访问mysql数据库,我可以看到值(至少用户名和电子邮件) 有人知道会出什么问题吗