it-swarm-eu.dev

Organizační kód ve WordPress Theme's function.php Soubor?

Čím více přizpůsobím aplikaci WordPress, tím více začnu přemýšlet o tom, zda bych měl tento soubor organizovat nebo rozdělit.

Přesněji řečeno, pokud mám spoustu vlastních funkcí, které se vztahují pouze na oblast admin a další, které se vztahují pouze na mé veřejné webové stránky, existuje nějaký důvod, proč je možné zahrnout všechny funkce správce do vlastního souboru nebo je seskupit dohromady?

Rozdělit je do samostatných souborů nebo seskupit je dohromady může urychlit webové stránky WordPress nebo WordPress/PHP automaticky přeskočí funkce, které mají předponu is_admin kódu?

Jaký je nejlepší způsob, jak se vypořádat s velkým souborem funkcí (moje je dlouhá 1370 řádků).

91

Pokud se dostáváte do bodu, kdy kód ve vašem functions.php tématu začíná přemoci vás, určitě bych řekl, že jste připraveni zvážit rozdělení do několika souborů. V tomto bodě mám sklon dělat to téměř druhou povahou.

Použít Zahrnout soubory do souboru functions.php Soubor

Vytvořím podadresář nazvaný "zahrnuje" pod mým adresářem motivů a segmentuji můj kód do souborů organizovaných podle toho, co mi v té době dává smysl (což znamená, že jsem neustále refactoring a pohybující se kód kolem webu se vyvíjí. ) Také zřídka v reálném kódu v functions.php; vše jde v souborech zahrnujících; jen moje preference.

Jen abych vám dal příklad zde je moje zkušební instalace, kterou používám k testování svých odpovědí na otázky zde na WordPress Odpovědi. Pokaždé, když odpovím na otázku, mám kód v případě, že ji potřebuji znovu. To není přesně to, co budete dělat pro živé stránky, ale ukazuje mechaniku rozdělení kódu:

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

Nebo Vytvořit moduly

Další možností je začít seskupovat kód podle funkce a vytvořit si vlastní pluginy. Pro mě začnu kódování v souboru functions.php a v době, kdy dostanu kód, jsem přesunul většinu kódu do pluginů.

Nicméně žádná významná výkonnost pochází z PHP Kódové organizace

Na druhou stranu strukturování souborů PHP je 99% o vytvoření objednávky a udržovatelnosti a 1% o výkonu, pokud (organizování souborů .js a .css, které prohlížeč přes HTTP volá, je zcela odlišný případ a má obrovský rozsah Ale jak si organizujete svůj PHP kód na serveru do značné míry z hlediska výkonu nezáleží.

Organizace Code je osobní preferencí

A v neposlední řadě organizace kódu je osobní preference. Někteří lidé by nenáviděli, jak organizuji kód, stejně jako bych mohl nenávidět, jak to taky dělají. Najděte si něco, co se vám líbí a držte se ho, ale dovolte, aby se vaše strategie v průběhu času vyvíjela, abyste se s ní dozvěděli více a lépe se s ní spokojili.

117
MikeSchinkel

Pozdní odpověď

Jak zahrnout vaše soubory správným způsobem:

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

Totéž platí i pro pluginy.

Jak získat správnou cestu nebo URi

Podívejte se také na funkce API systému souborů jako:

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

Jak snížit počet include/require

Pokud potřebujete zkopírovat všechny soubory z adresáře, přejděte na

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

Mějte na paměti, že to ignoruje selhání (možná dobré pro výrobní použití)/ne načtitelné soubory.

Chcete-li toto chování změnit, můžete během vývoje použít jinou konfiguraci:

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

Edit: OOP/SPL přístup

Jak jsem se právě vrátil a viděl, že tato odpověď je stále více a více upvotes, myslel jsem, že bych mohl ukázat, jak to dělám dnes - ve světě PHP 5.3+. Následující příklad načte všechny soubory z podsložky s názvem src/. To je místo, kde mám své knihovny, které pracují s určitými úkoly, jako jsou menu, obrázky, atd. Nemusíte se ani starat o jméno, protože každý soubor se načte. Pokud máte v tomto adresáři jiné podsložky, budou ignorovány.

\FilesystemIterator je PHP 5.3+ supercedor nad \DirectoryIterator. Oba jsou součástí PHP SPL. Zatímco PHP 5.2 umožnilo vypnout vestavěnou příponu SPL (méně než 1% všech instalací), SPL je nyní součástí jádra PHP.

<?php

namespace Theme;

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

Dříve, když jsem ještě podporoval PHP 5.2.x, použil jsem následující řešení: A \FilterIterator v adresáři src/Filters k načtení pouze souborů (a nikoliv bodových ukazatelů složek) a \DirectoryIterator k provedení smyčky a načítání.

namespace Theme;

use Theme\Filters\IncludesFilter;

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

\FilterIterator bylo stejně snadné jako:

<?php

namespace Theme\Filters;

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

Kromě toho, že PHP 5.2 je nyní mrtvé/EOL (a také 5.3), je zde fakt, že je to více kódu a jeden další soubor ve hře, takže není důvod jít s novější a podporou _.PHP 5.2.x.

Shrnul

Ještě podrobnější článek lze nalézt zde na WPKrauts .

EDITSamozřejmě správným způsobem je použít namespaced kód, připravený pro PSR-4 autoloading tím, že vložíte vše do příslušného adresáře, který je již definován přes jmenný prostor. Pak stačí použít Composer a composer.json ke správě vašich závislostí a nechat auto-sestavit vaše PHP autoloader (který automaticky importuje soubor pouhým voláním use \<namespace>\ClassName). To je de-facto standard ve světě PHP, nejjednodušší způsob, jak jít a ještě více před-automatizovaný a zjednodušený WP Starter .

50
kaiser

Líbí se mi použít funkci pro soubory uvnitř složky. Tento přístup usnadňuje přidávání nových funkcí při přidávání nových souborů. Ale píšu vždy ve třídě nebo jmenných prostorech - dávám jí větší kontrolu nad jmenným prostorem funkcí, metodou atd.

Pod malým příkladem; ut také s dohodou o třídě * .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;

}

V tématech používám často jiný scénář. Definuji funkci souboru externel v ID podpory, viz příklad. To je užitečné, pokud mohu snadno deaktivovat fetest externel souboru. Používám hlavní funkci WP require_if_theme_supports() a načte pouze, pokud bylo aktivní ID podpory. V následujícím příkladu jsem tuto podporu podporoval v řádku před načtením souboru.

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

Více se o tom můžete dozvědět v repo tématu .

5
bueltge

pokud jde o rozbití, v mé kotlové desce používám vlastní funkci k vyhledání složky nazvané funkce v adresáři motivů, pokud ji tam nevytvoří. Pak se vytvoří pole všech souborů .php, které nalezne v dané složce (pokud existuje) a spustí příkaz include (); na každém z nich.

Tímto způsobem, pokaždé, když potřebuji napsat nějaké nové funkce, přidám soubor PHP do složky funkcí a nemusím se starat o jeho kódování do webu.

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

Spravuji web s asi 50 jedinečnými vlastními typy stránek v serverových různých jazycích přes síťovou instalaci. Spolu s TON pluginy.

Tam, kde jsme byli nuceni to všechno rozdělit. Soubor funkcí s 20-30k řádky kódu není vůbec vtipný.

Rozhodli jsme se doplnit refactor all code, abychom mohli lépe spravovat codebase. Výchozí struktura wordpress téma je dobrá pro malé stránky, ale ne pro větší weby.

Naše nové funkce.php obsahuje pouze to, co je nezbytné pro spuštění webu, ale nic, co patří ke konkrétní stránce.

Rozvržení motivu, které nyní používáme, je podobné vzorovému vzoru MCV, ale ve stylu procedurálního kódování.

Například naše členská stránka:

page-member.php . Zodpovídá za inicializaci stránky. Volání správných funkcí ajax nebo podobných funkcí. Mohl by být rovnocenný s částí Controller ve stylu MCV.

functions-member.php . Obsahuje všechny funkce související s touto stránkou. To je také zahrnuto v serveral dalších stránkách, které potřebují funkce pro naše členy.

content-member.php . Připravuje data pro HTML Mohl by být rovnocenný s modelem v MCV.

layout-member.php . Část HTML.

Poté, co jsme provedli tyto změny, vývojový čas snadno klesl o 50% a nyní má vlastník produktu problémy s novými úkoly. :)

4
Patrik Grinsvall

Soubor child.php:

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

V function.php by bylo elegantnějším způsobem volání požadovaného souboru:

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

0
Imperative Ideas

Já jsem kombinoval @kaiser 's a @ mikeschinkel ' s odpovědí.

Mám všechny své úpravy na mé téma ve složce /includes a v této složce mám všechno rozdělené do podsložek.

Chci, aby /includes/admin a jeho dílčí obsah byly zahrnuty při true === is_admin()

Pokud je složka vyloučena v iterator_check_traversal_callback vrácením false, pak její podadresáře nebudou iterovány (nebo předány 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