it-swarm-es.com

Organizar el código en el archivo de funciones de WordPress Theme.php?

Cuanto más personalización hago a WordPress, más empiezo a pensar si debo organizar este archivo o dividirlo.

Más específicamente, si tengo un montón de funciones personalizadas que solo se aplican al área de administración y otras que solo se aplican a mi sitio web público, ¿hay alguna razón para incluir todas las funciones de administración en su propio archivo o agruparlas?

¿Dividirlos en archivos separados o agruparlos podría acelerar un sitio web de WordPress o WordPress/PHP omite automáticamente las funciones que tienen un prefijo de código is_admin?

¿Cuál es la mejor manera de tratar con un archivo de funciones grande (el mío es 1370 líneas de largo).

91
NetConstructor.com

Si llega al punto en que el código en el functions.php de su tema está empezando a abrumarlo, definitivamente diría que está listo para considerar dividirlo en varios archivos. Tiendo a hacer eso casi por segunda naturaleza en este punto.

Utilice Incluir archivos en el archivo functions.php de su tema

Creo un subdirectorio llamado "incluye" debajo de mi directorio de temas y segmento mi código para incluir archivos organizados por lo que tiene sentido para mí en ese momento (lo que significa que estoy refactorizando y moviendo el código constantemente a medida que el sitio evoluciona. ) También rara vez puse un código real en functions.php; Todo va en los archivos de inclusión; solo mi preferencia.

Solo para darle un ejemplo, aquí está mi instalación de prueba que utilizo para probar mis respuestas a las preguntas aquí en WordPress Answers. Cada vez que respondo una pregunta guardo el código en caso de que lo necesite de nuevo. Esto no es exactamente lo que harás para un sitio en vivo, pero muestra la mecánica de dividir el código:

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

O crear complementos

Otra opción es comenzar a agrupar su código por función y crear sus propios complementos. Para mí, comienzo a codificar en el archivo functions.php del tema y, en el momento en que hago el código, he movido la mayor parte de mi código a los complementos.

Sin embargo, NO hay una ganancia de rendimiento significativa de PHP Organización del código

Por otra parte, estructurar sus PHP archivos es 99% sobre la creación de orden y mantenimiento y 1% sobre el rendimiento, si eso (organizar los archivos .js y .css llamados por el navegador a través de HTTP es un caso completamente diferente y tiene un enorme implicaciones de rendimiento.) Pero la forma en que organiza su PHP código en el servidor no importa mucho desde una perspectiva de rendimiento.

Y la organización del código es una preferencia personal

Y por último, pero no menos importante, la organización del código es la preferencia personal. Algunas personas odiarían la forma en que organizo el código, así como yo también odiaría la forma en que lo hacen. Encuentre algo que le guste y apéguese a él, pero permita que su estrategia evolucione con el tiempo a medida que aprende más y se sienta más cómodo con él.

117
MikeSchinkel

Respuesta tardía

Cómo incluir tus archivos de la manera correcta:

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

Lo mismo funciona en los complementos también.

Cómo conseguir el camino correcto o URi

También eche un vistazo a las funciones de la API del sistema de archivos como:

  • 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.

Cómo reducir el número de include/require

Si necesita recuperar todos archivos de un directorio, vaya con

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

Tenga en cuenta que esto ignora las fallas (quizás buenas para uso de producción)/los archivos no cargables.

Para modificar este comportamiento, es posible que desee utilizar una configuración diferente durante el desarrollo:

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

Edición: enfoque OOP/SPL

Cuando acabo de regresar y vi que esta respuesta es cada vez más upvotes, pensé que podría mostrar cómo lo estoy haciendo hoy en día, en un PHP 5.3+ mundo. El siguiente ejemplo carga todos los archivos de una subcarpeta de temas llamada src/. Aquí es donde tengo mis bibliotecas que manejan ciertas tareas como menús, imágenes, etc. Ni siquiera tiene que preocuparse por el nombre al cargar cada archivo. Si tiene otras subcarpetas en este directorio, se ignorarán.

El \FilesystemIterator es el PHP 5.3+ supercedor sobre el \DirectoryIterator. Ambos son parte del PHP SPL. Mientras que PHP 5.2 hizo posible desactivar la extensión SPL incorporada (menos del 1% de todas las instalaciones lo hicieron), la SPL ahora es parte de PHP core.

<?php

namespace Theme;

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

Anteriormente, mientras todavía era compatible con PHP 5.2.x, usé la siguiente solución: un \FilterIterator en el directorio src/Filters para recuperar solo archivos (y no punteros de puntos) de las carpetas y un \DirectoryIterator para hacer el bucle y la carga.

namespace Theme;

use Theme\Filters\IncludesFilter;

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

El \FilterIterator fue tan fácil como eso:

<?php

namespace Theme\Filters;

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

Aparte de que PHP 5.2 ya está muerto/EOL (y 5.3 también), existe el hecho de que hay más código y un archivo más en el juego, por lo que no hay razón para ir más tarde y soporte PHP 5.2.x.

Resumió

Se puede encontrar un artículo aún más en profundidad aquí en WPKrauts .

EDITARLa forma obviamente correcta es usar el código namespaced, preparado para PSR-4 carga automática colocando todo en el directorio apropiado que ya está definido a través del espacio de nombres. Luego solo use Composer y un composer.json para administrar sus dependencias y deje que genere automáticamente su PHP autoloader (que importa automáticamente un archivo simplemente llamando a use \<namespace>\ClassName). Ese es el estándar de facto en el mundo PHP, la forma más fácil de hacerlo y aún más pre-automatizado y simplificado por WP Starter .

50
kaiser

Me gusta usar una función para los archivos dentro de una carpeta. Este enfoque facilita la adición de nuevas funciones al agregar nuevos archivos. Pero escribo siempre en clase o con espacios de nombres: le doy más control sobre el espacio de nombres de funciones, método, etc.

Abajo un pequeño ejemplo; Pero también uso con el acuerdo sobre la clase * .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;

}

En Temas utilizo a menudo otro escenario. Defino la función del archivo externo en un ID de soporte, vea el ejemplo. Eso es útil si fácilmente desactivaré la recuperación del archivo externo. Uso la WP función de núcleo require_if_theme_supports() y se carga solo, si el ID de soporte estaba activo. En el siguiente ejemplo, especifiqué este ID admitido en la línea antes de cargar el archivo.

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

Puedes ver más de esto en el repo de este tema .

5
bueltge

en cuanto a su separación, en mi placa de calderas utilizo una función personalizada para buscar una carpeta llamada funciones en el directorio de temas, si no está allí, la crea. Luego, crea una matriz de todos los archivos .php que encuentra en esa carpeta (si existe) y ejecuta un include (); en cada uno de ellos.

De esa manera, cada vez que necesito escribir alguna nueva funcionalidad, solo agrego un archivo PHP a la carpeta de funciones, y no tengo que preocuparme por codificarlo en el sitio.

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

Administro un sitio con aproximadamente 50 tipos de páginas personalizadas únicas en diferentes idiomas en una instalación de red. Junto con una tonelada de plugins.

Nos obligaron a dividirlo todo en algún momento. Un archivo de funciones con 20-30k líneas de código no es divertido en absoluto.

Decidimos completar todo el código para poder administrar mejor el código base. La estructura predeterminada del tema de wordpress es buena para sitios pequeños, pero no para sitios más grandes.

Nuestro nuevo functions.php solo contiene lo que es necesario para iniciar el sitio, pero nada que pertenezca a una página específica.

El diseño del tema que utilizamos ahora es similar al patrón de diseño de MCV, pero en un estilo de codificación de procedimiento.

Por ejemplo nuestra página de miembros:

page-member.php . Responsable de inicializar la página. Llamando a las funciones correctas de ajax o similares. Podría ser equivalente a la parte del controlador en el estilo MCV.

funciones-miembro.php . Contiene todas las funciones relacionadas con esta página. Esto también se incluye en otras páginas que necesitan funciones para nuestros miembros.

content-member.php . Prepara los datos para HTML. Podría ser equivalente al modelo en MCV.

layout-member.php . La parte HTML.

Una vez que hicimos estos cambios, el tiempo de desarrollo se redujo fácilmente en un 50% y ahora el propietario del producto tiene problemas para darnos nuevas tareas. :)

4
Patrik Grinsvall

De archivo de funciones de temas infantiles: php:

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

En functions.php, una forma más elegante de llamar a un archivo requerido sería:

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

0
Imperative Ideas

Combiné las respuestas de @kaiser 's y @mikeschinkel .

Tengo todas mis personalizaciones para mi tema en una carpeta /includes y dentro de esa carpeta tengo todo dividido en subcarpetas.

Solo quiero que /includes/admin y sus sub-contenidos sean incluidos cuando true === is_admin()

Si una carpeta se excluye en iterator_check_traversal_callback devolviendo false, sus subdirectorios no se repetirán (ni se pasarán a 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