Carga automática y espacios de nombres en plugins y temas de WordPress: ¿puede funcionar?

70

¿Alguien ha usado espacios de nombres de carga automática y / o PHP dentro de un complemento o tema?

¿Pensamientos para usarlos? ¿Cualquier daño? Trampas?

Nota: los espacios de nombres son solo PHP 5.3+. Suponga, para esta pregunta, que sabe que estará tratando con servidores que sabe que tienen PHP 5.3 o superior.

chrisguitarguy
fuente

Respuestas:

88

De acuerdo, he tenido dos grandes proyectos en los que he tenido el control del servidor lo suficiente como para usar el espacio de nombres y confiar en la carga automática.

Por primera vez. La carga automática es increíble. No preocuparse por requiere es algo relativamente bueno.

Aquí hay un cargador que he estado usando en algunos proyectos. Verifica para asegurarse de que la clase esté primero en el espacio de nombres actual, luego se retira si no. A partir de ahí, es solo una manipulación de cadenas para encontrar la clase.

<?php
spl_autoload_register(__NAMESPACE__ . '\\autoload');
function autoload($cls)
{
    $cls = ltrim($cls, '\\');
    if(strpos($cls, __NAMESPACE__) !== 0)
        return;

    $cls = str_replace(__NAMESPACE__, '', $cls);

    $path = PLUGIN_PATH_PATH . 'inc' . 
        str_replace('\\', DIRECTORY_SEPARATOR, $cls) . '.php';

    require_once($path);
}

Uno podría adaptar esto fácilmente para usarlo sin espacios de nombres. Suponiendo que prefija las clases de su plugin / tema de manera uniforme, puede probar ese prefijo. Luego use guiones bajos en el nombre de la clase como marcadores de posición para los separadores de directorio. Si está utilizando muchas clases, es probable que desee utilizar algún tipo de cargador automático de mapas de clase.

Espacios de nombres y ganchos

El sistema de ganchos de WordPress funciona mediante el uso de call_user_func(y call_user_func_array), que toma los nombres de las funciones como cadenas y las llama cuando se realiza la llamada a la función do_action(y, posteriormente, call_user_func).

Con espacios de nombres, eso significa que deberá pasar nombres de funciones completamente calificados que incluyan el espacio de nombres en ganchos.

<?php
namespace WPSE\SomeNameSpace;

add_filter('some_filter', 'WPSE\\SomeNameSpace\\the_function');
function the_function()
{
   return 'did stuff';
}

Probablemente sería mejor hacer un uso liberal de la __NAMESPACE__constante mágica si quieres hacer esto.

<?php
namespace WPSE\SomeNameSpace;

add_filter('some_filter', __NAMESPACE__ . '\\the_function');
function the_function()
{
   return 'did stuff';
}

Si siempre pones tus ganchos en las clases, es más fácil. La instancia de creación estándar de una clase y todos los ganchos en el constructor $thisfuncionan bien.

<?php
namespace WPSE\SomeNameSpace;

new Plugin;

class Plugin
{
    function __construct()
    {
        add_action('plugins_loaded', array($this, 'loaded'));
    }

    function loaded()
    {
        // this works!
    }
}

Si usa métodos estáticos como quiero hacer, deberá pasar el nombre de clase completo como primer argumento de la matriz. Eso es mucho trabajo, así que puedes usar la __CLASS__constante mágica o get_class.

<?php
namespace WPSE\SomeNameSpace;

Plugin::init();

class Plugin
{
    public static function init()
    {
        add_action('plugins_loaded', array(__CLASS__, 'loaded'));
        // OR: add_action('plugins_loaded', array(get_class(), 'loaded'));
    }

    public static function loaded()
    {
        // this works!
    }
}

Usar clases principales

La resolución del nombre de clase de PHP es un poco inestable. Si va a utilizar las clases principales de WP ( WP_Widgeten el ejemplo a continuación) debe proporcionar usedeclaraciones.

use \WP_Widget;

class MyWidget extends WP_Widget
{
   // ...
}

O bien, puede usar el nombre de clase completo, básicamente con el prefijo de una barra diagonal inversa.

<?php
namespace WPSE\SomeNameSpace;

class MyWidget extends \WP_Widget
{
   // ...
}

Define

Este es un PHP más general, pero me mordió, así que aquí está.

Es posible que desee definir cosas que usará con frecuencia, como la ruta a su complemento. El uso de la instrucción define coloca las cosas en el espacio de nombres raíz a menos que pases explícitamente el espacio de nombres en el primer argumento de define.

<?php
namespace WPSE\SomeNameSpace;

// root namespace
define('WPSE_63668_PATH', plugin_dir_path(__FILE__));

// in the current namespace
define(__NAMESPACE__ . '\\PATH', plugin_dir_path(__FILE__));

También puede usar la constpalabra clave en el nivel raíz de un archivo con PHP 5.3 plus. constss siempre están en el espacio de nombres actual, pero son menos flexibles que una definellamada.

<?php
namespace WPSE\SomeNameSpace;

// in the current namespace
const MY_CONST = 1;

// this won't work!
const MY_PATH = plugin_dir_path(__FILE__);

¡No dude en agregar cualquier otro consejo que pueda tener!

chrisguitarguy
fuente
16

Aquí hay una respuesta de 2017.

La carga automática es increíble. El espacio de nombres es asombroso.

Aunque puede hacerlo usted mismo, en 2017 tiene más sentido usar el magnífico y ubicuo Composer para manejar sus requisitos de PHP. Composer admite la carga automática de PSR-0 y PSR-4 , pero la primera ha quedado en desuso desde 2014, por lo tanto, use PSR-4. Reduce la complejidad de sus directorios.

Mantenemos cada uno de nuestros complementos / temas en su propio repositorio de Github, cada uno con su propio composer.jsonarchivo y composer.lockarchivo.

Aquí está la estructura de directorios que usamos para nuestros complementos. (Realmente no tenemos un complemento llamado awesome-plugin, pero deberíamos hacerlo).

plugins/awesome-plugin/bootstrap.php
plugins/awesome-plugin/composer.json
plugins/awesome-plugin/composer.lock
plugins/awesome-plugin/awesome-plugin.php
plugins/awesome-plugin/src/*

plugins/awesome-plugin/vendor/autoload.php
plugins/awesome-plugin/vendor/*

Si proporciona un composer.jsonarchivo apropiado , Composer maneja el espacio entre nombres y la carga automática aquí.

{
    "name": "awesome-company/awesome-plugin",
    "description": "Wordpress plugin for AwesomeCompany website, providing awesome functionality.",
    "type": "wordpress-plugin",
    "autoload": {
        "psr-4": {
            "AwesomeCompany\\Plugins\\AwesomePlugin\\": "src"
        }
    }
}

Cuando ejecuta composer install, crea el vendordirectorio y el vendor/autoload.phparchivo, que cargará automáticamente todos sus archivos con espacios de nombres src/y cualquier otra biblioteca que pueda necesitar.

Luego, en la parte superior de su archivo de complemento principal (que para nosotros es awesome-plugin.php), después de los metadatos de su complemento, simplemente necesita:

// Composer autoloading.
require_once __DIR__ . '/vendor/autoload.php';

...

Característica de bonificación

No es una necesidad, pero usamos el repetitivo de Bedrock Wordpress para usar Composer desde el principio. Luego, podemos usar Composer para ensamblar los complementos que necesitamos a través de Composer, incluido su propio complemento que escribió anteriormente. Además, gracias a WPackagist , se puede requerir cualquier otro plugin desde Wordpress.org (véase el ejemplo de cool-themey cool-pluginabajo).

{
  "name": "awesome-company/awesome-website",
  "type": "project",
  "license": "proprietary",
  "description": "WordPress boilerplate with modern development tools, easier configuration, and an improved folder structure",
  "config": {
    "preferred-install": "dist"
  },
  "repositories": [
    {
      "type": "composer",
      "url": "https://wpackagist.org"
    },
    { // Tells Composer to look for our proprietary Awesome Plugin here.
        "url": "https://github.com/awesome-company/awesome-plugin.git",
        "type": "git"
    }
  ],
  "require": {
    "php": ">=5.5",
    "awesome-company/awesome-plugin": "dev-production", // Our plugin!
    "wpackagist-plugin/cool-plugin": "dev-trunk",       // Someone else' plugin
    "wpackagist-theme/cool-theme": "dev-trunk",         // Someone else' theme
    "composer/installers": "~1.2.0",     // Bedrock default
    "vlucas/phpdotenv": "^2.0.1",        // Bedrock default
    "johnpbloch/wordpress": "4.7.5",     // Bedrock default
    "oscarotero/env": "^1.0",            // Bedrock default
    "roots/wp-password-bcrypt": "1.0.0"  // Bedrock default
  },
  "extra": {
    // This is the magic that drops packages with the correct TYPE in the correct location. 
    "installer-paths": {
      "web/app/mu-plugins/{$name}/": ["type:wordpress-muplugin"],
      "web/app/plugins/{$name}/": ["type:wordpress-plugin"],
      "web/app/themes/{$name}/": ["type:wordpress-theme"]
    },
    "wordpress-install-dir": "web/wp"
  },
  "scripts": {
    "test": [
      "vendor/bin/phpcs"
    ]
  }
}

Nota 1: Los comentarios no son legales en JSON, pero he anotado el archivo anterior para mayor claridad.

Nota 2: Corté algunos bits del archivo Bedrock repetitivo para abreviar.

Nota 3: esta es la razón por la cual el typecampo en el primer composer.jsonarchivo es significativo. Composer lo suelta automáticamente en el web/app/pluginsdirectorio.

haz
fuente
Agradezco su respuesta, muy útil! Pero tengo curiosidad sobre el "bootstrap.php" al que te refieres. Que contiene :)
INT
1
Tener un archivo bootstrap.php es algo estilístico que hago en la mayoría de mis proyectos, dentro o fuera de WP. Mi programa de arranque normalmente solo verifica la configuración y las variables de entorno; su objetivo principal es asegurarse de que mi complemento siempre tenga lo que necesita para ejecutarse, independientemente de si se ha ejecutado desde WP o como una aplicación PHP independiente.
haz
4

Utilizo la carga automática (ya que mi complemento tiene muchas clases, en parte porque incluye Twig), nunca tuve un problema que me llamó la atención (el complemento se instaló> 20,000 veces).

Si está seguro de que nunca más necesitará usar una instalación de php que no admite espacios de nombres, entonces está bien (~ 70% de los blogs actuales de WordPress no admiten espacios de nombres). Algunas cosas a tener en cuenta:

Me parece recordar que los espacios de nombres no distinguen entre mayúsculas y minúsculas en php regular, pero sí cuando se usa fastcgi php en iis; esto causa algunos dolores de cabeza si prueba en Linux y no ve una letra minúscula pícara.

Además, incluso si está seguro de que el código que está desarrollando actualmente solo se usará en> 5.3.0, no podrá reutilizar ningún código con proyectos que no tengan ese lujo, esa es la razón principal por la que no lo he hecho. espacios de nombres usados ​​en proyectos internos. He encontrado que los espacios de nombres realmente no añaden que tanto si se compara con la posible dolor de cabeza de tener que quitar la dependencia de ellos.

Daniel Chatfield
fuente