[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$f2uuO3NCOpuAkwOdPnqIf61tHv5QQmobQ3xDTFWgwiJ8":3,"$fDRkOPbuEDkTfZPC1DykMFeLabNfkR7ht3nHJEBkS5-0":43},{"data":4},{"id":5,"estado":6,"titulo":7,"slug":8,"intro":9,"texto":10,"meta_description":11,"categoria_id":12,"imagen_fv_id":13,"categoria":14,"imagen_destacada":19,"tags":23,"creado_en":38,"creado_iso":39,"publicar_en":40,"updated_at":41,"revisado_en":28,"revisado_iso":42},30,1,"Cómo crear un plugin de WordPress desde cero","como-crear-un-plugin-de-wordpress","Para crear un plugin de WordPress desde cero basta un archivo PHP con una cabecera de seis líneas. Vemos la estructura mínima, cómo funcionan las acciones y los filtros, y qué errores evitar antes de subirlo a producción.","\u003Cp class=\"nota-servicio\">Este tutorial explica cómo se programa un plugin de WordPress desde cero. Si lo que buscas es encargarlo, desarrollamos \u003Ca href=\"\u002Fdesarrollo-de-modulos-y-conectores\">módulos y conectores a medida\u003C\u002Fa> sobre WordPress, WooCommerce y PrestaShop.\u003C\u002Fp>\n\n\u003Cp>Para crear un plugin de WordPress desde cero no hace falta un framework ni una estructura de carpetas complicada: basta un archivo PHP con una cabecera de seis líneas. Esa es la respuesta corta, y conviene tenerla delante antes de empezar, porque la mayoría de tutoriales arrancan montando un andamiaje que todavía no necesitas.\u003C\u002Fp>\n\n\u003Ch2>Antes de programar un plugin de WordPress: ¿de verdad hace falta?\u003C\u002Fh2>\n\n\u003Cp>En el repositorio oficial hay decenas de miles de plugins. Antes de escribir una línea, busca. Si existe uno mantenido que hace lo que necesitas, usarlo casi siempre sale mejor: alguien más lo parchea cuando aparece un fallo de seguridad.\u003C\u002Fp>\n\n\u003Cp>Programar el tuyo compensa en tres casos concretos:\u003C\u002Fp>\n\n\u003Cul>\n\u003Cli>\u003Cstrong>No existe.\u003C\u002Fstrong> La funcionalidad es específica de tu negocio: un cálculo propio, una integración con tu ERP, un tipo de contenido que sólo tiene sentido en tu sector.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Existe pero trae diez veces más de lo que necesitas.\u003C\u002Fstrong> Instalar un plugin de cuatro megas para añadir un campo a un formulario es pagar con rendimiento algo que se resuelve en treinta líneas.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Existe y está abandonado.\u003C\u002Fstrong> Última actualización hace tres años y avisos de incompatibilidad en la ficha. Ahí el plugin no es una solución, es una deuda.\u003C\u002Fli>\n\u003C\u002Ful>\n\n\u003Cp>Y hay un caso en el que un plugin es la herramienta equivocada: si lo que quieres cambiar es cómo se ve el sitio, eso va en el tema o en un tema hijo, no en un plugin. La regla es vieja pero sigue valiendo: \u003Cstrong>el tema es la apariencia, el plugin es el comportamiento.\u003C\u002Fstrong> Si desactivas el plugin y se rompe el diseño, algo has puesto en el sitio que no era.\u003C\u002Fp>\n\n\u003Ch2>Dónde vive un plugin de WordPress y cómo debe llamarse\u003C\u002Fh2>\n\n\u003Cp>Los plugins van en \u003Ccode>wp-content\u002Fplugins\u003C\u002Fcode>. Crea ahí una carpeta con el nombre del tuyo y, dentro, un archivo PHP con ese mismo nombre:\u003C\u002Fp>\n\n\u003Cpre>wp-content\u002Fplugins\u002F\n└── airearte-avisos\u002F\n    └── airearte-avisos.php\u003C\u002Fpre>\n\n\u003Cp>Usa guiones y minúsculas, y \u003Cstrong>prefija absolutamente todo\u003C\u002Fstrong>: la carpeta, el archivo, las funciones, las clases, las constantes y las opciones que guardes en la base de datos. WordPress carga todos los plugins activos en el mismo espacio de nombres global, así que si tú declaras una función \u003Ccode>enviar_aviso()\u003C\u002Fcode> y otro plugin declara otra igual, PHP aborta con un error fatal y el sitio se cae entero. No es un riesgo teórico: es la causa más común de la pantalla en blanco al activar.\u003C\u002Fp>\n\n\u003Ch2>La cabecera es lo único que WordPress necesita para reconocerlo\u003C\u002Fh2>\n\n\u003Cp>Un archivo PHP se convierte en plugin en cuanto empieza por un comentario con esta forma:\u003C\u002Fp>\n\n\u003Cpre>\u003C?php\n\u002F**\n * Plugin Name:       Airearte Avisos\n * Description:       Muestra un aviso configurable encima del contenido.\n * Version:           1.0.0\n * Requires at least: 6.0\n * Requires PHP:      8.0\n * Author:            Airearte\n * Author URI:        https:\u002F\u002Fairearte.es\n * License:           GPL-2.0-or-later\n * Text Domain:       airearte-avisos\n *\u002F\u003C\u002Fpre>\n\n\u003Cp>WordPress lee ese bloque y con él pinta la fila del plugin en el panel. Sólo \u003Ccode>Plugin Name\u003C\u002Fcode> es obligatorio, pero merece la pena rellenar dos que casi nadie pone: \u003Ccode>Requires at least\u003C\u002Fcode> y \u003Ccode>Requires PHP\u003C\u002Fcode>. Con ellas, WordPress se niega a activar el plugin en una instalación que no cumple los requisitos, en lugar de dejar que reviente a mitad.\u003C\u002Fp>\n\n\u003Ch2>Cierra la puerta al acceso directo\u003C\u002Fh2>\n\n\u003Cp>Justo después de la cabecera, en \u003Cem>todos\u003C\u002Fem> los archivos PHP del plugin:\u003C\u002Fp>\n\n\u003Cpre>defined( 'ABSPATH' ) || exit;\u003C\u002Fpre>\n\n\u003Cp>\u003Ccode>ABSPATH\u003C\u002Fcode> la define WordPress al arrancar. Si alguien pide tu archivo directamente por URL, esa constante no existe y el script termina sin ejecutar nada. Es una línea y evita toda una familia de problemas.\u003C\u002Fp>\n\n\u003Ch2>Las rutas las calcula WordPress, no las escribas a mano\u003C\u002Fh2>\n\n\u003Cp>Aquí es donde se cuela un error clásico: escribir la ruta del plugin concatenando \u003Ccode>ABSPATH\u003C\u002Fcode> con \u003Ccode>'wp-content\u002Fplugins\u002Fmi-plugin'\u003C\u002Fcode>. Funciona en tu portátil y falla en cuanto el sitio tiene \u003Ccode>wp-content\u003C\u002Fcode> movido de sitio, que es algo que se hace a menudo por seguridad. Usa las funciones que existen para esto:\u003C\u002Fp>\n\n\u003Cpre>define( 'AIREARTE_AVISOS_DIR', plugin_dir_path( __FILE__ ) );\ndefine( 'AIREARTE_AVISOS_URL', plugin_dir_url( __FILE__ ) );\u003C\u002Fpre>\n\n\u003Cp>La primera te da la ruta en disco y sirve para hacer \u003Ccode>require\u003C\u002Fcode> de otros archivos. La segunda te da la URL pública y sirve para encolar hojas de estilo, scripts o imágenes. No son intercambiables, y confundirlas produce el fallo más desconcertante del principiante: una imagen que no carga y una ruta del servidor asomando en el HTML.\u003C\u002Fp>\n\n\u003Cfigure>\n\u003Cimg src=\"\u002Fstorage\u002Fimagen\u002Fplugin-wordpress-hooks-portatil.webp\" alt=\"Portátil mostrando en el editor el código PHP de un plugin de WordPress\" width=\"1600\" height=\"1067\" loading=\"lazy\" decoding=\"async\" \u002F>\n\u003Cfigcaption>Los hooks son el mecanismo por el que WordPress llama a tu plugin, y no al revés.\u003C\u002Ffigcaption>\n\u003C\u002Ffigure>\n\n\u003Ch2>Los hooks de WordPress: cómo entra tu código en la plataforma\u003C\u002Fh2>\n\n\u003Cp>WordPress no llama a tu plugin. Tu plugin le dice a WordPress cuándo quiere que lo llamen. Ese mecanismo son los \u003Cstrong>hooks\u003C\u002Fstrong>, y hay de dos tipos.\u003C\u002Fp>\n\n\u003Ch3>Las acciones ejecutan código en un momento concreto\u003C\u002Fh3>\n\n\u003Cp>Una acción es un punto del ciclo de carga donde puedes colgar una función tuya. No devuelve nada: hace algo.\u003C\u002Fp>\n\n\u003Cpre>add_action( 'wp_enqueue_scripts', 'airearte_avisos_estilos' );\n\nfunction airearte_avisos_estilos() {\n    wp_enqueue_style(\n        'airearte-avisos',\n        AIREARTE_AVISOS_URL . 'css\u002Favisos.css',\n        array(),\n        '1.0.0'\n    );\n}\u003C\u002Fpre>\n\n\u003Cp>Fíjate en el hook elegido. Para cargar CSS es \u003Ccode>wp_enqueue_scripts\u003C\u002Fcode>, no \u003Ccode>wp_head\u003C\u002Fcode>. Escribir un \u003Ccode>&lt;link&gt;\u003C\u002Fcode> a pelo en \u003Ccode>wp_head\u003C\u002Fcode> funciona, pero se salta el sistema de dependencias y versiones de WordPress, y acabas con el mismo estilo cargado dos veces y sin forma de invalidar la caché del navegador. \u003Cstrong>Casi siempre existe un hook más específico que el que se te ocurre primero\u003C\u002Fstrong>, y usar el correcto es la diferencia entre un plugin que convive con los demás y uno que pelea con ellos.\u003C\u002Fp>\n\n\u003Ch3>Los filtros modifican un valor antes de que se use\u003C\u002Fh3>\n\n\u003Cp>Un filtro recibe algo, lo cambia y \u003Cstrong>lo devuelve\u003C\u002Fstrong>. Esa última parte es obligatoria:\u003C\u002Fp>\n\n\u003Cpre>add_filter( 'the_content', 'airearte_avisos_contenido' );\n\nfunction airearte_avisos_contenido( $contenido ) {\n    if ( ! is_singular( 'post' ) || ! is_main_query() ) {\n        return $contenido;\n    }\n\n    $aviso = get_option( 'airearte_avisos_texto', '' );\n\n    if ( '' === $aviso ) {\n        return $contenido;\n    }\n\n    return '&lt;p class=\"aviso\"&gt;' . esc_html( $aviso ) . '&lt;\u002Fp&gt;' . $contenido;\n}\u003C\u002Fpre>\n\n\u003Cp>Si olvidas el \u003Ccode>return\u003C\u002Fcode>, la función devuelve \u003Ccode>null\u003C\u002Fcode> y borras el contenido de todas las entradas del sitio. Es el fallo más frecuente con filtros y también el más aparatoso.\u003C\u002Fp>\n\n\u003Cp>Ese ejemplo hace además otras dos cosas que conviene copiar. La primera, comprobar dónde estás: \u003Ccode>the_content\u003C\u002Fcode> se dispara también en los listados, en los feeds y en cualquier consulta secundaria, así que sin la condición el aviso sale multiplicado por toda la portada. La segunda, \u003Ccode>esc_html()\u003C\u002Fcode> al sacar un valor guardado. Todo lo que venga de la base de datos o de un formulario se escapa al imprimirlo, sin excepciones.\u003C\u002Fp>\n\n\u003Ch3>Prioridad y número de argumentos\u003C\u002Fh3>\n\n\u003Cp>Tanto \u003Ccode>add_action()\u003C\u002Fcode> como \u003Ccode>add_filter()\u003C\u002Fcode> aceptan dos parámetros más:\u003C\u002Fp>\n\n\u003Cpre>add_filter( 'the_content', 'airearte_avisos_contenido', 20, 1 );\u003C\u002Fpre>\n\n\u003Cp>El tercero es la \u003Cstrong>prioridad\u003C\u002Fstrong>: por defecto 10, y cuanto más bajo, antes se ejecuta. Súbelo cuando necesites actuar después de otro plugin que toca lo mismo. El cuarto es el \u003Cstrong>número de argumentos\u003C\u002Fstrong> que quieres recibir. Por defecto es 1, y si el hook pasa tres y tú no lo declaras, los otros dos no llegan: te encuentras con una variable vacía sin ningún error que lo explique.\u003C\u002Fp>\n\n\u003Ch2>Activación y desactivación del plugin\u003C\u002Fh2>\n\n\u003Cp>Si tu plugin necesita preparar algo la primera vez —una opción por defecto, una tabla, una tarea programada—, ese código no va suelto en el archivo, porque se ejecutaría en cada carga de cada página. Va en el hook de activación, que corre una sola vez:\u003C\u002Fp>\n\n\u003Cpre>register_activation_hook( __FILE__, 'airearte_avisos_activar' );\n\nfunction airearte_avisos_activar() {\n    add_option( 'airearte_avisos_texto', '' );\n}\n\nregister_deactivation_hook( __FILE__, 'airearte_avisos_desactivar' );\n\nfunction airearte_avisos_desactivar() {\n    wp_clear_scheduled_hook( 'airearte_avisos_tarea' );\n}\u003C\u002Fpre>\n\n\u003Cp>Al desactivar se limpia lo que consume recursos —tareas programadas, cachés—, pero \u003Cstrong>no se borran los datos del usuario\u003C\u002Fstrong>. Mucha gente desactiva un plugin para descartar un problema y lo vuelve a activar cinco minutos después; si al desactivarlo has borrado su configuración, te has ganado una reseña de una estrella. El borrado definitivo va en \u003Ccode>uninstall.php\u003C\u002Fcode>, que WordPress ejecuta sólo cuando se elimina el plugin de verdad.\u003C\u002Fp>\n\n\u003Ch2>Lo que aquí no hemos visto\u003C\u002Fh2>\n\n\u003Cp>Con lo anterior tienes un plugin funcional. Para uno que vaya a producción faltan cuatro cosas, y merece la pena saber que existen:\u003C\u002Fp>\n\n\u003Cul>\n\u003Cli>\u003Cstrong>Página de ajustes.\u003C\u002Fstrong> En cuanto haya un formulario en el panel, necesitas \u003Ccode>nonces\u003C\u002Fcode> para verificar que la petición viene de tu formulario y \u003Ccode>current_user_can()\u003C\u002Fcode> para comprobar que quien la manda tiene permiso. Sin las dos, cualquier usuario registrado puede cambiar la configuración.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Saneado a la entrada.\u003C\u002Fstrong> Escapar a la salida no basta: lo que llega de un formulario se sanea antes de guardarlo, con \u003Ccode>sanitize_text_field()\u003C\u002Fcode>, \u003Ccode>wp_kses_post()\u003C\u002Fcode> o la función que corresponda al tipo de dato.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Traducciones.\u003C\u002Fstrong> Envuelve los textos visibles en \u003Ccode>__()\u003C\u002Fcode> o \u003Ccode>esc_html__()\u003C\u002Fcode> con tu \u003Cem>text domain\u003C\u002Fem> desde el principio. Añadirlas después obliga a repasar el plugin entero.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Clases en vez de funciones sueltas.\u003C\u002Fstrong> Pasadas dos o tres funcionalidades, agrupar en una clase con prefijo ahorra la mitad de los conflictos de nombres.\u003C\u002Fli>\n\u003C\u002Ful>\n\n\u003Ch2>Los cinco fallos más comunes al programar un plugin\u003C\u002Fh2>\n\n\u003Col>\n\u003Cli>\u003Cstrong>No prefijar.\u003C\u002Fstrong> Colisión de nombres y error fatal al activar.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Un filtro sin \u003Ccode>return\u003C\u002Fcode>.\u003C\u002Fstrong> Se vacía el contenido del sitio.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Escribir rutas a mano\u003C\u002Fstrong> en lugar de \u003Ccode>plugin_dir_path()\u003C\u002Fcode> y \u003Ccode>plugin_dir_url()\u003C\u002Fcode>.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>No escapar a la salida.\u003C\u002Fstrong> Cualquier valor guardado que se imprime sin \u003Ccode>esc_html()\u003C\u002Fcode> o equivalente es una puerta abierta.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Modificar el plugin directamente en producción.\u003C\u002Fstrong> Un error de sintaxis deja el sitio en blanco y el editor del panel ya no está disponible para arreglarlo.\u003C\u002Fli>\n\u003C\u002Fol>\n\n\u003Ch2>Y cuándo dejar de programarlo tú\u003C\u002Fh2>\n\n\u003Cp>Un plugin propio es código que alguien tiene que mantener cuando WordPress publique la siguiente versión mayor, cuando cambie el mínimo de PHP o cuando el plugin con el que convive se actualice. Si lo que necesitas toca pagos, datos personales o la sincronización con otro sistema, el coste no está en escribirlo: está en los años siguientes.\u003C\u002Fp>\n\n\u003Cp>Esa es justamente la parte que cubrimos nosotros en \u003Ca href=\"\u002Fdesarrollo-de-modulos-y-conectores\">módulos y conectores a medida\u003C\u002Fa>. Y si no lo tienes claro, \u003Ca href=\"\u002Fcontacto\">cuéntanos qué quieres resolver\u003C\u002Fa>: si lo cubre un plugin del repositorio, te lo diremos.\u003C\u002Fp>\n\n\u003Cp class=\"revision\">\u003Cem>Publicado en diciembre de 2016 como serie en dos partes. Refundido y revisado en agosto de 2026.\u003C\u002Fem>\u003C\u002Fp>","Guía paso a paso para crear un plugin de WordPress: estructura, cabecera, hooks, acciones y filtros, con código listo para copiar y los fallos más comunes.",2,276,{"id":12,"nombre":15,"slug":16,"pagina":17,"creado_en":18,"actualizado_en":18},"Desarrollo web a medida","desarrollo-web-a-medida","trabajos","20-04-2026",{"id":13,"url":20,"alt":21,"title":7,"parent_type":22,"parent_id":5},"https:\u002F\u002Fairearte.es\u002Fstorage\u002Fimagen\u002Fplugin-wordpress-editor-codigo.webp","Editor de código con un archivo PHP abierto durante el desarrollo de un plugin de WordPress","App\\Models\\Articulo",[24,29,34],{"id":25,"etiqueta":26,"slug":27,"creado_en":18,"actualizado_en":28},58,"WordPress","wordpress","25-08-2026",{"id":30,"etiqueta":31,"slug":32,"creado_en":33,"actualizado_en":33},407,"Tutorial","tutorial","24-04-2026",{"id":35,"etiqueta":36,"slug":37,"creado_en":18,"actualizado_en":18},19,"Desarrollo web","desarrollo-web","07-12-2016","2016-12-07T15:53:41+00:00","2016-12-07","2026-08-25T09:35:05.000000Z","2026-08-25T09:35:05+00:00",{"data":44},[45,52,78],{"id":5,"estado":6,"titulo":7,"slug":8,"intro":9,"texto":10,"meta_description":11,"categoria_id":12,"imagen_fv_id":13,"categoria":46,"imagen_destacada":47,"tags":48,"creado_en":38,"creado_iso":39,"publicar_en":40,"updated_at":41,"revisado_en":28,"revisado_iso":42},{"id":12,"nombre":15,"slug":16,"pagina":17,"creado_en":18,"actualizado_en":18},{"id":13,"url":20,"alt":21,"title":7,"parent_type":22,"parent_id":5},[49,50,51],{"id":25,"etiqueta":26,"slug":27,"creado_en":18,"actualizado_en":28},{"id":30,"etiqueta":31,"slug":32,"creado_en":33,"actualizado_en":33},{"id":35,"etiqueta":36,"slug":37,"creado_en":18,"actualizado_en":18},{"id":53,"estado":6,"titulo":54,"slug":55,"intro":56,"texto":57,"meta_description":58,"categoria_id":12,"imagen_fv_id":59,"categoria":60,"imagen_destacada":61,"tags":64,"creado_en":75,"creado_iso":76,"publicar_en":77,"updated_at":41,"revisado_en":28,"revisado_iso":42},29,"Cómo crear un módulo de PrestaShop desde cero","primer-modulo-en-prestashop","Vamos a crear un módulo de PrestaShop completo y funcional: un bloque de HTML editable desde el back-office que se muestra en la portada de la tienda. Instalar, configurar, guardar y mostrar: con esas cuatro piezas se hacen casi todos los demás.","\u003Cp class=\"nota-servicio\">Este tutorial explica cómo se construye un módulo de PrestaShop paso a paso. Si lo que necesitas es que te lo desarrollemos nosotros, esto es lo que hacemos en \u003Ca href=\"\u002Fdesarrollo-de-modulos-y-conectores\">módulos y conectores a medida\u003C\u002Fa>.\u003C\u002Fp>\n\n\u003Cp>Para crear un módulo de PrestaShop desde cero basta una carpeta, un archivo PHP y un hook. Vamos a construir uno completo y funcional: un bloque de HTML que el gestor de la tienda edita desde el back-office y que se pinta en la portada. Es el ejemplo más corto que recorre entero el ciclo de un módulo —instalación, configuración, guardado y presentación—, y con esas cuatro piezas ya se pueden hacer casi todas las demás.\u003C\u002Fp>\n\n\u003Cul>\n\u003Cli>\u003Cstrong>Requisitos:\u003C\u002Fstrong> PHP y HTML a nivel básico, y haberte movido antes por el back-office de PrestaShop.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Dificultad:\u003C\u002Fstrong> media.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Versiones:\u003C\u002Fstrong> el código está escrito para PrestaShop 1.7, 8 y 9, que comparten esta arquitectura de módulos. Si vienes de 1.6, la estructura cambió.\u003C\u002Fli>\n\u003C\u002Ful>\n\n\u003Ch2>Antes de programar un módulo de PrestaShop: cuándo compensa y cuándo no\u003C\u002Fh2>\n\n\u003Cp>PrestaShop trae unos doscientos módulos nativos y el marketplace tiene miles. Programar el tuyo compensa cuando la funcionalidad es propia de tu negocio o cuando lo que hay en el mercado te obliga a instalar diez veces más de lo que necesitas.\u003C\u002Fp>\n\n\u003Cp>Lo que \u003Cstrong>no\u003C\u002Fstrong> debe ir en un módulo es la apariencia de la tienda: eso es el tema. Y sobre todo, nunca toques el núcleo. Modificar archivos de \u003Ccode>classes\u002F\u003C\u002Fcode> o \u003Ccode>controllers\u002F\u003C\u002Fcode> funciona hasta la primera actualización, y entonces se pierde: o pierdes tus cambios, o te quedas sin poder actualizar. \u003Cstrong>El sistema de hooks existe precisamente para no tener que hacerlo.\u003C\u002Fstrong>\u003C\u002Fp>\n\n\u003Ch2>La estructura mínima de un módulo de PrestaShop\u003C\u002Fh2>\n\n\u003Cp>Un módulo es una carpeta dentro de \u003Ccode>modules\u002F\u003C\u002Fcode> con un archivo PHP que se llama igual:\u003C\u002Fp>\n\n\u003Cpre>modules\u002F\n└── airearte_html\u002F\n    ├── airearte_html.php\n    └── views\u002F\n        └── templates\u002F\n            └── hook\u002F\n                └── home.tpl\u003C\u002Fpre>\n\n\u003Cp>El nombre de la carpeta, el del archivo y la propiedad \u003Ccode>$this->name\u003C\u002Fcode> tienen que coincidir exactamente. La clase es ese mismo nombre con las iniciales en mayúscula y \u003Cstrong>conservando los guiones bajos\u003C\u002Fstrong>: para \u003Ccode>airearte_html\u003C\u002Fcode>, la clase es \u003Ccode>Airearte_Html\u003C\u002Fcode>. Funciona porque en PHP los nombres de clase no distinguen mayúsculas, y es la convención que siguen los propios módulos nativos (\u003Ccode>ps_emailsubscription\u003C\u002Fcode> declara \u003Ccode>Ps_Emailsubscription\u003C\u002Fcode>). Si algo de esto no cuadra, PrestaShop no lista el módulo y no da ninguna pista de por qué.\u003C\u002Fp>\n\n\u003Cp>Para no escribir el esqueleto a mano existe el \u003Ca href=\"https:\u002F\u002Fvalidator.prestashop.com\u002Fgenerator\" target=\"_blank\" rel=\"noopener\">generador oficial de módulos\u003C\u002Fa>, que pide nombre, descripción, autor y los hooks que quieras registrar, y te devuelve el andamiaje listo. Necesita cuenta en prestashop.com.\u003C\u002Fp>\n\n\u003Cfigure>\n\u003Cimg src=\"\u002Fstorage\u002Fimagen\u002Fmodulo-prestashop-codigo.webp\" alt=\"Primer plano del código de un módulo de PrestaShop en la pantalla de un desarrollador\" width=\"1600\" height=\"1067\" loading=\"lazy\" decoding=\"async\" \u002F>\n\u003Cfigcaption>El archivo principal del módulo: una clase que extiende \u003Ccode>Module\u003C\u002Fcode> y poco más.\u003C\u002Ffigcaption>\n\u003C\u002Ffigure>\n\n\u003Ch2>El archivo principal del módulo\u003C\u002Fh2>\n\n\u003Cpre>\u003C?php\n\nif (!defined('_PS_VERSION_')) {\n    exit;\n}\n\nclass Airearte_Html extends Module\n{\n    public function __construct()\n    {\n        $this->name = 'airearte_html';\n        $this->tab = 'front_office_features';\n        $this->version = '1.0.0';\n        $this->author = 'Airearte';\n        $this->need_instance = 0;\n        $this->ps_versions_compliancy = ['min' => '1.7.0.0', 'max' => _PS_VERSION_];\n        $this->bootstrap = true;\n\n        parent::__construct();\n\n        $this->displayName = $this->l('Bloque HTML en la portada');\n        $this->description = $this->l('Muestra en la portada un HTML editable desde el back-office.');\n    }\n}\u003C\u002Fpre>\n\n\u003Cp>Dos detalles que se pasan por alto. \u003Ccode>displayName\u003C\u002Fcode> y \u003Ccode>description\u003C\u002Fcode> van \u003Cstrong>después\u003C\u002Fstrong> de \u003Ccode>parent::__construct()\u003C\u002Fcode>, porque antes de esa llamada el sistema de traducciones todavía no está listo. Y \u003Ccode>ps_versions_compliancy\u003C\u002Fcode> evita que alguien lo instale en una versión donde no funciona: es la diferencia entre un aviso claro y un error a mitad de la instalación.\u003C\u002Fp>\n\n\u003Ch2>Instalar y desinstalar el módulo\u003C\u002Fh2>\n\n\u003Cp>La instalación hace dos cosas: registrar el hook donde queremos aparecer y dejar la configuración con un valor inicial.\u003C\u002Fp>\n\n\u003Cpre>const CLAVE = 'AIREARTE_HTML_CONTENIDO';\n\npublic function install()\n{\n    return parent::install()\n        && $this->registerHook('displayHome')\n        && Configuration::updateValue(self::CLAVE, '');\n}\n\npublic function uninstall()\n{\n    return parent::uninstall()\n        && Configuration::deleteByName(self::CLAVE);\n}\u003C\u002Fpre>\n\n\u003Cp>\u003Cstrong>La clave de configuración, en una constante.\u003C\u002Fstrong> Puede parecer manía, pero es el fallo más común de este tipo de módulos: se guarda con un nombre y se lee con otro, el formulario aparenta funcionar, y en la portada no sale nada. Con una constante el error no se puede cometer.\u003C\u002Fp>\n\n\u003Cp>Y desinstalar limpia lo que se creó. Un módulo que deja su configuración tirada en la tabla \u003Ccode>ps_configuration\u003C\u002Fcode> es basura acumulada que nadie va a ir a buscar.\u003C\u002Fp>\n\n\u003Ch2>La página de configuración en el back-office\u003C\u002Fh2>\n\n\u003Cp>Cuando el gestor pulsa «Configurar», PrestaShop llama a \u003Ccode>getContent()\u003C\u002Fcode>. Ese método hace las dos cosas: procesa el envío si lo hay y devuelve el formulario.\u003C\u002Fp>\n\n\u003Cpre>public function getContent()\n{\n    $salida = '';\n\n    if (Tools::isSubmit('submitAirearteHtml')) {\n        $contenido = Tools::getValue('AIREARTE_HTML_CONTENIDO');\n\n        if (!Validate::isCleanHtml($contenido)) {\n            $salida .= $this->displayError($this->l('El contenido no es válido.'));\n        } else {\n            Configuration::updateValue(self::CLAVE, $contenido, true);\n            $salida .= $this->displayConfirmation($this->l('Cambios guardados.'));\n        }\n    }\n\n    return $salida . $this->renderForm();\n}\u003C\u002Fpre>\n\n\u003Cp>Tres cosas importan aquí:\u003C\u002Fp>\n\n\u003Cul>\n\u003Cli>El nombre que se comprueba en \u003Ccode>Tools::isSubmit()\u003C\u002Fcode> tiene que ser \u003Cstrong>el mismo\u003C\u002Fstrong> que el del botón de envío del formulario. Es la segunda causa de «le doy a guardar y no pasa nada».\u003C\u002Fli>\n\u003Cli>\u003Ccode>Validate::isCleanHtml()\u003C\u002Fcode> rechaza el HTML con \u003Ccode>&lt;script&gt;\u003C\u002Fcode> y con manejadores de eventos. Estamos dejando que alguien meta HTML en la portada de la tienda: sin esta comprobación, el módulo es un agujero abierto.\u003C\u002Fli>\n\u003Cli>El tercer parámetro de \u003Ccode>Configuration::updateValue()\u003C\u002Fcode> es el que permite guardar HTML. Sin ese \u003Ccode>true\u003C\u002Fcode>, PrestaShop escapa las etiquetas y lo que se guarda es el código en texto plano.\u003C\u002Fli>\n\u003C\u002Ful>\n\n\u003Cp>El formulario se monta con \u003Ccode>HelperForm\u003C\u002Fcode>, que se encarga de darle el aspecto del panel:\u003C\u002Fp>\n\n\u003Cpre>protected function renderForm()\n{\n    $campos = [[\n        'form' => [\n            'legend' => ['title' => $this->l('Contenido'), 'icon' => 'icon-cogs'],\n            'input' => [[\n                'type' => 'textarea',\n                'label' => $this->l('HTML'),\n                'name' => 'AIREARTE_HTML_CONTENIDO',\n                'autoload_rte' => true,\n                'cols' => 100,\n                'rows' => 20,\n            ]],\n            'submit' => ['title' => $this->l('Guardar')],\n        ],\n    ]];\n\n    $helper = new HelperForm();\n    $helper->module = $this;\n    $helper->identifier = $this->identifier;\n    $helper->submit_action = 'submitAirearteHtml';\n    $helper->currentIndex = AdminController::$currentIndex . '&amp;configure=' . $this->name;\n    $helper->token = Tools::getAdminTokenLite('AdminModules');\n    $helper->tpl_vars = [\n        'fields_value' => [self::CLAVE => Configuration::get(self::CLAVE)],\n    ];\n\n    return $helper->generateForm($campos);\n}\u003C\u002Fpre>\n\n\u003Cp>\u003Ccode>'autoload_rte' =&gt; true\u003C\u002Fcode> convierte el textarea en el editor visual del panel. Es una línea y le cambia la vida a quien vaya a usar el módulo todos los días.\u003C\u002Fp>\n\n\u003Ch2>Pintarlo en la portada: el hook devuelve, no imprime\u003C\u002Fh2>\n\n\u003Cp>Esta es la parte donde más gente se atasca, y casi siempre por el mismo motivo:\u003C\u002Fp>\n\n\u003Cpre>public function hookDisplayHome($params)\n{\n    $this->context->smarty->assign([\n        'airearte_html' => Configuration::get(self::CLAVE),\n    ]);\n\n    return $this->fetch('module:airearte_html\u002Fviews\u002Ftemplates\u002Fhook\u002Fhome.tpl');\n}\u003C\u002Fpre>\n\n\u003Cp>\u003Cstrong>Un hook de visualización tiene que \u003Cem>devolver\u003C\u002Fem> el HTML, no imprimirlo.\u003C\u002Fstrong> Si usas \u003Ccode>echo\u003C\u002Fcode>, el contenido sale igualmente, pero fuera de sitio: se escribe en el momento en que PHP ejecuta el hook, no en el punto de la plantilla donde le toca. El resultado típico es el bloque asomando por encima de la cabecera, o partiendo el diseño. Se ve raro, se busca en el CSS, y el problema estaba en una palabra.\u003C\u002Fp>\n\n\u003Cp>La plantilla es de una línea:\u003C\u002Fp>\n\n\u003Cpre>{if $airearte_html}\n    &lt;div class=\"airearte-html\"&gt;{$airearte_html nofilter}&lt;\u002Fdiv&gt;\n{\u002Fif}\u003C\u002Fpre>\n\n\u003Cp>El modificador \u003Ccode>nofilter\u003C\u002Fcode> es obligatorio: el Smarty de PrestaShop escapa por defecto todo lo que se imprime, así que sin él verías las etiquetas en pantalla en lugar del bloque. Y es exactamente por eso que antes había que validar el HTML al guardarlo: aquí ya no hay red.\u003C\u002Fp>\n\n\u003Ch2>Los errores que más tiempo cuestan al crear un módulo\u003C\u002Fh2>\n\n\u003Col>\n\u003Cli>\u003Cstrong>Nombre de carpeta, archivo, clase y \u003Ccode>$this->name\u003C\u002Fcode> descuadrados.\u003C\u002Fstrong> El módulo no aparece en la lista y no hay mensaje de error.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Guardar con una clave y leer con otra.\u003C\u002Fstrong> Guarda sin quejarse y no muestra nada.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>El \u003Ccode>submit_action\u003C\u002Fcode> y el \u003Ccode>Tools::isSubmit()\u003C\u002Fcode> distintos.\u003C\u002Fstrong> El botón no hace nada.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>\u003Ccode>echo\u003C\u002Fcode> en lugar de \u003Ccode>return\u003C\u002Fcode>\u003C\u002Fstrong> en un hook de visualización.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Olvidar el \u003Ccode>true\u003C\u002Fcode> de \u003Ccode>updateValue()\u003C\u002Fcode>\u003C\u002Fstrong> al guardar HTML, o el \u003Ccode>nofilter\u003C\u002Fcode> en la plantilla.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Tocar archivos del núcleo\u003C\u002Fstrong> «sólo esta vez». Nunca es sólo esta vez.\u003C\u002Fli>\n\u003C\u002Fol>\n\n\u003Cp>Cuando algo no cuadre, activa el modo depuración en \u003Ccode>config\u002Fdefines.inc.php\u003C\u002Fcode> (\u003Ccode>_PS_MODE_DEV_\u003C\u002Fcode> a \u003Ccode>true\u003C\u002Fcode>) y borra la caché desde Parámetros avanzados. PrestaShop cachea las plantillas con ganas: una parte considerable de los «no funciona» son en realidad «no se ha recargado».\u003C\u002Fp>\n\n\u003Ch2>De aquí en adelante\u003C\u002Fh2>\n\n\u003Cp>Con este esqueleto ya puedes registrar otros hooks, añadir tablas propias, encolar tu CSS o llamar a una API externa. El salto de dificultad no está en la primera versión: está en mantenerla cuando llegue la siguiente versión mayor de PrestaShop, cuando cambie el mínimo de PHP o cuando haya que sincronizar la tienda con el ERP y aparezcan los casos raros.\u003C\u002Fp>\n\n\u003Cp>Esa parte es la que cubrimos en \u003Ca href=\"\u002Fdesarrollo-de-modulos-y-conectores\">módulos y conectores a medida\u003C\u002Fa>, y también trabajamos sobre la tienda entera en \u003Ca href=\"\u002Ftienda-online\">desarrollo de tiendas online\u003C\u002Fa>. Si no tienes claro si lo tuyo necesita un módulo, \u003Ca href=\"\u002Fcontacto\">cuéntanoslo\u003C\u002Fa>: cuando lo resuelve algo que ya existe, lo decimos.\u003C\u002Fp>\n\n\u003Cp class=\"revision\">\u003Cem>Publicado en noviembre de 2016. Revisado y actualizado a PrestaShop 1.7, 8 y 9 en agosto de 2026.\u003C\u002Fem>\u003C\u002Fp>","Tutorial para crear un módulo de PrestaShop 1.7, 8 y 9: estructura, instalación, configuración con HelperForm y hook displayHome, con el código completo.",278,{"id":12,"nombre":15,"slug":16,"pagina":17,"creado_en":18,"actualizado_en":18},{"id":59,"url":62,"alt":63,"title":54,"parent_type":22,"parent_id":53},"https:\u002F\u002Fairearte.es\u002Fstorage\u002Fimagen\u002Fmodulo-prestashop-tienda-online.webp","Responsable de una tienda online preparando pedidos junto al portátil",[65,69,70,71],{"id":66,"etiqueta":67,"slug":68,"creado_en":18,"actualizado_en":28},81,"PrestaShop","prestashop",{"id":30,"etiqueta":31,"slug":32,"creado_en":33,"actualizado_en":33},{"id":35,"etiqueta":36,"slug":37,"creado_en":18,"actualizado_en":18},{"id":72,"etiqueta":73,"slug":74,"creado_en":18,"actualizado_en":33},40,"Tiendas online","tienda-online","21-11-2016","2016-11-21T16:06:46+00:00","2016-11-21",{"id":79,"estado":6,"titulo":80,"slug":81,"intro":82,"texto":83,"meta_description":84,"categoria_id":12,"imagen_fv_id":85,"categoria":86,"imagen_destacada":87,"tags":91,"creado_en":93,"creado_iso":94,"publicar_en":95,"updated_at":41,"revisado_en":28,"revisado_iso":42},25,"Software de gestión en la nube o en tu servidor: qué cambia de verdad","software-de-gestion-en-la-nube-o-en-tu-servidor","La pregunta ya no es si mover el programa de gestión a internet: casi todo está ahí. La útil es otra, y casi nadie la hace a tiempo: quién administra el sistema y dónde viven tus datos.","\u003Cp class=\"nota-servicio\">Este artículo compara las dos formas de tener el software de tu empresa y qué cambia en cada una. Si quieres saltar directamente al servicio, lo que hacemos es \u003Ca href=\"\u002Fsoftware-de-gestion-a-medida\">software de gestión a medida\u003C\u002Fa>.\u003C\u002Fp>\n\n\u003Cp>Hace diez años la pregunta era si mover el programa de gestión a internet. Hoy ya no: casi todo está ahí. La pregunta útil es otra, y casi nadie la hace a tiempo: \u003Cstrong>quién administra el sistema y dónde viven tus datos.\u003C\u002Fstrong>\u003C\u002Fp>\n\n\u003Cp>De la respuesta dependen el coste a cinco años, qué pasa si el proveedor cierra y si puedes cambiar de opinión más adelante.\u003C\u002Fp>\n\n\u003Ch2>«En la nube» significa tres cosas distintas\u003C\u002Fh2>\n\n\u003Cp>Y conviene distinguirlas, porque quien te lo vende no siempre lo hace:\u003C\u002Fp>\n\n\u003Col>\n\u003Cli>\u003Cstrong>Un programa por suscripción, compartido.\u003C\u002Fstrong> El proveedor tiene un único software y lo usan miles de empresas, cada una con sus datos separados. Pagas por usuario y mes. Ni ves el servidor ni te afecta.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Tu software, en un servidor de alquiler.\u003C\u002Fstrong> El programa es tuyo o está hecho para ti, pero corre en la infraestructura de otro. Tú decides qué hace; el proveedor pone la máquina.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Tu software, en tu servidor.\u003C\u002Fstrong> En tus oficinas o en un centro de datos contratado a tu nombre. Todo bajo tu control y toda la responsabilidad también.\u003C\u002Fli>\n\u003C\u002Fol>\n\n\u003Cp>La conversación de «nube sí o nube no» mezcla las tres. Las decisiones importantes están entre la primera y las otras dos.\u003C\u002Fp>\n\n\u003Ch2>Lo que se gana\u003C\u002Fh2>\n\n\u003Cul>\n\u003Cli>\u003Cstrong>Se entra desde cualquier sitio\u003C\u002Fstrong>, con un navegador. Suena obvio hasta que alguien tiene que consultar un pedido desde casa de un cliente.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Nadie instala nada.\u003C\u002Fstrong> Ni versiones distintas en cada ordenador, ni la tarde perdida cuando entra un empleado nuevo.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Las actualizaciones se hacen una vez\u003C\u002Fstrong>, en el servidor, y todo el mundo trabaja ya con la versión nueva.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>No hay que comprar máquinas.\u003C\u002Fstrong> El gasto pasa de ser una inversión inicial a una cuota, que para muchas empresas es más fácil de asumir.\u003C\u002Fli>\n\u003C\u002Ful>\n\n\u003Ch2>Con qué hay que contar\u003C\u002Fh2>\n\n\u003Cp>Esta es la parte que suele faltar en la presentación comercial:\u003C\u002Fp>\n\n\u003Cul>\n\u003Cli>\u003Cstrong>Sin conexión no hay trabajo.\u003C\u002Fstrong> Si tu actividad no puede pararse una tarde, la línea de internet deja de ser un gasto de oficina y pasa a ser infraestructura crítica: conviene tener una segunda.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>La cuota no termina nunca.\u003C\u002Fstrong> Una suscripción por usuario y mes parece barata el primer año. Multiplícala por el número de personas que la usarán dentro de cinco y compárala con lo que costaría desarrollar lo que necesitas de verdad. A veces sale a favor de la suscripción, y a veces no, pero la cuenta hay que hacerla.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>El programa cambia sin pedirte permiso.\u003C\u002Fstrong> Con un producto compartido, el proveedor decide qué se añade y qué se retira. Si un día quita la función sobre la que gira tu proceso, no hay a quién recurrir.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Y puede desaparecer.\u003C\u002Fstrong> Los productos se descontinúan y las empresas se venden. Merece la pena preguntarse qué pasaría con tus datos.\u003C\u002Fli>\n\u003C\u002Ful>\n\n\u003Ch2>La pregunta que decide: ¿puedes llevarte tus datos?\u003C\u002Fh2>\n\n\u003Cp>Si te quedas con una sola de este artículo, que sea esta. Antes de firmar nada, pregunta —y pide que te lo pongan por escrito—:\u003C\u002Fp>\n\n\u003Cul>\n\u003Cli>¿Puedo exportar \u003Cstrong>todos\u003C\u002Fstrong> mis datos, no solo unos listados, en un formato estándar?\u003C\u002Fli>\n\u003Cli>¿Puedo hacerlo yo, cuando quiera, sin pedir permiso ni pagar aparte?\u003C\u002Fli>\n\u003Cli>Si dejo de pagar, ¿cuánto tiempo tengo para sacarlos antes de que se borren?\u003C\u002Fli>\n\u003Cli>¿Incluye el histórico o solo el ejercicio en curso?\u003C\u002Fli>\n\u003C\u002Ful>\n\n\u003Cp>Un proveedor serio responde a las cuatro sin incomodarse. Si la respuesta se enreda, ya sabes cuál es: \u003Cstrong>una salida difícil no es un detalle del contrato, es el contrato.\u003C\u002Fstrong>\u003C\u002Fp>\n\n\u003Ch2>Dónde están los servidores, y por qué importa\u003C\u002Fh2>\n\n\u003Cp>Si en tu sistema hay datos personales —clientes, empleados, proveedores— el RGPD te hace responsable a ti de cómo se tratan, aunque el servidor sea de otro. Eso significa saber en qué país están alojados, tener firmado el contrato de encargado de tratamiento con el proveedor y poder demostrarlo si alguien pregunta.\u003C\u002Fp>\n\n\u003Cp>No es un impedimento para usar servicios de fuera, pero sí algo que hay que tener resuelto y documentado antes, no el día de la inspección.\u003C\u002Fp>\n\n\u003Cp>Es también el motivo por el que, cuando entra \u003Ca href=\"\u002Finteligencia-artificial-para-empresas\">inteligencia artificial\u003C\u002Fa> en la ecuación, tiene sentido plantearse modelos que corran en tu propia infraestructura: la información con la que trabajan no llega a salir.\u003C\u002Fp>\n\n\u003Cfigure>\n\u003Cimg src=\"\u002Fstorage\u002Fimagen\u002Fnube-o-servidor-discos.webp\" alt=\"Bahías de disco de un servidor con los indicadores en verde\" width=\"1600\" height=\"1060\" loading=\"lazy\" decoding=\"async\" \u002F>\n\u003Cfigcaption>Servidor propio: todo el control y también toda la responsabilidad.\u003C\u002Ffigcaption>\n\u003C\u002Ffigure>\n\n\u003Ch2>Cuándo encaja cada opción\u003C\u002Fh2>\n\n\u003Cp>\u003Cstrong>Un producto por suscripción\u003C\u002Fstrong> encaja cuando tu proceso se parece al de las demás empresas de tu sector, cuando quieres empezar la semana que viene y cuando prefieres no tener que pensar en servidores. Facturación, nóminas o correo entran casi siempre aquí, y desarrollarlos a medida raramente compensa.\u003C\u002Fp>\n\n\u003Cp>\u003Cstrong>Software propio, en servidor de alquiler\u003C\u002Fstrong> encaja cuando tu proceso \u003Cem>no\u003C\u002Fem> cabe en ningún programa estándar y ya lo has comprobado peleándote con uno. Es la opción más habitual en los proyectos que hacemos: tú decides lo que hace el sistema y no cargas con el mantenimiento del hierro.\u003C\u002Fp>\n\n\u003Cp>\u003Cstrong>Software propio, en servidor propio\u003C\u002Fstrong> encaja cuando hay un requisito que lo obliga: datos que no pueden salir de tus instalaciones, una integración con maquinaria de fábrica, o un cliente que lo exige por contrato.\u003C\u002Fp>\n\n\u003Ch2>Casi siempre acaba siendo mixto\u003C\u002Fh2>\n\n\u003Cp>En la práctica, lo normal no es elegir una y descartar las otras. Una empresa acaba con la contabilidad en un producto de suscripción, su plataforma propia en un servidor de alquiler y algún sistema concreto dentro de casa.\u003C\u002Fp>\n\n\u003Cp>Eso está bien, y solo tiene un requisito: \u003Cstrong>que las piezas se hablen.\u003C\u002Fstrong> El problema de verdad no suele ser dónde está cada sistema, sino que el mismo dato se teclee tres veces porque nadie los conectó. Ahí es donde entran los \u003Ca href=\"\u002Fdesarrollo-de-modulos-y-conectores\">conectores entre sistemas\u003C\u002Fa>.\u003C\u002Fp>\n\n\u003Ch2>Por dónde empezar\u003C\u002Fh2>\n\n\u003Cp>Antes de mirar producto alguno, escribe en un folio qué pasos da hoy la información en tu empresa, desde que entra un pedido hasta que se cobra. Casi siempre aparecen dos o tres saltos que se hacen a mano y que nadie había contado.\u003C\u002Fp>\n\n\u003Cp>Esa lista vale más que cualquier demostración comercial, porque es la que dice si lo tuyo cabe en un programa estándar o no. Si quieres, \u003Ca href=\"\u002Fcontacto\">cuéntanos qué te sale\u003C\u002Fa> y te decimos por dónde se empieza. Cuando lo cubre algo del mercado más barato que un desarrollo, lo decimos también.\u003C\u002Fp>\n\n\u003Cp class=\"revision\">\u003Cem>Publicado en enero de 2016. Revisado y reescrito en agosto de 2026.\u003C\u002Fem>\u003C\u002Fp>","Las tres formas de tener el software de tu empresa, qué se gana y qué se pierde con cada una, y la pregunta que decide: si puedes llevarte tus datos.",284,{"id":12,"nombre":15,"slug":16,"pagina":17,"creado_en":18,"actualizado_en":18},{"id":85,"url":88,"alt":89,"title":90,"parent_type":22,"parent_id":79},"https:\u002F\u002Fairearte.es\u002Fstorage\u002Fimagen\u002Fnube-o-servidor-diagrama.webp","Esquema de un puesto de trabajo conectado a unos servidores alojados en la nube","Software de gestión en la nube o en tu servidor",[92],{"id":35,"etiqueta":36,"slug":37,"creado_en":18,"actualizado_en":18},"23-01-2016","2016-01-23T12:07:22+00:00","2016-01-23"]