Error fatal en Elementor: Clase 'Elementor\Widget_Base' no encontrada
Estoy intentando crear un widget básico en Elementor. Al seguir la documentación para desarrolladores para crear un nuevo widget, aparece el siguiente error:
Fatal error: Class 'Elementor\Widget_Base' not found
Aquí está mi código (mayormente copiado de la documentación oficial)
Clase principal de la extensión del plugin:
<?php
/**
* Plugin Name: Deo Elementor Extension
* Description: Extensión personalizada para Elementor.
* Plugin URI: https://elementor.com/
* Version: 1.0.0
* Author: DeoThemes
* Author URI: https://elementor.com/
* Text Domain: deo-elementor-extension
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Salir si se accede directamente
}
/**
* Clase principal de la extensión de prueba de Elementor
*
* La clase principal que inicia y ejecuta el plugin.
*
* @since 1.0.0
*/
final class Elementor_Test_Extension {
/**
* Versión del plugin
*
* @since 1.0.0
*
* @var string La versión del plugin.
*/
const VERSION = '1.0.0';
/**
* Versión mínima de Elementor requerida
*
* @since 1.0.0
*
* @var string Versión mínima de Elementor necesaria para ejecutar el plugin.
*/
const MINIMUM_ELEMENTOR_VERSION = '2.0.0';
/**
* Versión mínima de PHP requerida
*
* @since 1.0.0
*
* @var string Versión mínima de PHP necesaria para ejecutar el plugin.
*/
const MINIMUM_PHP_VERSION = '7.0';
/**
* Instancia
*
* @since 1.0.0
*
* @access private
* @static
*
* @var Elementor_Test_Extension La única instancia de la clase.
*/
private static $_instance = null;
/**
* Obtener instancia
*
* Asegura que solo una instancia de la clase sea cargada o pueda ser cargada.
*
* @since 1.0.0
*
* @access public
* @static
*
* @return Elementor_Test_Extension Una instancia de la clase.
*/
public static function instance() {
if ( is_null( self::$_instance ) ) {
self::$_instance = new self();
}
return self::$_instance;
}
/**
* Constructor
*
* @since 1.0.0
*
* @access public
*/
public function __construct() {
add_action( 'init', [ $this, 'i18n' ] );
add_action( 'plugins_loaded', [ $this, 'init' ] );
}
/**
* Cargar textos traducidos
*
* Carga los archivos de localización del plugin.
*
* Se ejecuta mediante el hook 'init'.
*
* @since 1.0.0
*
* @access public
*/
public function i18n() {
load_plugin_textdomain( 'elementor-test-extension' );
}
/**
* Inicializar el plugin
*
* Carga el plugin solo después de que Elementor (y otros plugins) estén cargados.
* Comprueba los requisitos básicos del plugin, si falla alguna comprobación no continúa,
* si todas las comprobaciones pasan, carga los archivos necesarios para ejecutar el plugin.
*
* Se ejecuta mediante el hook 'plugins_loaded'.
*
* @since 1.0.0
*
* @access public
*/
public function init() {
// Comprobar si Elementor está instalado y activado
if ( ! did_action( 'elementor/loaded' ) ) {
add_action( 'admin_notices', [ $this, 'admin_notice_missing_main_plugin' ] );
return;
}
// Comprobar versión requerida de Elementor
if ( ! version_compare( ELEMENTOR_VERSION, self::MINIMUM_ELEMENTOR_VERSION, '>=' ) ) {
add_action( 'admin_notices', [ $this, 'admin_notice_minimum_elementor_version' ] );
return;
}
// Comprobar versión requerida de PHP
if ( version_compare( PHP_VERSION, self::MINIMUM_PHP_VERSION, '<' ) ) {
add_action( 'admin_notices', [ $this, 'admin_notice_minimum_php_version' ] );
return;
}
// Incluir archivos del plugin
$this->includes();
// Registrar widgets
add_action( 'elementor/widgets/widgets_registered', [ $this, 'register_widgets' ] );
}
/**
* Notificación de administración
*
* Advertencia cuando el sitio no tiene Elementor instalado o activado.
*
* @since 1.0.0
*
* @access public
*/
public function admin_notice_missing_main_plugin() {
if ( isset( $_GET['activate'] ) ) unset( $_GET['activate'] );
$message = sprintf(
/* translators: 1: Nombre del plugin 2: Elementor */
esc_html__( '"%1$s" requiere que "%2$s" esté instalado y activado.', 'elementor-test-extension' ),
'<strong>' . esc_html__( 'Elementor Test Extension', 'elementor-test-extension' ) . '</strong>',
'<strong>' . esc_html__( 'Elementor', 'elementor-test-extension' ) . '</strong>'
);
printf( '<div class="notice notice-warning is-dismissible"><p>%1$s</p></div>', $message );
}
/**
* Notificación de administración
*
* Advertencia cuando el sitio no tiene la versión mínima requerida de Elementor.
*
* @since 1.0.0
*
* @access public
*/
public function admin_notice_minimum_elementor_version() {
if ( isset( $_GET['activate'] ) ) unset( $_GET['activate'] );
$message = sprintf(
/* translators: 1: Nombre del plugin 2: Elementor 3: Versión requerida de Elementor */
esc_html__( '"%1$s" requiere la versión %3$s o superior de "%2$s".', 'elementor-test-extension' ),
'<strong>' . esc_html__( 'Elementor Test Extension', 'elementor-test-extension' ) . '</strong>',
'<strong>' . esc_html__( 'Elementor', 'elementor-test-extension' ) . '</strong>',
self::MINIMUM_ELEMENTOR_VERSION
);
printf( '<div class="notice notice-warning is-dismissible"><p>%1$s</p></div>', $message );
}
/**
* Notificación de administración
*
* Advertencia cuando el sitio no tiene la versión mínima requerida de PHP.
*
* @since 1.0.0
*
* @access public
*/
public function admin_notice_minimum_php_version() {
if ( isset( $_GET['activate'] ) ) unset( $_GET['activate'] );
$message = sprintf(
/* translators: 1: Nombre del plugin 2: PHP 3: Versión requerida de PHP */
esc_html__( '"%1$s" requiere la versión %3$s o superior de "%2$s".', 'elementor-test-extension' ),
'<strong>' . esc_html__( 'Elementor Test Extension', 'elementor-test-extension' ) . '</strong>',
'<strong>' . esc_html__( 'PHP', 'elementor-test-extension' ) . '</strong>',
self::MINIMUM_PHP_VERSION
);
printf( '<div class="notice notice-warning is-dismissible"><p>%1$s</p></div>', $message );
}
/**
* Incluir archivos
*
* Carga los archivos principales requeridos del plugin.
*
* @since 1.0.0
*
* @access public
*/
public function includes() {
require_once( __DIR__ . '/widgets/test-widget.php' );
}
/**
* Registrar widgets
*
* @since 1.0.0
*
* @access public
*/
public function register_widgets() {
\Elementor\Plugin::instance()->widgets_manager->register_widget_type( new \Elementor_oEmbed_Widget() );
}
}
Elementor_Test_Extension::instance();
Clase del widget de prueba:
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Salir si se accede directamente
}
class Elementor_oEmbed_Widget extends \Elementor\Widget_Base {
/**
* Obtener nombre del widget
*
* Recupera el nombre del widget oEmbed.
*
* @since 1.0.0
* @access public
*
* @return string Nombre del widget.
*/
public function get_name() {
return 'oembed';
}
/**
* Obtener título del widget
*
* Recupera el título del widget oEmbed.
*
* @since 1.0.0
* @access public
*
* @return string Título del widget.
*/
public function get_title() {
return __( 'oEmbed', 'plugin-name' );
}
/**
* Obtener icono del widget
*
* Recupera el icono del widget oEmbed.
*
* @since 1.0.0
* @access public
*
* @return string Icono del widget.
*/
public function get_icon() {
return 'fa fa-code';
}
/**
* Obtener categorías del widget
*
* Recupera la lista de categorías a las que pertenece el widget oEmbed.
*
* @since 1.0.0
* @access public
*
* @return array Categorías del widget.
*/
public function get_categories() {
return [ 'general' ];
}
/**
* Registrar controles del widget oEmbed
*
* Añade diferentes campos de entrada para permitir al usuario cambiar y personalizar los ajustes del widget.
*
* @since 1.0.0
* @access protected
*/
protected function _register_controls() {
$this->start_controls_section(
'content_section',
[
'label' => __( 'Contenido', 'plugin-name' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'url',
[
'label' => __( 'URL para incrustar', 'plugin-name' ),
'type' => \Elementor\Controls_Manager::TEXT,
'input_type' => 'url',
'placeholder' => __( 'https://tu-enlace.com', 'plugin-name' ),
]
);
$this->end_controls_section();
}
/**
* Renderizar la salida del widget oEmbed en el frontend.
*
* Escrito en PHP y usado para generar el HTML final.
*
* @since 1.0.0
* @access protected
*/
protected function render() {
$settings = $this->get_settings_for_display();
$html = wp_oembed_get( $settings['url'] );
echo '<div class="oembed-elementor-widget">';
echo ( $html ) ? $html : $settings['url'];
echo '</div>';
}
}

Tuve el mismo problema. Saca $this->includes(); del método init, y ponlo en el método register_widgets:
public function init() {
...
// Incluir archivos del plugin
// $this->includes(); // <-- elimina esto
}
public function register_widgets() {
$this->includes(); // <- ponlo aquí
\Elementor\Plugin::instance()->widgets_manager->register_widget_type( new \Elementor_oEmbed_Widget() );
}

¡Muchas gracias Frank! Eso es exactamente lo que descubrí ayer. Creé un método separado y puse $this->includes allí y funcionó. Publiqué el problema en el repositorio Github de Elementor. No sé por qué otros votaron negativamente esta publicación, obviamente hay algo mal con el código de la documentación o con el núcleo. Pero el repositorio de Github está deshabilitado ahora debido al DMCA :) De todos modos tu respuesta es correcta.

¿No sería eso editar los archivos principales del tema ReservoirLabs_v2 y por lo tanto resultaría en no poder actualizar el núcleo sin perder los cambios, en el mejor de los casos, y potencialmente romper otras funciones en el peor? Por favor, también intenta incluir una explicación de por qué tu respuesta funciona y qué está intentando lograr.
