diferentes entornos de desarrollo

Desarrollo en WordPress en diferentes entornos

Hace unos años escribí un artículo para ver cómo podíamos configurar nuestro archivo wp-config.php para trabajar con diferentes entornos. Como suele decirse, ha llovido bastante y yo también he aprendido mucho desde entonces.

Y no sólo eso, WordPress ha también ha evolucionado y desde la versión 5.5 ha añadido una nueva función (wp_get_environment_type()) que devuelve el valor de una constante WP_ENVIRONMENT_TYPE que puedes definir en función de tu entorno.

¿Y para qué es útil esta función? Por lo general cuando estás desarrollando un nuevo proyecto, durante el ciclo de vida del desarrollo trabajas con diferentes entornos. Y ejecutar ciertas cosas en función del entorno se torna necesario.

Hosting WordPress SSD Raiola Networks

Lo más normal es que tengas tu entorno montado en local, donde trabajas en el día a día. Es habitual también tener un entorno de desarrollo, donde se realizan pruebas cuando se integra tu trabajo con el resto de miembros del equipo. Luego el cliente suele (o debería) disponer de un entorno que puede recibir varios nombres: pre, staging, uat, qa… y por último el entorno «real» de producción.

Por resumir, generalizar y estandarizar, en este artículo vamos a hablar de 4 entornos: local, development, staging y production.

¿Qué cambia entre entornos?

Pues son varias cosas las que pueden cambiar entre entornos. Por ejemplo, cuando estamos desarrollando en local nos interesa elevar el nivel de errores para que nos salga en pantalla todos los avisos (notices, warnings, errors…) con el fin de depurarlos y corregirlos.

Justo nos interesará lo contrario en production. También nos interesará en producción activar temas de caché, etc…

Y si tienes integraciones son sistemas de terceros, lo más normal es que por ejemplo, tu entorno de staging se conecte con el entorno de pruebas de tu aplicación de terceros, y que production se integre con el entorno real de tu aplicación. Y probablemente las credenciales no sean las mismas.

¿Cómo hacemos diferentes configuraciones para cada entorno?

Es recomendable que almacenes todas tus variables de entorno en un fichero apto para ello (.env). Lo ideal es que este archivo se encuentre fuera de la raíz donde apunte tu host, para que no sea accesible por navegador.

Y a tu elección tienes dos opciones. Crear un único archivo .env y no versionarlo (para lo que necesitarías un .env.dist), o disponer de tantos archivos de entorno como entornos tengas. Voy a tirar por este camino para ilustrar el ejemplo.

En nuestro caso tendremos 4 entornos, por lo tanto 4 archivos:

  • .env.local, para el entorno local
  • .env.development, para el entorno de desarrollo
  • .env.staging, para el entorno de pre-producción
  • .env, para el entorno de producción

El siguiente paso es definir nuestra constante WP_ENVIRONMENT_TYPE, en el archivo wp-config.php. A continuación, en función del valor de esa constante cargaremos la info del archivo de variables de entorno correspondiente. Para esto necesitaremos hacer uso de la librería vlucas/phpdotenv que puedes cargar a través de composer.

Vamos a ver a continuación cómo quedaría el archivo wp-config.php:

<?php

/**
 * The base configuration for WordPress.
 *
 * The wp-config.php creation script uses this file during the
 * installation. You don't have to use the web site, you can
 * copy this file to "wp-config.php" and fill in the values.
 *
 * This file contains the following configurations:
 *
 * * MySQL settings
 * * Secret keys
 * * Database table prefix
 * * ABSPATH
 *
 * @see https://wordpress.org/support/article/editing-wp-config-php/
 */

// Lo primero de todo es que definas el entorno.
define('WP_ENVIRONMENT_TYPE', 'local');

// A continuación vamos a guardar la ruta donde hemos almacenado nuestros archivos de entorno. En caso de ser un entorno de producción, utilizaremos el archivo '.env' por defecto
$env_path = dirname(__FILE__, 2) . '/config/';
$env_file = '.env' . ('production' === WP_ENVIRONMENT_TYPE ? '' : '.' . WP_ENVIRONMENT_TYPE);

// Si el archivo no existe, lanzamos un error
if (! file_exists($env_path . $env_file)) {
    define('WP_DEBUG', false);
    header('HTTP/1.1 503 Service Unavailable.', true, 503);
    echo 'The application environment is not set correctly.';

    exit(1); // EXIT_ERROR
}

// Si el archivo existe, leemos el contenido. Utilizamos el método createUnsafeImmutable para tener disponible las variables de entorno en la función getenv
require_once ABSPATH . 'vendor/autoload.php';
$dotenv = Dotenv\Dotenv::createUnsafeImmutable($env_path);
$dotenv->load();

// ** MySQL settings - You can get this info from your web host ** //
// The name of the database for WordPress
define('DB_NAME', getenv('DB_NAME') ?: 'db_name');

// MySQL database username
define('DB_USER', getenv('DB_USER') ?: 'db_user');

// MySQL database password
define('DB_PASSWORD', getenv('DB_PASSWORD') ?: 'db_password');

// MySQL hostname
define('DB_HOST', getenv('DB_HOST') ?: 'localhost');

// Database Charset to use in creating database tables.
define('DB_CHARSET', getenv('DB_CHARSET') ?: 'utf8mb4');

// The Database Collate type. Don't change this if in doubt.
define('DB_COLLATE', '');

/*#@+
 * Authentication Unique Keys and Salts.
 *
 * Change these to different unique phrases!
 * You can generate these using the {@link https://api.wordpress.org/secret-key/1.1/salt/ WordPress.org secret-key service}
 * You can change these at any point in time to invalidate all existing cookies. This will force all users to have to log in again.
 *
 * @since 2.6.0
 */
define('AUTH_KEY', 'put your unique phrase here');
define('SECURE_AUTH_KEY', 'put your unique phrase here');
define('LOGGED_IN_KEY', 'put your unique phrase here');
define('NONCE_KEY', 'put your unique phrase here');
define('AUTH_SALT', 'put your unique phrase here');
define('SECURE_AUTH_SALT', 'put your unique phrase here');
define('LOGGED_IN_SALT', 'put your unique phrase here');
define('NONCE_SALT', 'put your unique phrase here');

/** #@- */

/**
 * WordPress Database Table prefix.
 *
 * You can have multiple installations in one database if you give each
 * a unique prefix. Only numbers, letters, and underscores please!
 */
$table_prefix = getenv('DB_PREFIX') ?: 'wp_';

/*
 * For developers: WordPress debugging mode.
 *
 * Change this to true to enable the display of notices during development.
 * It is strongly recommended that plugin and theme developers use WP_DEBUG
 * in their development environments.
 *
 * For information on other constants that can be used for debugging,
 * visit the documentation.
 *
 * @link https://wordpress.org/support/article/debugging-in-wordpress/
 */

// DEBUG
define('WP_DEBUG', filter_var(getenv('WP_DEBUG'), FILTER_VALIDATE_BOOLEAN));
define('SCRIPT_DEBUG', filter_var(getenv('SCRIPT_DEBUG'), FILTER_VALIDATE_BOOLEAN));
define('WP_DEBUG_LOG', filter_var(getenv('WP_DEBUG_LOG'), FILTER_VALIDATE_BOOLEAN));
define('WP_DEBUG_DISPLAY', filter_var(getenv('WP_DEBUG_DISPLAY'), FILTER_VALIDATE_BOOLEAN));

// COMPRESSION
define('COMPRESS_CSS', filter_var(getenv('COMPRESS_CSS'), FILTER_VALIDATE_BOOLEAN));
define('COMPRESS_SCRIPTS', filter_var(getenv('COMPRESS_SCRIPTS'), FILTER_VALIDATE_BOOLEAN));
define('CONCATENATE_SCRIPTS', filter_var(getenv('CONCATENATE_SCRIPTS'), FILTER_VALIDATE_BOOLEAN));
define('ENFORCE_GZIP', filter_var(getenv('ENFORCE_GZIP'), FILTER_VALIDATE_BOOLEAN));

// SSL
define('FORCE_SSL_ADMIN', filter_var(getenv('FORCE_SSL_ADMIN'), FILTER_VALIDATE_BOOLEAN));
define('FORCE_SSL_LOGIN', filter_var(getenv('FORCE_SSL_LOGIN'), FILTER_VALIDATE_BOOLEAN));

// SECURITY
define('IMAGE_EDIT_OVERWRITE', filter_var(getenv('IMAGE_EDIT_OVERWRITE'), FILTER_VALIDATE_BOOLEAN));
define('DISALLOW_FILE_MODS', filter_var(getenv('DISALLOW_FILE_MODS'), FILTER_VALIDATE_BOOLEAN));
define('DISALLOW_FILE_EDIT', filter_var(getenv('DISALLOW_FILE_EDIT'), FILTER_VALIDATE_BOOLEAN));
define('WP_AUTO_UPDATE_CORE', filter_var(getenv('WP_AUTO_UPDATE_CORE'), FILTER_VALIDATE_BOOLEAN));

// CONFIGURATION
define('WP_POST_REVISIONS', filter_var(getenv('WP_POST_REVISIONS'), FILTER_VALIDATE_BOOLEAN));

// That's all, stop editing! Happy publishing.

// Absolute path to the WordPress directory.
if (! defined('ABSPATH')) {
    define('ABSPATH', __DIR__ . '/');
}

/** Sets up WordPress vars and included files. */
require_once ABSPATH . 'wp-settings.php';

A continuación veamos algunas configuraciones interesantes para cada entorno. En local nos interesa activar el nivel de errores al máximo y no haría falta activar todo lo relativo a cachés, compresión, etc… salvo que queramos probar algo concreto. Puede que tampoco nos interesen las revisiones, ni forzar la navegación por SSL (si carecemos de certificados).

Por contra en entornos de producción, nos interesará desactivar los errores para que no aparezcan alertas por notices y warnings (que deberían depurarse gracias a que en otros entornos se evidencian en pantalla). Nos interesará también constantes que tengan que ver con la optimización y la seguridad, o desactivar actualizaciones automáticas (mejor probarlas en otros entornos antes que en producción).

Un ejemplo de un archivo .env.local:

### DDBB ###
DB_NAME=wptest
DB_USER=root
DB_PASSWORD=password
DB_HOST=localhost
DB_PREFIX=wp_
DB_CHARSET=utf8mb4

### DEBUG ###
WP_DEBUG=true
SCRIPT_DEBUG=true
WP_DEBUG_LOG=true
WP_DEBUG_DISPLAY=true

### COMPRESSION ###
COMPRESS_CSS=false
COMPRESS_SCRIPTS=false
CONCATENATE_SCRIPTS=false
ENFORCE_GZIP=false

### SSL ###
FORCE_SSL_ADMIN=false
FORCE_SSL_LOGIN=false

### SECURITY ###
IMAGE_EDIT_OVERWRITE=true
DISALLOW_FILE_MODS=false
DISALLOW_FILE_EDIT=false
WP_AUTO_UPDATE_CORE=false

### CONFIGURATION ###
WP_POST_REVISIONS=false

### 3rd PARTY CONSTANTS ###
FB_APP_ID=YOUR_CREDENTIALS
CLIENT_SECRET=YOUR_CREDENTIALS
TOKEN=YOUR_CREDENTIALS

Puedes hacerte una idea de todas las configuraciones posibles a través de constantes en esta página.

¿Cómo saber en qué entorno estoy?

Siempre podremos preguntar si la constante WP_ENVIRONMENT_TYPE está establecida y qué valor tiene. Pero en los plugins y temas que desarrollemos podemos hacer uso de la función wp_get_environment_type():

switch (wp_get_environment_type()) {
    case 'local':
    case 'development':
        do_nothing();

        break;

    case 'staging':
        do_staging_thing();

        break;

    case 'production':
    default:
        do_production_thing();

        break;
}

La ventaja de utilizar la función es que, entre otras cosas, si la constante no está definida te devuelve por defecto el valor «production«, así puedes evitar posibles errores de constante no definida.

¿Te ha resultado útil esta información? 🍺

Si este post te ha resuelto un problema, invítame a un café o a una cerveza. Con este pequeño gesto me animas a seguir escribiendo.

Comentarios

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *:

  • El fin del tratamiento es únicamente la moderación de comentarios para evitar spam
  • La legitimación es tu consentimiento al comentar
  • No se comunicará ningún dato a terceros salvo por obligación legal
  • Tienes derecho al acceso, rectificación y eliminación de los comentarios