Guía Completa para Desarrolladores

Integra tus plugins con nuestro ecosistema de licencias y actualizaciones automáticas.

Sistema de Licencias y Activación

El sistema de licencias te permite proteger tu plugin, asegurando que solo los usuarios con una clave válida puedan acceder a sus funcionalidades completas y recibir soporte o actualizaciones.


Paso 1: Entender el Endpoint de la API

Todas las solicitudes de licencias (activar, desactivar, verificar) se gestionan a través de un único endpoint. Siempre debes enviar los datos vía POST.

https://descargas.smsenlinea.com/api/license.php

Parámetros Requeridos

ParámetroDescripción
actionLa acción a realizar: activate, deactivate o check.
license_keyLa clave de licencia que el usuario introduce.
plugin_slugCrucial: El slug público de tu plugin (el que aparece en la URL del producto).
domainEl dominio del sitio del usuario. En WordPress, se obtiene de forma segura con home_url().

Respuestas de la API

La API siempre devolverá un objeto JSON. Una respuesta exitosa tendrá "success": true. Una fallida tendrá "success": false y un código de error para identificar el problema.

Posibles Códigos de Error:
  • invalid_license_key: La clave no existe.
  • license_plugin_mismatch: La clave es válida, pero para otro plugin.
  • license_not_active: La licencia está inactiva, expirada o deshabilitada por un administrador.
  • license_expired: La fecha de expiración ha pasado.
  • activation_limit_reached: No quedan activaciones disponibles.
  • domain_not_activated: Se intenta hacer un check en un dominio no registrado.

Paso 2: Crear el Gestor de Licencias en tu Plugin

Añade una página de ajustes a tu plugin donde el usuario pueda introducir su licencia. El siguiente código PHP crea una clase completa para gestionar esta página y toda la comunicación con la API, incluyendo los avisos de expiración.

Crea un archivo llamado license-manager.php en tu plugin y pega este código:

<?php
/**
 * Clase para gestionar la licencia y los avisos de expiración.
 */
class My_Plugin_License_Manager {

    private $plugin_slug;
    private $option_group = 'my_plugin_license_options';
    private $page_slug = 'my-plugin-license';
    private $transient_key = 'my_plugin_license_check';

    public function __construct($plugin_slug) {
        $this->plugin_slug = $plugin_slug;
        add_action('admin_menu', [$this, 'add_license_page']);
        add_action('admin_init', [$this, 'register_settings']);
        add_action('admin_notices', [$this, 'show_expiry_notice']);
    }
    
    public function show_expiry_notice() {
        $license_status = get_option('my_plugin_license_status');
        $license_check_data = get_transient($this->transient_key);

        if ($license_status === 'active' && !empty($license_check_data['expiry_notice'])) {
            $message = $license_check_data['expiry_notice'];
            printf('<div class="notice notice-warning is-dismissible"><p>%s</p></div>', $message);
        }
    }

    public function add_license_page() {
        add_options_page('Licencia de Mi Plugin', 'Mi Plugin Premium', 'manage_options', $this->page_slug, [$this, 'render_license_page']);
    }

    public function render_license_page() {
        ?>
        <div class="wrap">
            <h1>Ajustes de Licencia de Mi Plugin Premium</h1>
            <?php settings_errors(); ?>
            <form method="post" action="options.php">
                <?php
                settings_fields($this->option_group);
                do_settings_sections($this->page_slug);
                submit_button('Guardar Cambios');
                ?>
            </form>
        </div>
        <?php
    }

    public function register_settings() {
        register_setting($this->option_group, 'my_plugin_license_key', [$this, 'sanitize_and_validate_license']);
        add_settings_section('my_plugin_license_section', 'Estado de la Activación', [$this, 'render_section_text'], $this->page_slug);
        add_settings_field('my_plugin_license_key_field', 'Clave de Licencia', [$this, 'render_license_key_field'], $this->page_slug, 'my_plugin_license_section');
    }
    
    public function render_section_text() {
        $status = get_option('my_plugin_license_status', 'inactive');
        if ($status === 'active') {
            echo '<p style="color: green; font-weight: bold;">Tu licencia está activa. ¡Gracias por usar nuestro plugin!</p>';
        } else {
            echo '<p style="color: red; font-weight: bold;">Tu licencia está inactiva. Introduce una clave válida para activar las funcionalidades completas, el soporte y las actualizaciones.</p>';
        }
    }

    public function render_license_key_field() {
        $license_key = get_option('my_plugin_license_key', '');
        echo "<input type='text' name='my_plugin_license_key' value='" . esc_attr($license_key) . "' class='regular-text' placeholder='Pega tu clave de licencia aquí' />";
    }

    public function sanitize_and_validate_license($new_key) {
        $old_key = get_option('my_plugin_license_key');
        
        delete_transient($this->transient_key);

        if ($old_key && $new_key !== $old_key) {
            $this->call_api('deactivate', $old_key);
            update_option('my_plugin_license_status', 'inactive');
        }

        if (empty($new_key)) {
            add_settings_error('my_plugin_license_options', 'cleared', 'Ajustes guardados. La licencia ha sido desactivada.', 'updated');
            return '';
        }

        $response = $this->call_api('activate', $new_key);

        if (isset($response['success']) && $response['success']) {
            update_option('my_plugin_license_status', 'active');
            set_transient($this->transient_key, $response, DAY_IN_SECONDS);
            add_settings_error('my_plugin_license_options', 'activated', '¡Licencia activada con éxito!', 'updated');
            return $new_key;
        } else {
            update_option('my_plugin_license_status', 'inactive');
            $error_message = 'Error al activar la licencia. Código: ' . ($response['error'] ?? 'desconocido');
            add_settings_error('my_plugin_license_options', 'error', $error_message, 'error');
            return '';
        }
    }
    
    public function check_license_periodically() {
        if (get_transient($this->transient_key) === false) {
            $license_key = get_option('my_plugin_license_key');
            if ($license_key) {
                $response = $this->call_api('check', $license_key);
                if (isset($response['success']) && $response['success']) {
                    set_transient($this->transient_key, $response, DAY_IN_SECONDS); 
                } else {
                    update_option('my_plugin_license_status', 'inactive');
                }
            }
        }
    }

    private function call_api($action, $license_key) {
        $api_url = 'https://descargas.smsenlinea.com/api/license.php';
        $response = wp_remote_post($api_url, [
            'body' => [ 'action' => $action, 'license_key' => $license_key, 'plugin_slug' => $this->plugin_slug, 'domain' => home_url() ],
            'timeout' => 20, 'sslverify' => true,
        ]);
        if (is_wp_error($response)) { return ['success' => false, 'error' => 'request_failed']; }
        return json_decode(wp_remote_retrieve_body($response), true);
    }
}

Sistema de Actualizaciones Automáticas

Permite a tus usuarios actualizar el plugin con un solo clic desde su panel de WordPress, igual que con los plugins del repositorio oficial. Este sistema es seguro y solo funcionará para usuarios con una licencia activa.


Paso 1: Entender el Endpoint de la API

WordPress buscará actualizaciones enviando una petición POST al siguiente endpoint:

https://descargas.smsenlinea.com/api/update.php

Parámetros Requeridos

ParámetroDescripción
actionPara el chequeo inicial, el valor siempre es plugin_information.
update_identifierCrucial: El "Identificador para Actualizaciones" que definiste en el panel de administración. Este valor es permanente.
versionLa versión actual del plugin instalada en el sitio del usuario.
license_keyLa clave de licencia activa del usuario. Si es inválida, no se proporcionará el enlace de descarga.

Paso 2: Implementar el Código del Actualizador

La siguiente clase se integra con los filtros de WordPress para gestionar el proceso de actualización. Crea un archivo llamado updater.php en tu plugin y pega este código:

<?php
/**
 * Clase para gestionar las actualizaciones automáticas del plugin.
 */
class My_Plugin_Auto_Updater {

    private $api_url;
    private $update_identifier;
    private $plugin_version;
    private $license_key;
    private $plugin_file_basename;

    public function __construct($plugin_file, $update_identifier, $plugin_version, $license_key) {
        $this->api_url = 'https://descargas.smsenlinea.com/api/update.php';
        $this->plugin_file_basename = plugin_basename($plugin_file);
        $this->update_identifier = $update_identifier;
        $this->plugin_version = $plugin_version;
        $this->license_key = $license_key;

        add_filter('pre_set_site_transient_update_plugins', [$this, 'check_for_updates']);
    }

    public function check_for_updates($transient) {
        if (empty($transient->checked)) {
            return $transient;
        }

        $response = $this->call_api('plugin_information');

        if ($response && version_compare($this->plugin_version, $response->new_version, '<')) {
            $transient->response[$this->plugin_file_basename] = $response;
        }

        return $transient;
    }
    
    private function call_api($action) {
        $payload = [
            'body' => [
                'action' => $action,
                'update_identifier' => $this->update_identifier,
                'version' => $this->plugin_version,
                'license_key' => $this->license_key,
            ],
            'timeout' => 20, 'sslverify' => true,
        ];
        
        $request = wp_remote_post($this->api_url, $payload);
        
        if (is_wp_error($request) || wp_remote_retrieve_response_code($request) !== 200) {
            return false;
        }
        
        $response = json_decode(wp_remote_retrieve_body($request));
        
        if (is_object($response) && !empty($response)) {
            $response->plugin = $this->plugin_file_basename;
            return $response;
        }

        return false;
    }
}

Ejemplo de Integración Completa

Este es un ejemplo de cómo deberías estructurar tu archivo principal del plugin para inicializar ambos sistemas: el gestor de licencias y el actualizador automático.

<?php
/**
 * Plugin Name: Mi Plugin Premium
 * Plugin URI:  https://tusitio.com/plugins/mi-plugin-premium
 * Description: Un plugin de ejemplo que integra licencias y actualizaciones.
 * Version:     1.0.0
 * Author:      Tu Nombre
 * Author URI:  https://tusitio.com
 */

// Evitar acceso directo
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

// 1. Define las constantes de tu plugin
define( 'MY_PLUGIN_FILE', __FILE__ );
define( 'MY_PLUGIN_VERSION', '1.0.0' );
define( 'MY_PLUGIN_SLUG', 'mi-plugin-premium' ); // Slug PÚBLICO del plugin
define( 'MY_PLUGIN_UPDATE_ID', 'mi-plugin-premium-stable' ); // Identificador ÚNICO y PERMANENTE para actualizaciones

// 2. Incluye los archivos del gestor de licencia y del actualizador
require_once __DIR__ . '/license-manager.php';
require_once __DIR__ . '/updater.php';

/**
 * Función para inicializar los sistemas del plugin.
 */
function my_plugin_init() {
    // Instanciar el gestor de licencias
    $license_manager = new My_Plugin_License_Manager( MY_PLUGIN_SLUG );

    // OBTENER DATOS DE LICENCIA
    $license_key = get_option('my_plugin_license_key');
    $license_status = get_option('my_plugin_license_status');
    
    // Iniciar el actualizador solo si la licencia está activa
    if ($license_status === 'active' && !empty($license_key)) {
        new My_Plugin_Auto_Updater(
            MY_PLUGIN_FILE,
            MY_PLUGIN_UPDATE_ID,
            MY_PLUGIN_VERSION,
            $license_key
        );
    }
    
    // Ejecutar la verificación periódica de la licencia en el panel de admin
    if (is_admin()) {
        $license_manager->check_license_periodically();
    }
}
add_action('plugins_loaded', 'my_plugin_init');

/**
 * Función de ejemplo para comprobar si la licencia está activa.
 * Puedes usarla para bloquear funcionalidades premium.
 */
function my_plugin_is_license_active() {
    return get_option('my_plugin_license_status') === 'active';
}

// Ejemplo de cómo proteger una funcionalidad:
/*
if ( my_plugin_is_license_active() ) {
    // Cargar aquí las funcionalidades premium
    require_once __DIR__ . '/includes/premium-features.php';
}
*/