it-swarm-ko.tech

WordPress 테마의 functions.php 파일에서 코드 구성?

내가 WordPress에 더 많은 사용자 지정을 할수록이 파일을 구성하거나 분할해야하는지에 대해 생각하기 시작합니다.

좀 더 구체적으로 말하자면, 관리 영역에만 적용되는 커스텀 기능과 내 공개 웹 사이트에만 적용되는 커스텀 기능이있는 경우 모든 관리 기능을 자체 파일에 포함 시키거나 함께 그룹화 할 이유가 있습니까?

별도의 파일로 그룹화하거나 그룹화하여 WordPress 웹 사이트의 속도를 높이거나 WordPress/PHP가 is_admin 코드 접두사가있는 기능을 자동으로 건너 뛸 수 있습니까?

대형 함수 파일 (제 1370 행 길이)을 처리하는 가장 좋은 방법은 무엇입니까?.

91

테마의 functions.php에있는 코드가 압도되기 시작하는 시점에 도달하면 여러 파일로 분할 할 준비가 된 것입니다. 나는이 시점에서 거의 제 2의 본성으로하는 경향이있다.

테마의 functions.php 파일에 포함 파일 사용

내 테마 디렉토리 아래에 "includes"라는 서브 디렉토리를 작성하고 당시에 이해가 잘되는 파일로 코드를 세분화합니다. 사이트도 발전합니다.) 또한 실제 코드를 functions.php; 모든 것은 포함 파일에 들어갑니다. 단지 내 취향.

여기 예를 들어 여기 WordPress Answers의 질문에 대한 답변을 테스트하는 데 사용하는 테스트 설치가 있습니다. 질문에 대답 할 때마다 다시 필요할 때를 대비하여 코드를 보관하십시오. 이것은 실제 사이트에서 수행 할 작업이 아니지만 코드를 나누는 메커니즘을 보여줍니다.

<?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 파일을 구성하는 것은 HTTP를 통해 브라우저에서 호출 한 .js.css 파일을 구성하는 경우 주문 및 유지 관리 성 생성에 대해 99 %, 성능에 대해 1 %입니다 완전히 다른 경우이며 성능에 큰 영향을 미칩니다.) 그러나 서버에서 PHP 코드를 구성하는 방법은 성능 관점에서 중요하지 않습니다.

그리고 코드 조직은 개인 취향입니다

마지막으로 코드 구성은 개인 취향입니다. 어떤 사람들은 코드를 구성하는 방식이 싫은 것처럼 코드를 구성하는 방식을 싫어합니다. 마음에 드는 것을 찾고 고수하지만 시간이 지남에 따라 더 많이 배우고 더 편하게 전략을 발전시킬 수 있습니다.

120
MikeSchinkel

최근 답변

올바른 방법으로 파일을 포함시키는 방법 :

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 수를 줄이는 방법

디렉토리에서 all 파일을 가져와야하는 경우

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\DirectoryIterator의 PHP 5.3 + supercedor 입니다. 둘 다 PHP SPL의 일부입니다. PHP 5.2에서 내장 SPL 확장 기능을 해제 할 수 있었지만 (모든 설치의 1 % 미만이 그랬습니다) 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를 지원했지만 다음 솔루션을 사용했습니다. \FilterIterator 디렉토리의 src/Filters는 파일 만 검색하고 폴더의 도트 포인터는 제외하고 \DirectoryIterator는 반복 및로드를 수행합니다.

namespace Theme;

use Theme\Filters\IncludesFilter;

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

\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.x.

요약

더 깊이있는 기사는 여기서는 WPKrauts 에서 찾을 수 있습니다.

EDIT 분명히 올바른 방법은 PSR-4 자동로드를 위해 준비된 namespaced 코드를 사용하는 것입니다. 네임 스페이스를 통해 이미 정의 된 적절한 디렉토리의 모든 것. 그런 다음 Composercomposer.json를 사용하여 종속성을 관리하고 PHP 오토로더 (use \<namespace>\ClassName를 호출하여 파일을 자동으로 가져옴)를 자동 빌드하십시오. 이것이 가장 쉬운 방법이며 WP Starter 에 의해 훨씬 더 자동화되고 단순화 된 PHP 세계의 사실상의 표준입니다.

50
kaiser

나는 폴더 안에있는 파일에 함수를 사용하고 싶다. 이 방법을 사용하면 새 파일을 추가 할 때 새 기능을 쉽게 추가 할 수 있습니다. 하지만 항상 클래스 또는 네임 스페이스로 씁니다. 함수, 메서드 등의 네임 스페이스에 대해 더 많은 제어권을 부여합니다.

작은 예제 아래; 또한 클래스에 대한 합의와 함께 사용 * .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;

}

Themes에서는 종종 다른 시나리오를 사용합니다. 지원 ID로 externel 파일의 기능을 정의합니다 (예제 참조). externel 파일의 특성을 쉽게 비활성화 할 수 있다면 유용합니다. 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에서 더 많은 것을 볼 수 있습니다 .

5
bueltge

그것을 분해하는 관점에서, 보일러 판에 사용자 정의 함수를 사용하여 테마 디렉토리에있는 함수라는 폴더를 찾습니다. 거기에 없으면 만들어냅니다. 다음은 해당 폴더에서 발견 된 모든 .php 파일의 배열을 생성하고 include ()를 실행합니다. 그들 각각에.

그런 식으로 새로운 기능을 추가해야 할 때마다 function 폴더에 PHP 파일을 추가하기 만하면되므로 사이트에 코딩하는 것에 대해 걱정할 필요가 없습니다.

<?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

네트워크 설치를 통해 여러 언어로 된 약 50 개의 고유 한 사용자 정의 페이지 유형으로 사이트를 관리합니다. 플러그인의 톤과 함께.

우리는 어느 시점에서 모든 것을 분열시켜야했습니다. 20-30k 줄의 코드를 가진 함수 파일은 전혀 재미 있지 않습니다.

우리는 코드베이스를 더 잘 관리하기 위해 모든 코드를 리팩터링하기로 결정했습니다. 기본 wordpress 테마 구조는 작은 사이트에는 좋지만 큰 사이트에는 적합하지 않습니다.

새로운 functions.php에는 사이트를 시작하는 데 필요한 내용 만 포함되어 있지만 특정 페이지에 속한 내용은 없습니다.

우리가 지금 사용하는 테마 레이아웃은 MCV 디자인 패턴과 비슷하지만 절차 적 코딩 스타일과 비슷합니다.

예를 들어 우리 회원 페이지 :

page-member.php . 페이지를 초기화하는 작업을 담당합니다. 올바른 Ajax 함수 또는 유사한 호출. MCV 스타일의 컨트롤러 파트와 동일 할 수 있습니다.

functions-member.php . 이 페이지와 관련된 모든 기능을 포함합니다. 이것은 회원들을위한 기능을 필요로하는 다른 페이지들에도 포함되어 있습니다.

content-member.php . HTML 용 데이터 준비 MCV에서 모델과 동일 할 수 있습니다.

layout-member.php . HTML 부분.

Efter가 이러한 변경 작업을 수행 한 결과 개발 시간이 50 % 나 떨어졌으며 제품 소유자는 새로운 작업을 제공하는 데 어려움을 겪고 있습니다. :)

4
Patrik Grinsvall

하위 테마에서 functions.php 파일 :

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

Functions.php에서 필요한 파일을 호출하는 좀 더 우아한 방법은 다음과 같습니다.

require_once locate_template ( '/ inc/functions/shortcodes.php');

0
Imperative Ideas

@ 카이저@mikeschinkel 의 답변을 결합했습니다.

/includes 폴더에 내 테마에 대한 모든 사용자 정의가 있으며 해당 폴더 내에서 모든 항목이 하위 폴더로 구분됩니다.

나는 /includes/admin와 그 서브 컨텐츠가 true === is_admin() 일 때만 포함되기를 원한다.

폴더가 false을 반환하여 iterator_check_traversal_callback에서 제외 된 경우 해당 하위 디렉토리는 반복되거나 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