Code d'organisation dans le fichier functions.php de votre thème WordPress?

85

Plus je personnalise WordPress, plus je commence à réfléchir à la question de savoir si je devrais organiser ce fichier ou le scinder.

Plus précisément, si j’ai un ensemble de fonctions personnalisées qui ne s’appliquent qu’à la zone administrative et à d’autres qui s’appliquent uniquement à mon site Web public, y at-il lieu d’inclure éventuellement toutes les fonctions administratives dans leur propre fichier ou de les regrouper? / p>

Le fait de les séparer en fichiers séparés ou de les regrouper pourrait-il accélérer un site Web WordPress ou WordPress / PHP ignore-t-il automatiquement les fonctions comportant un préfixe is_admin?

Quel est le meilleur moyen de traiter un fichier de fonctions volumineuses (le mien a une longueur de 1370 lignes).

    
posée NetConstructor.com 06.09.2010 - 10:38
la source

8 réponses

113

Si vous arrivez au point où le code dans votre functions.php de votre thème commence à vous submerger, je dirais certainement que vous êtes prêt à envisager de le scinder en plusieurs fichiers. J'ai tendance à le faire presque par seconde nature à ce stade.

Utilisez les fichiers d'inclusion dans le fichier functions.php de votre thème

Je crée un sous-répertoire nommé "includes" dans mon répertoire de thèmes et segmente mon code en fichiers include organisés en fonction de ce qui a du sens pour moi à ce moment-là (ce qui signifie que je refonte et déplace constamment le code autour d'un site évoluant). J'ai aussi rarement mis un code réel dans functions.php ; tout se passe dans les fichiers inclus; juste ma préférence.

Juste pour vous donner un exemple, voici mon installation de test que j’utilise pour tester mes réponses aux questions ici sur WordPress Answers. Chaque fois que je réponds à une question, je garde le code au cas où j'en aurais besoin à nouveau. Ce n’est pas exactement ce que vous ferez pour un site actif, mais cela montre la mécanique de la division du code:

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

Ou créer des plugins

Une autre option est de commencer à grouper votre code par fonction et de créer vos propres plugins. Pour moi, je commence à coder dans le fichier functions.php du thème et au moment où le code est étoffé, j'ai transféré la plupart de mon code dans des plugins.

Cependant, AUCUN gain de performance significatif avec l'organisation du code PHP

D'autre part, structurer vos fichiers PHP concerne 99% de la création d'ordre et de maintenabilité et 1% de performance, si cela (organiser .js et .css des fichiers appelés par le navigateur via HTTP est un cas complètement différent et a conséquences énormes sur les performances.) Mais la manière dont vous organisez votre code PHP sur le serveur n’importe pas du point de vue des performances.

Et l'organisation du code est la préférence personnelle

Enfin, l’organisation du code est une préférence personnelle. Certaines personnes détesteraient la façon dont j'organise le code, tout comme je le ferais peut-être aussi. Trouvez quelque chose que vous aimez et respectez-le, mais laissez votre stratégie évoluer avec le temps, à mesure que vous en apprendrez plus et en deviendrez plus à l'aise.

    
réponse donnée MikeSchinkel 06.09.2010 - 12:38
la source
47

Réponse tardive

Comment inclure vos fichiers correctement:

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

La même chose fonctionne aussi dans les plugins.

Comment obtenir le bon chemin ou l'URi

Examinez également les fonctions de l'API du système de fichiers, telles que:

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

Comment réduire le nombre de include/require

Si vous devez extraire tous les fichiers d'un répertoire, allez avec

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

N'oubliez pas que cela ignore les échecs (peut-être bons pour une utilisation en production) / les fichiers non chargeables.

Pour modifier ce comportement, vous pouvez utiliser une configuration différente au cours du développement:

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

Éditer: approche POO / SPL

Alors que je revenais juste et que je voyais que cette réponse recevait de plus en plus de votes positifs, j'ai pensé pouvoir montrer comment je le fais aujourd'hui - dans un monde PHP 5.3+. L'exemple suivant charge tous les fichiers d'un sous-dossier de thèmes nommé src/ . C'est là que mes bibliothèques gèrent certaines tâches telles que les menus, les images, etc. Vous n'avez même pas à vous soucier du nom car chaque fichier est chargé. Si vous avez d'autres sous-dossiers dans ce répertoire, ils sont ignorés.

Le \FilesystemIterator correspond au supercedor de PHP 5.3+ par rapport au \DirectoryIterator . Les deux font partie du PHP SPL. Bien que PHP 5.2 ait permis de désactiver l'extension SPL intégrée (moins de 1% de toutes les installations l'ont fait), le SPL fait maintenant partie du noyau PHP.

<?php

namespace Theme;

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

Auparavant, alors que je soutenais encore PHP 5.2.x, j’utilisais la solution suivante: Un \FilterIterator dans le répertoire src/Filters pour extraire uniquement les fichiers (et non les pointeurs de dossiers) et un \DirectoryIterator pour le bouclage. et chargement.     

namespace Theme;

use Theme\Filters\IncludesFilter;

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

Le \FilterIterator était aussi simple que cela:

<?php

namespace Theme\Filters;

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

Hormis le fait que PHP 5.2 soit mort / EOL maintenant (et 5.3 également), il y a plus de code et un fichier de plus dans le jeu, il n'y a donc aucune raison de continuer et de supporter PHP 5.2.x .

Résumé

Vous pouvez trouver un article encore plus détaillé ici sur WPKrauts . .

MODIFIER La bonne méthode consiste évidemment à utiliser le code namespace d, préparé pour PSR-4 à chargement automatique en plaçant tout dans le répertoire approprié déjà défini via l'espace de noms. Ensuite, utilisez simplement Composer et un composer.json pour gérer vos dépendances et laissez-le construire automatiquement votre autochargeur PHP (qui importe automatiquement un fichier en appelant simplement use \<namespace>\ClassName ). C’est le standard de facto dans le monde PHP, le moyen le plus simple et encore plus pré-automatisé et simplifié par WP Starter .

    
réponse donnée kaiser 13.10.2012 - 15:53
la source
5

Pour ce qui est de le casser, dans ma plaque de chaudière, j’utilise une fonction personnalisée pour rechercher un dossier appelé fonctions dans le répertoire du thème. Si ce n’est pas le cas, il le crée. Ensuite, crée un tableau de tous les fichiers .php trouvés dans ce dossier (le cas échéant) et exécute un include (); sur chacun d’eux.

Ainsi, chaque fois que je dois écrire de nouvelles fonctionnalités, j'ajoute simplement un fichier PHP au dossier des fonctions, sans avoir à vous soucier de le coder dans le site.

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

}
    
réponse donnée Mild Fuzz 06.09.2010 - 15:50
la source
5

J'aime utiliser une fonction pour les fichiers d'un dossier. Cette approche facilite l'ajout de nouvelles fonctionnalités lors de l'ajout de nouveaux fichiers. Mais j'écris toujours en classe ou avec des espaces de noms - donnez-lui plus de contrôle sur l'espace de noms des fonctions, méthodes, etc.

Ci-dessous un petit exemple. ut également utilisation avec l'accord sur la classe * .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;

}

Dans les thèmes, j’utilise souvent un autre scénario. Je définis la fonction du fichier externel dans un ID de support, voir l'exemple. C’est utile si je vais facilement désactiver la fonction du fichier externel. J'utilise la fonction de base WP require_if_theme_supports() et il ne charge que si l'ID de support était actif. Dans l'exemple suivant, j'ai défini cet ID pris en charge dans la ligne avant de charger le fichier.

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

Vous en verrez plus dans le rapport de ce thème .

    
réponse donnée bueltge 04.10.2012 - 11:16
la source
4

Je gère un site avec environ 50 types de page personnalisés uniques dans plusieurs langues sur une installation réseau. Avec une tonne de plugins.

Nous avons été obligés de tout séparer à un moment donné. Un fichier de fonctions avec 20-30k lignes de code n’est pas drôle du tout.

Nous avons décidé de complètement refactoriser tout le code afin de mieux gérer la base de code. La structure de thèmes wordpress par défaut convient aux petits sites, mais pas aux plus grands.

Notre nouveau functions.php ne contient que ce qui est nécessaire pour démarrer le site, mais rien qui appartient à une page spécifique.

La disposition de thème que nous utilisons maintenant est similaire au modèle de conception MCV, mais dans un style de codage procédural.

Par exemple, notre page membre:

.

page-member.php . Responsable de l'initialisation de la page. Appeler les fonctions ajax correctes ou similaires. Pourrait être équivalent à la partie contrôleur dans le style MCV.

functions-member.php . Contient toutes les fonctions liées à cette page. Ceci est également inclus dans plusieurs autres pages qui nécessitent des fonctions pour nos membres.

content-member.php . Prépare les données pour HTML Peut être équivalent au modèle dans MCV.

layout-member.php . La partie HTML.

Après ces modifications, le temps de développement a facilement été réduit de 50% et le responsable du produit a maintenant du mal à nous attribuer de nouvelles tâches. :)

    
réponse donnée Patrik Grinsvall 04.10.2012 - 11:37
la source
3

À partir du fichier functions.php des thèmes enfants:

    require_once( get_stylesheet_directory() . '/inc/custom.php' );
    
réponse donnée Brad Dalton 20.10.2013 - 20:34
la source
0

Dans functions.php, un moyen plus élégant d’appeler un fichier requis serait:

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

    
réponse donnée Imperative Ideas 04.10.2012 - 09:23
la source
0

J'ai combiné les @kaiser et @ mikeschinkel ».

Toutes mes personnalisations sur mon thème se trouvent dans un dossier /includes . Dans ce dossier, tout est divisé en sous-dossiers.

Je veux seulement que /includes/admin et ses sous-contenus soient inclus lorsque true === is_admin()

Si un dossier est exclu dans iterator_check_traversal_callback en renvoyant false , ses sous-répertoires ne seront pas itérés (ni transmis à 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();
}
    
réponse donnée seangwright 19.08.2018 - 21:02
la source

Lire d'autres questions sur les étiquettes