it-swarm-vi.com

Mã tổ chức trong tệp tin.php của WordPress Theme của bạn?

Càng nhiều tùy chỉnh tôi thực hiện cho WordPress, tôi càng bắt đầu suy nghĩ về việc tôi nên tổ chức tệp này hay tách nó ra.

Cụ thể hơn, nếu tôi có một loạt các chức năng tùy chỉnh chỉ áp dụng cho khu vực quản trị viên và các chức năng khác chỉ áp dụng cho trang web công cộng của tôi thì có lý do gì để có thể bao gồm tất cả các chức năng quản trị trong tệp riêng của họ hoặc nhóm chúng lại với nhau không?

Việc chia chúng thành các tệp riêng biệt hoặc nhóm chúng lại với nhau có thể tăng tốc trang web WordPress hay WordPress/PHP sẽ tự động bỏ qua các chức năng có tiền tố mã is_admin?

Cách tốt nhất để xử lý một tệp chức năng lớn (của tôi dài 1370 dòng).

91
NetConstructor.com

Nếu bạn đang đi đến điểm mà mã trong functions.php của chủ đề của bạn bắt đầu áp đảo bạn, tôi chắc chắn sẽ nói rằng bạn đã sẵn sàng xem xét chia nó thành nhiều tệp. Tôi có xu hướng làm điều đó gần như bởi bản chất thứ hai vào thời điểm này.

Sử dụng Bao gồm tệp trong tệp functions.php của chủ đề của bạn

Tôi tạo một thư mục con có tên "bao gồm" trong thư mục chủ đề của tôi và phân đoạn mã của tôi thành các tệp được sắp xếp theo ý nghĩa của tôi tại thời điểm đó (có nghĩa là tôi liên tục tái cấu trúc và di chuyển mã xung quanh khi trang web phát triển. ) Tôi cũng hiếm khi đặt bất kỳ mã thực nào vào functions.php; tất cả mọi thứ đi trong các tập tin bao gồm; chỉ là sở thích của tôi.

Chỉ để cung cấp cho bạn một ví dụ ở đây cài đặt thử nghiệm của tôi mà tôi sử dụng để kiểm tra câu trả lời của mình cho các câu hỏi ở đây trên Câu trả lời WordPress. Mỗi khi tôi trả lời một câu hỏi, tôi sẽ giữ mã xung quanh trong trường hợp tôi cần lại. Đây không phải là chính xác những gì bạn sẽ làm cho một trang web trực tiếp nhưng nó cho thấy các cơ chế phân tách mã:

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

Hoặc tạo plugin

Một tùy chọn khác để bắt đầu nhóm mã của bạn theo chức năng và tạo các plugin của riêng bạn. Đối với tôi, tôi bắt đầu mã hóa trong tệp functions.php của chủ đề và đến khi tôi nhận được mã xác thực, tôi đã chuyển phần lớn mã của mình vào các plugin.

Tuy nhiên KHÔNG CÓ Hiệu suất đáng kể nào đạt được từ PHP Tổ chức mã

Mặt khác, cấu trúc các tệp PHP của bạn là 99% về việc tạo thứ tự và khả năng duy trì và 1% về hiệu suất, nếu điều đó (tổ chức các tệp .js.css được trình duyệt gọi qua HTTP là một trường hợp hoàn toàn khác và có rất nhiều ý nghĩa về hiệu suất.) Nhưng cách bạn tổ chức mã PHP của mình trên máy chủ gần như không quan trọng từ góc độ hiệu suất.

Và tổ chức mã là sở thích cá nhân

Và cuối cùng nhưng không kém phần quan trọng là tổ chức mã là sở thích cá nhân. Một số người sẽ ghét cách tôi tổ chức mã giống như tôi có thể ghét cách họ cũng làm như vậy. Tìm thứ gì đó bạn thích và gắn bó với nó, nhưng cho phép chiến lược của bạn phát triển theo thời gian khi bạn tìm hiểu thêm và thoải mái hơn với nó.

117
MikeSchinkel

Câu trả lời muộn

Cách bao gồm các tệp của bạn đúng cách:

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' );

Các plugin cũng vậy.

Làm thế nào để đi đúng đường hoặc URi

Ngoài ra hãy xem các chức năng API hệ thống tệp như:

  • home_url()
  • plugin_dir_url()
  • plugin_dir_path()
  • admin_url()
  • get_template_directory()
  • get_template_directory_uri()
  • get_stylesheet_directory()
  • get_stylesheet_directory_uri()
  • v.v.

Cách giảm số lượng include/require

Nếu bạn cần tìm nạp các tệp tất cả từ một thư mục, hãy đi với

foreach ( glob( 'path/to/folder/*.php' ) as $file )
    include $file;

Hãy nhớ rằng điều này bỏ qua các lỗi (có thể tốt cho sử dụng sản xuất)/không thể tải các tệp.

Để thay đổi hành vi này, bạn có thể muốn sử dụng một cấu hình khác trong quá trình phát triển:

$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;

Chỉnh sửa: Cách tiếp cận OOP/SPL

Khi tôi vừa trở lại và thấy rằng câu trả lời này ngày càng được nâng cao hơn, tôi nghĩ rằng tôi có thể cho thấy cách mà tôi đang làm ngày nay - trong một thế giới PHP 5.3+. Ví dụ sau đây tải tất cả các tệp từ thư mục con chủ đề có tên src/. Đây là nơi tôi có thư viện của mình xử lý một số tác vụ nhất định như menu, hình ảnh, v.v. Thậm chí bạn không cần phải quan tâm đến tên khi mỗi tệp được tải. Nếu bạn có các thư mục con khác trong thư mục này, chúng sẽ bị bỏ qua.

\FilesystemIterator là PHP 5.3+ siêu tụ điện trên \DirectoryIterator. Cả hai đều là một phần của PHP SPL. Trong khi PHP 5.2 có thể tắt tiện ích mở rộng SPL tích hợp (dưới 1% trong số tất cả các cài đặt đã làm điều đó), SPL hiện là một phần của lõi PHP.

<?php

namespace Theme;

$files = new \FilesystemIterator( __DIR__.'/src', \FilesystemIterator::SKIP_DOTS );
foreach ( $files as $file )
{
    /** @noinspection PhpIncludeInspection */
    ! $files->isDir() and include $files->getRealPath();
}

Trước đây trong khi tôi vẫn hỗ trợ PHP 5.2.x, tôi đã sử dụng giải pháp sau: A \FilterIterator trong thư mục src/Filters để chỉ truy xuất tệp (và không chấm con trỏ của thư mục) và \DirectoryIterator để thực hiện lặp và tải.

namespace Theme;

use Theme\Filters\IncludesFilter;

$files = new IncludesFilter( new \DirectoryIterator( __DIR__.'/src' ) );
foreach ( $files as $file )
{
    include_once $files->current()->getRealPath();
}

\FilterIterator dễ như vậy:

<?php

namespace Theme\Filters;

class IncludesFilter extends \FilterIterator
{
    public function accept()
    {
        return
            ! $this->current()->isDot()
            and $this->current()->isFile()
            and $this->current()->isReadable();
    }
}

Ngoài PHP 5.2 đã chết/EOL cho đến bây giờ (và cả 5.3), có một thực tế là có thêm mã và một tệp nữa trong trò chơi, vì vậy không có lý do gì để đi sau và hỗ trợ PHP 5.2.x.

Tóm tắt

Một bài viết chuyên sâu hơn nữa có thể được tìm thấy ở đây trên WPKrauts .

CHỈNH SỬACách rõ ràng chính xác là sử dụng mã namespaced, được chuẩn bị cho PSR-4 tự động tải bằng cách đặt mọi thứ vào thư mục thích hợp đã được xác định qua không gian tên. Sau đó, chỉ cần sử dụng Trình soạn thảo và một composer.json để quản lý các phụ thuộc của bạn và để nó tự động xây dựng PHP trình tải tự động của bạn (tự động nhập tệp bằng cách chỉ cần gọi use \<namespace>\ClassName). Đó là tiêu chuẩn thực tế trong thế giới PHP, cách dễ nhất để đi và thậm chí còn được tự động hóa và đơn giản hóa hơn bởi WP Starter .

50
kaiser

Tôi thích sử dụng một chức năng cho các tập tin trong một thư mục. Cách tiếp cận này giúp dễ dàng thêm các tính năng mới khi thêm tệp mới. Nhưng tôi viết luôn trong lớp hoặc với các không gian tên - cho phép nó kiểm soát nhiều hơn về Không gian tên của các hàm, phương thức, v.v.

Dưới một ví dụ nhỏ; ut cũng useage với thỏa thuận về lớp * .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;

}

Trong Chủ đề tôi thường sử dụng một kịch bản khác. Tôi xác định chức năng của tệp externel trong ID hỗ trợ, xem ví dụ. Điều đó là hữu ích nếu tôi sẽ dễ dàng hủy kích hoạt feture của tệp externel. Tôi sử dụng hàm WP core require_if_theme_supports() và anh ta chỉ tải, nếu ID hỗ trợ đã hoạt động. Trong ví dụ sau, tôi đã hủy ID được hỗ trợ này trong dòng trước khi tải tệp.

    /**
     * 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'
    );

Bạn có thể thấy nhiều hơn về điều này trong repo của chủ đề này .

5
bueltge

về mặt phá vỡ nó, trong tấm nồi hơi của tôi, tôi sử dụng một chức năng tùy chỉnh để tìm một thư mục có tên là các chức năng trong thư mục chủ đề, nếu nó không ở đó thì nó tạo ra nó. Sau đó, tạo một mảng gồm tất cả các tệp .php mà nó tìm thấy trong thư mục đó (nếu có) và chạy tệp bao gồm (); trên mỗi người trong số họ.

Bằng cách đó, mỗi lần tôi cần viết một số chức năng mới, tôi chỉ cần thêm tệp PHP vào thư mục hàm và không phải lo lắng về việc mã hóa nó vào trang web.

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

}
5
Mild Fuzz

Tôi quản lý một trang web với khoảng 50 loại trang tùy chỉnh duy nhất bằng các ngôn ngữ khác nhau của máy chủ qua cài đặt mạng. Cùng với một TẤN các plugin.

Chúng tôi buộc phải chia tách tất cả tại một số điểm. Một tệp chức năng với 20-30k dòng mã không hài hước chút nào.

Chúng tôi quyết định hoàn thành tái cấu trúc tất cả các mã để quản lý cơ sở mã tốt hơn. Cấu trúc chủ đề wordpress mặc định là tốt cho các trang web nhỏ, nhưng không phải cho các trang web lớn hơn.

Hàm mới.php của chúng tôi chỉ chứa những gì cần thiết để bắt đầu trang web, nhưng không có gì thuộc về một trang cụ thể.

Bố cục chủ đề chúng ta sử dụng bây giờ tương tự như mẫu thiết kế MCV, nhưng theo kiểu mã hóa thủ tục.

Ví dụ: trang thành viên của chúng tôi:

trang-thành viên.php . Chịu trách nhiệm khởi tạo trang. Gọi các hàm ajax chính xác hoặc tương tự. Có thể tương đương với phần Bộ điều khiển theo kiểu MCV.

Hàm-thành viên.php . Chứa tất cả các chức năng liên quan đến trang này. Điều này cũng được bao gồm trong các trang khác của máy chủ cần chức năng cho các thành viên của chúng tôi.

nội dung-thành viên.php . Chuẩn bị dữ liệu cho HTML Có thể tương đương với Mô hình trong MCV.

layout-thành viên.php . Phần HTML.

Sau khi chúng tôi thực hiện những thay đổi này, thời gian phát triển đã dễ dàng giảm 50% và bây giờ chủ sở hữu sản phẩm gặp khó khăn khi giao cho chúng tôi các nhiệm vụ mới. :)

4
Patrik Grinsvall

Từ tập tin chủ đề con.php.

    require_once( get_stylesheet_directory() . '/inc/custom.php' );
3
Brad Dalton

Trong hàm.php, một cách thanh lịch hơn để gọi một tệp yêu cầu sẽ là:

yêu cầu xác định vị trí ('/ inc/hàm/shortcodes.php');

0
Imperative Ideas

Tôi đã kết hợp @kaiser 's và @mikechinkel ' s câu trả lời.

Tôi có tất cả các tùy chỉnh cho chủ đề của mình trong thư mục /includes và trong thư mục đó, tôi có mọi thứ được chia thành các thư mục phụ.

Tôi chỉ muốn bao gồm /includes/admin và nội dung phụ của nó khi true === is_admin()

Nếu một thư mục được loại trừ trong iterator_check_traversal_callback bằng cách trả về false thì các thư mục con của nó sẽ không bị lặp lại (hoặc được chuyển đến 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();
}
0
seangwright