Por qué importan los plugins de nopCommerce
nopCommerce da soporte a más de 60.000 tiendas online en todo el mundo. Es la plataforma de comercio electrónico de código abierto líder sobre .NET, y su arquitectura de plugins es el motor que hay detrás de ese ecosistema. Cada integración de pasarela de pago, cada transportista de envíos, cada widget y cada funcionalidad personalizada existe como un plugin.
Si comprendes cómo crear plugins de nopCommerce, puedes ampliar una de las plataformas de comercio electrónico más potentes del mercado, y construir un negocio haciéndolo. Esta guía cubre todo, desde el andamiaje de tu primer plugin hasta los patrones de despliegue en producción.
Llevamos creando plugins de nopCommerce desde 2009, con más de 38 plugins en nuestro catálogo, incluidas 12 integraciones de pasarelas de pago brasileñas y la única solución de pago PIX completa de la plataforma. Esta guía refleja lo que hemos aprendido creando plugins que procesan millones de transacciones.
Arquitectura de plugins: los cimientos
La jerarquía de interfaces de los plugins
Todo plugin de nopCommerce comienza con la interfaz IPlugin en Nop.Services.Plugins. En lugar de obligarte a implementarlo todo desde cero, nopCommerce proporciona BasePlugin, una clase abstracta que se encarga del código repetitivo, y un conjunto de interfaces especializadas para los tipos de plugin más habituales:
| Interfaz | Propósito | Ejemplo |
|---|---|---|
| IPaymentMethod | Procesamiento de pagos (autorizar, capturar, reembolsar, anular) | PayPal, Stripe, PIX, MercadoPago |
| IShippingRateComputationMethod | Calcular tarifas de envío de los transportistas | UPS, FedEx, Correios (Brasil) |
| ITaxProvider | Calcular tipos impositivos por jurisdicción | Avalara, TaxJar |
| IWidgetPlugin | Renderizar widgets de interfaz en zonas concretas | Chat en vivo, ventana emergente de boletín, tarjetas de Trello |
| IExchangeRateProvider | Obtener tipos de cambio de divisas | BCE, Banco Central de Brasil |
| IDiscountRequirementRule | Lógica de descuentos personalizada | "El cliente de Brasil obtiene un 10 % de descuento" |
| IExternalAuthenticationMethod | Inicio de sesión social y SSO | Google, Facebook, Azure AD |
| IMultiFactorAuthenticationMethod | Plugins de MFA (desde la 4.40) | Google Authenticator, OTP por SMS |
| IPickupPointProvider | Puntos de recogida en tienda | Red de tiendas locales, sistemas de taquillas |
| IMiscPlugin | Extensiones de propósito general | Gestión de DNS, analítica, integraciones |
Elige la interfaz más específica para tu caso de uso. IPaymentMethod te ofrece el ciclo de vida completo del pago (ProcessPaymentAsync, PostProcessPaymentAsync, RefundAsync, VoidAsync, CaptureAsync), mientras que IMiscPlugin es la vía de escape para cualquier cosa que no encaje en una categoría estándar.
Estructura del proyecto: paso a paso
1. Crea el proyecto de biblioteca de clases
Crea un nuevo proyecto de tipo Class Library dirigido a .NET 9. La convención de nomenclatura recomendada es Nop.Plugin.{Group}.{Name}:
Nop.Plugin.Payments.PayPalCommerce
Nop.Plugin.Shipping.FedEx
Nop.Plugin.Widgets.WhatsApp
Nop.Plugin.Misc.GoDaddy
Coloca el proyecto en el directorio \Plugins de la raíz de la solución (no dentro de \Nop.Web\Plugins, que es el destino del despliegue). Establece la ruta de salida del .csproj en $(SolutionDir)\Presentation\Nop.Web\Plugins\{PluginOutputDirectory} y activa CopyLocalLockFileAssemblies para asegurarte de que las dependencias de NuGet se copian a la salida.
2. Crea plugin.json
Todo plugin requiere un archivo plugin.json con metadatos:
{
"Group": "Payment methods",
"FriendlyName": "My Payment Gateway",
"SystemName": "Payments.MyGateway",
"Version": "1.00",
"SupportedVersions": [ "4.90" ],
"Author": "SplatDev",
"DisplayOrder": 1,
"FileName": "Nop.Plugin.Payments.MyGateway.dll",
"Description": "Process payments via My Gateway"
}
El SystemName debe coincidir con el nombre de tu ensamblado. SupportedVersions determina qué versiones de nopCommerce pueden instalar el plugin. Si actualizas nopCommerce y un plugin deja de funcionar, revisa este campo primero: muchos plugins solo necesitan que se actualicen sus versiones compatibles.
3. Implementa la clase del plugin
Crea una clase que implemente la interfaz de plugin adecuada y que derive de BasePlugin:
public class MyPaymentProcessor : BasePlugin, IPaymentMethod
{
public override Task InstallAsync()
{
// Insert settings, locale resources, or database tables
return base.InstallAsync();
}
public override Task UninstallAsync()
{
// Clean up settings, locale resources, or database tables
return base.UninstallAsync();
}
public override Task UpdateAsync(string currentVersion, string targetVersion)
{
// Handle version migrations
return base.UpdateAsync(currentVersion, targetVersion);
}
public Task<ProcessPaymentResult> ProcessPaymentAsync(ProcessPaymentRequest request)
{
// Your payment logic here
}
public override string GetConfigurationPageUrl()
{
return _nopUrlHelper.RouteUrl(MyDefaults.Route.Configuration);
}
}
Las sobrescrituras de InstallAsync, UninstallAsync y UpdateAsync son tus enganches del ciclo de vida. Llama siempre a la implementación base: base.InstallAsync() se encarga del registro en el sistema de plugins.
4. Añade la configuración (interfaz de administración)
Para los plugins con ajustes, crea un controlador MVC, un modelo y una vista de Razor:
- Controllers/{Name}Controller.cs: decorado con
[AuthorizeAdmin]y[Area(AreaNames.ADMIN)]. Hereda deBasePluginController. - Models/ConfigurationModel.cs: una clase simple con las propiedades de tus ajustes y atributos
[NopResourceDisplayName]para la localización. - Views/Configure.cshtml: utiliza el diseño
_ConfigurePlugin. Incluye también_ViewImports.cshtml(cópialo de un plugin existente).
Registra la ruta de configuración en un RouteProvider.cs que implemente IRouteProvider:
public class RouteProvider : IRouteProvider
{
public void RegisterRoutes(IEndpointRouteBuilder endpointRouteBuilder)
{
endpointRouteBuilder.MapControllerRoute(
name: MyDefaults.Route.Configuration,
pattern: "Admin/MyGateway/Configure",
defaults: new { controller = "MyGateway", action = "Configure", area = AreaNames.ADMIN });
}
public int Priority => 0;
}
Crear un plugin de pago: el patrón del mundo real
Los plugins de pago son el tipo de plugin más común, y también el más complejo. Este es el patrón de producción que utilizamos en SplatDev:
Componentes principales
- Clase de ajustes: una clase que implementa
ISettingscon propiedades para las claves de API, las URL, los modos (sandbox/producción) y los interruptores de funcionalidades. Guarda los secretos enISettingService: nunca escribas las credenciales directamente en el código. - Clase de valores predeterminados: una clase estática con constantes: nombres de rutas, nombre de sistema, URL de configuración, puntos de conexión de API. Mantiene las cadenas mágicas fuera de tu lógica.
- Clase de servicio: tu lógica de integración real: llamadas HTTP a la pasarela de pago, análisis de respuestas, gestión de webhooks. Inyéctala mediante DI y mantenla comprobable (interfaz + implementación).
- Consumidores de eventos: implementa
IConsumer<OrderPlacedEvent>e interfaces similares para reaccionar a los eventos de la tienda: enviar confirmaciones de transacciones, activar flujos de trabajo posteriores al pago.
Flujo de pago: los métodos que debes implementar
| Método | Cuándo se llama | Qué debe hacer |
|---|---|---|
ProcessPaymentAsync |
El cliente hace clic en "Pagar" | Autorizar o capturar el pago. Devolver éxito/fallo y el ID de la transacción. |
PostProcessPaymentAsync |
Tras completarse el procesamiento del pago | Redirigir a la pasarela externa (PayPal, PagSeguro) o mostrar una página de confirmación. |
RefundAsync |
El administrador inicia un reembolso | Procesar el reembolso a través de la pasarela. Devolver éxito/fallo. |
VoidAsync |
El administrador anula una autorización | Anular la autorización pendiente. Solo aplica si el pago aún no se había capturado. |
CaptureAsync |
El administrador captura un pago autorizado | Capturar un importe previamente autorizado. Habitual en flujos de autorización y posterior captura. |
GetPaymentMethodDescriptionAsync |
Se renderiza la página de pago | Devolver el nombre visible, la descripción y el logotipo del método de pago. |
GetAdditionalHandlingFeeAsync |
Cálculo del total del pedido | Devolver cualquier tarifa adicional que cobre el método de pago, o cero. |
Ejemplo de plugin de pago brasileño: PIX
El sistema de pago instantáneo PIX de Brasil requiere un flujo específico: generar un código QR con una carga útil (cadena EMV), mostrárselo al cliente y esperar una confirmación por webhook cuando se recibe el pago. Este es el patrón:
- ProcessPaymentAsync: llama al PSP (PagSeguro, MercadoPago, etc.) para crear un cobro PIX. Guarda el ID de la transacción (
txid) y la carga útil EMV. - PostProcessPaymentAsync: renderiza el código QR (generado a partir de la carga útil EMV) y el código de "copiar y pegar". Establece el estado del pago en
Pending. - Gestor de webhooks: el PSP envía un webhook cuando PIX confirma el pago. Actualiza el estado del pedido y activa
OrderPaidEvent.
Este es el patrón que hay detrás de los 12 plugins de pago brasileños de SplatDev, que procesan pagos con PIX, boleto y tarjeta de crédito a plazos a través de PagSeguro, MercadoPago, Cielo, Banco Inter, Pagar.me, Rede, GetNet, PicPay, NuPay, Braspag e InfinityPay.
Widgets: añadir interfaz sin tocar los temas
Los plugins de widgets implementan IWidgetPlugin y deben indicar en qué zonas de widget se renderizan:
public Task<IList<string>> GetWidgetZonesAsync()
{
return Task.FromResult<IList<string>>(new List<string>
{
PublicWidgetZones.HomepageBeforeBestSellers,
PublicWidgetZones.ProductDetailsAfterPictures
});
}
Después implementa GetPublicViewComponentAsync para devolver el HTML del widget. El sistema de widgets llama a este método por cada zona que hayas registrado.
Patrones de widget habituales: ventanas emergentes de suscripción a boletines, botones de chat en vivo, sellos de confianza, banners de consentimiento de cookies, botones flotantes de WhatsApp, productos vistos recientemente y notificaciones de prueba social.
Acceso a la base de datos: IRepository<T> y migraciones
nopCommerce utiliza un patrón de repositorio mediante IRepository<T> para el acceso a datos. Para los plugins que necesitan tablas personalizadas:
- Define tu clase de entidad (debe tener una propiedad
Id). - Crea un
ObjectContextque registre tu entidad con Entity Framework Core. - En
InstallAsync, utiliza_dbContext.InstallAsync()para crear las tablas. - En
UninstallAsync, utiliza_dbContext.UninstallAsync()para eliminarlas.
Para las migraciones de esquema entre versiones del plugin, plantéate añadir un MigrationManager a tu sobrescritura de UpdateAsync que compruebe la versión actual del esquema y aplique las sentencias ALTER TABLE necesarias. Esto es más sencillo que FluentMigrator para los plugins y mantiene tu lógica de migración en un único lugar.
Pruebas: trata tu plugin como un producto
En SplatDev tratamos cada plugin como un producto con su propio conjunto de pruebas:
- Pruebas unitarias (xUnit): prueba tu capa de servicio de forma aislada. Simula
ISettingService,IRepository<T>y cualquier cliente HTTP. Tu lógica de pago, los cálculos de impuestos y los cálculos de tarifas de envío deberían tener una cobertura de pruebas unitarias del 100 % sobre la lógica de negocio. - Pruebas de integración: levanta una instancia de prueba de nopCommerce y verifica que tu plugin se instala, se configura y procesa a lo largo de todo el ciclo de vida. Utiliza credenciales de sandbox/prueba para las pasarelas de pago.
- Pruebas de localización: verifica que existen todos los recursos de idioma para cada lengua que declaras admitir. Las cadenas de recursos que faltan son el error más habitual en los plugins.
- Cumplimiento de StyleCop: nopCommerce exige el cumplimiento de StyleCop. Ejecútalo en tu canalización de CI: detecta problemas sutiles antes de la revisión de código.
Errores comunes (y cómo evitarlos)
1. No llamar a base.InstallAsync()
Si sobrescribes InstallAsync sin llamar a la base, tu plugin no se registrará en el sistema de plugins y no aparecerá en la administración. Incluye siempre await base.InstallAsync() al final de tu sobrescritura.
2. Escribir las credenciales directamente en el código
Guarda las claves de API, los tokens y los secretos en ISettingService: nunca los escribas directamente en plugin.json ni como constantes de clase. La página de ajustes debe permitir a los administradores configurar estos valores, y deben persistirse cifrados cuando corresponda.
3. Ignorar la compatibilidad de versiones
Las versiones de nopCommerce rompen los plugins. El campo SupportedVersions de plugin.json no es decorativo: nopCommerce lo comprueba antes de cargar tu plugin. Al actualizar nopCommerce, prueba tu plugin contra la nueva versión y actualiza este campo. No te limites a subir el número sin probar.
4. Bloquear el hilo de la solicitud
Todos los métodos de los plugins son asíncronos por una razón. Si tu procesador de pagos llama a una API externa, esa llamada debe ser asíncrona. Bloquear el hilo con .Result o .Wait() degradará el rendimiento bajo carga y puede provocar bloqueos mutuos (deadlocks).
5. Sin consumidores de eventos
Los plugins que solo ofrecen una página de configuración no captan lo esencial. El verdadero poder de los plugins de nopCommerce proviene de los consumidores de eventos: reaccionar a eventos de la tienda como OrderPlacedEvent, CustomerRegisteredEvent o ShipmentDeliveredEvent. Conecta tu plugin a los eventos de negocio de la tienda, no solo a la interfaz de administración.
nopCommerce 4.90: novedades para los desarrolladores de plugins
nopCommerce 4.90 está dirigido a .NET 9 y aporta varias mejoras para los desarrolladores de plugins:
- Entorno de ejecución de .NET 9: tus plugins se ejecutan sobre el .NET más rápido hasta la fecha, beneficiándose automáticamente de las mejoras del JIT, la adaptación dinámica del GC y las optimizaciones de bucles.
- Compatibilidad con C# 13: utiliza colecciones
params, interfacesref structy propiedades parciales en el código de tu plugin. - Dependencias de NuGet actualizadas: los paquetes subyacentes (Autofac, FluentValidation, etc.) se han actualizado. Prueba el árbol de dependencias de tu plugin.
- IMultiFactorAuthenticationMethod: los plugins de MFA son ahora un concepto de primer nivel con su propia interfaz.
- Plantilla de plugin mejorada: la plantilla oficial de plugin de nopCommerce para Visual Studio se ha actualizado para la 4.90; utilízala como punto de partida.
Cómo seguir a partir de aquí
El desarrollo de plugins para nopCommerce es una habilidad que impulsa una carrera profesional. El marketplace de nopCommerce está activo y en crecimiento, y los plugins bien construidos generan ingresos recurrentes a través de actualizaciones y soporte. En SplatDev los plugins son nuestro negocio principal: nuestra tienda en store.splatdev.com ofrece más de 38 plugins, y llevamos años siendo Gold Solutions Partner.
Si estás creando un proyecto de comercio electrónico sobre nopCommerce, no necesitas construirlo todo desde cero. Nuestro catálogo cubre pagos brasileños, envíos (Correios, JadLog, Braspress), integraciones con ERP y funcionalidad personalizada. Si necesitas algo que no tenemos, también creamos plugins a medida.
¿Listo para crear o ampliar tu tienda de nopCommerce? Nuestro equipo lleva haciéndolo desde 2009, más tiempo que casi cualquier otro en el ecosistema.
Trabaja con nuestro equipo de nopCommerce
O explora nuestro catálogo de plugins: store.splatdev.com