it-swarm.com.de

Code in der Datei functions.php Ihres WordPress-Themes organisieren?

Je mehr Anpassungen ich an WordPress vornehme, desto mehr überlege ich, ob ich diese Datei organisieren oder aufteilen soll.

Genauer gesagt, wenn ich eine Reihe von benutzerdefinierten Funktionen habe, die nur für den Admin-Bereich gelten, und andere, die nur für meine öffentliche Website gelten, gibt es einen Grund, alle Admin-Funktionen möglicherweise in ihre eigene Datei aufzunehmen oder zu einer Gruppe zusammenzufassen?

Würde das Aufteilen in separate Dateien oder Gruppieren diese möglicherweise eine WordPress-Website beschleunigen oder überspringt WordPress/PHP automatisch Funktionen, die ein is_admin-Code-Präfix haben?

Was ist der beste Weg, um mit einer großen Funktionsdatei umzugehen (meine ist 1370 Zeilen lang)?.

91

Wenn Sie an einem Punkt angelangt sind, an dem Sie der Code in functions.php Ihres Themas langsam überfordert, würde ich definitiv sagen, dass Sie bereit sind, eine Aufteilung in mehrere Dateien in Betracht zu ziehen. Ich neige dazu, das an diesem Punkt fast von Natur aus zu tun.

Verwenden Sie Include-Dateien in der functions.php-Datei Ihres Themas

Ich erstelle ein Unterverzeichnis mit dem Namen "includes" unter meinem Themenverzeichnis und segmentiere meinen Code in Include-Dateien, die nach dem für mich zum jeweiligen Zeitpunkt Sinnvollen geordnet sind (dh, ich überarbeite ständig den Code und verschiebe ihn, während sich die Site weiterentwickelt. ) Ich habe auch selten einen echten Code in functions.php eingefügt; Alles geht in die Include-Dateien; Nur meine Präferenz.

Um Ihnen ein Beispiel zu geben, hier ist meine Testinstallation, mit der ich meine Antworten auf Fragen hier auf WordPress Answers teste. Jedes Mal, wenn ich eine Frage beantworte, behalte ich den Code für den Fall, dass ich ihn erneut benötige. Dies ist nicht genau das, was Sie für eine Live-Site tun, aber es zeigt die Mechanismen der Aufteilung des Codes:

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

Oder Plugins erstellen

Eine weitere Möglichkeit ist es, den Code nach Funktionen zu gruppieren und eigene Plugins zu erstellen. Für mich fange ich an, in der functions.php-Datei des Themas zu codieren, und als der Code fertig ist, habe ich den größten Teil meines Codes in Plugins verschoben.

KEINE signifikante Leistungssteigerung durch die PHP Code-Organisation

Zum anderen geht es bei der Strukturierung Ihrer PHP -Dateien zu 99% darum, Ordnung und Wartbarkeit zu schaffen, und zu 1% um Leistung, wenn diese (das Organisieren von .js- und .css -Dateien, die vom Browser über HTTP aufgerufen werden, ist ein völlig anderer Fall und hat große Auswirkungen Auswirkungen auf die Leistung.) Wie Sie jedoch Ihren PHP Code auf dem Server organisieren, spielt aus Sicht der Leistung keine Rolle.

Und Code-Organisation ist persönliche Präferenz

Und nicht zuletzt ist die Code-Organisation eine persönliche Präferenz. Einige Leute hassen es, wie ich Code organisiere, genauso wie ich es hasse, wie sie es auch tun. Finden Sie etwas, das Ihnen gefällt, und bleiben Sie dabei. Lassen Sie jedoch zu, dass sich Ihre Strategie im Laufe der Zeit weiterentwickelt, wenn Sie mehr lernen und sich damit vertraut machen.

117
MikeSchinkel

Späte Antwort

So fügen Sie Ihre Dateien richtig ein:

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

Das gleiche funktioniert auch in Plugins.

Wie man den richtigen Weg oder URi findet

Schauen Sie sich auch die Funktionen der Dateisystem-API an:

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

Wie reduziert man die Anzahl der include/require

Wenn Sie all Dateien aus einem Verzeichnis abrufen müssen, verwenden Sie

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

Denken Sie daran, dass dies Fehler ignoriert (möglicherweise gut für die Produktion)/nicht ladbare Dateien.

Um dieses Verhalten zu ändern, möchten Sie möglicherweise während der Entwicklung eine andere Konfiguration verwenden:

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

Als ich gerade zurückkam und sah, dass diese Antwort immer mehr positive Stimmen erhielt, dachte ich, ich könnte zeigen, wie ich es heutzutage mache - in einer PHP 5.3+ Welt. Im folgenden Beispiel werden alle Dateien aus einem Themenunterordner mit dem Namen src/ geladen. Hier habe ich meine Bibliotheken, die bestimmte Aufgaben wie Menüs, Bilder usw. erledigen. Sie müssen sich nicht einmal um den Namen kümmern, wenn jede einzelne Datei geladen wird. Wenn Sie andere Unterordner in diesem Verzeichnis haben, werden diese ignoriert.

Der \FilesystemIterator ist der PHP 5.3+ supercedor über dem \DirectoryIterator. Beide sind Teil der PHP SPL. Während es mit PHP 5.2 möglich war, die eingebaute SPL-Erweiterung zu deaktivieren (weniger als 1% aller Installationen haben dies getan), ist die SPL jetzt Teil des PHP Kerns.

<?php

namespace Theme;

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

Während ich PHP 5.2.x noch unterstützte, verwendete ich die folgende Lösung: Einen \FilterIterator im src/Filters-Verzeichnis, um nur Dateien abzurufen (und keine Punktzeiger von Ordnern), und einen \DirectoryIterator, um die Schleife zu erstellen und zu laden.

namespace Theme;

use Theme\Filters\IncludesFilter;

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

Der \FilterIterator war so einfach:

<?php

namespace Theme\Filters;

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

Abgesehen davon, dass PHP 5.2 bereits tot/EOL ist (und auch 5.3), gibt es die Tatsache, dass es mehr Code und eine weitere Datei im Spiel gibt, so dass es keinen Grund gibt, sich für die spätere Version zu entscheiden und _ zu unterstützen.PHP 5.2.x.

Zusammengefasst

Ein noch ausführlicherer Artikel ist zu finden hier auf WPKrauts .

EDITDer offensichtlich richtige Weg ist die Verwendung von namespaced Code, der für das PSR-4 Autoloading vorbereitet ist, indem alles in das entsprechende Verzeichnis gestellt wird, das bereits über den Namespace definiert ist. Verwenden Sie dann einfach Composer und einen composer.json, um Ihre Abhängigkeiten zu verwalten, und lassen Sie den PHP - Autoloader automatisch erstellen (der automatisch eine Datei importiert, indem Sie einfach use \<namespace>\ClassName aufrufen). Das ist der De-facto-Standard in der PHP Welt, der einfachste Weg und noch vorautomatisierter und einfacher durch WP Starter .

50
kaiser

Ich verwende gerne eine Funktion für die Dateien in einem Ordner. Dieser Ansatz erleichtert das Hinzufügen neuer Funktionen, wenn neue Dateien hinzugefügt werden. Aber ich schreibe immer in der Klasse oder mit Namespaces - geben Sie ihm mehr Kontrolle über den Namespace von Funktionen, Methoden usw.

Unten ein kleines Beispiel; Nutze aber auch die Vereinbarung über die Klasse * .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;

}

In Themes verwende ich oft ein anderes Szenario. Ich definiere die Funktion der externen Datei in einer Support-ID, siehe Beispiel. Das ist nützlich, wenn ich die Funktion der externen Datei einfach deaktivieren möchte. Ich benutze die WP Kernfunktion require_if_theme_supports() und er lädt nur, wenn die Support-ID aktiv war. Im folgenden Beispiel habe ich diese unterstützte ID in der Zeile definiert, bevor ich die Datei geladen habe.

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

Sie können mehr davon im Repo dieses Themas sehen.

5
bueltge

in Bezug auf die Aufteilung verwende ich in meinem Kessel eine benutzerdefinierte Funktion, um nach einem Ordner mit dem Namen "functions" im Themenverzeichnis zu suchen. Wenn er nicht vorhanden ist, wird er erstellt. Anschließend wird ein Array aller gefundenen .php-Dateien in diesem Ordner erstellt (falls vorhanden) und ein include () ausgeführt. auf jedem von ihnen.

Auf diese Weise füge ich jedes Mal, wenn ich neue Funktionen schreiben muss, dem Funktionsordner eine PHP -Datei hinzu und muss mich nicht darum kümmern, diese in die Site zu codieren.

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

Ich verwalte eine Site mit ungefähr 50 benutzerdefinierten Seitentypen in mehreren verschiedenen Sprachen über eine Netzwerkinstallation. Zusammen mit einer Menge Plugins.

Wir waren gezwungen, alles irgendwann aufzuteilen. Eine Funktionsdatei mit 20 bis 30.000 Codezeilen ist überhaupt nicht lustig.

Wir haben beschlossen, den gesamten Code komplett umzugestalten, um die Codebasis besser verwalten zu können. Die standardmäßige WordPress-Designstruktur eignet sich für kleine Websites, nicht jedoch für größere Websites.

Unsere neue functions.php enthält nur das, was zum Starten der Site notwendig ist, aber nichts, was zu einer bestimmten Seite gehört.

Das jetzt verwendete Themenlayout ähnelt dem MCV-Entwurfsmuster, weist jedoch einen prozeduralen Codierungsstil auf.

Zum Beispiel unsere Mitgliederseite:

page-member.php . Verantwortlich für die Initialisierung der Seite. Aufrufen der richtigen Ajax-Funktionen oder ähnliches. Entspricht möglicherweise dem Controller-Teil im MCV-Stil.

functions-member.php . Enthält alle Funktionen zu dieser Seite. Dies ist auch in mehreren anderen Seiten enthalten, die Funktionen für unsere Mitglieder benötigen.

content-member.php . Vorbereiten der Daten für HTML Entspricht möglicherweise dem Modell in MCV.

layout-member.php . Der HTML-Teil.

Nachdem wir diese Änderungen vorgenommen haben, hat sich die Entwicklungszeit leicht um 50% verringert, und jetzt hat der Produktbesitzer Probleme, uns neue Aufgaben zu geben. :)

4

Aus der Datei functions.php für untergeordnete Themen:

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

In functions.php wäre eine elegantere Art, eine erforderliche Datei aufzurufen:

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

0

Ich habe die Antworten von @kaiser und @mikeschinkel kombiniert.

Ich habe alle meine Anpassungen an meinem Thema in einem /includes Ordner und in diesem Ordner habe ich alles in Unterordner aufgeteilt.

Ich möchte nur, dass /includes/admin und seine Unterinhalte einbezogen werden, wenn true === is_admin()

Wenn ein Ordner in iterator_check_traversal_callback ausgeschlossen wird, indem false zurückgegeben wird, werden seine Unterverzeichnisse nicht iteriert (oder an iterator_check_traversal_callback übergeben).

/**
 *  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