load_modules(); $this->register_hooks(); } /** * Load feature modules. */ private function load_modules() { require_once PIXLORA_PATH . 'includes/class-pixlora-kses.php'; require_once PIXLORA_PATH . 'includes/modules/header-footer/class-pixlora-hf-module.php'; require_once PIXLORA_PATH . 'includes/modules/presets/class-pixlora-presets-module.php'; require_once PIXLORA_PATH . 'includes/modules/settings/class-pixlora-settings-module.php'; require_once PIXLORA_PATH . 'includes/modules/ai/class-pixlora-ai-module.php'; ( new Pixlora_HF_Module() )->init(); ( new Pixlora_Presets_Module() )->init(); ( new Pixlora_Settings_Module() )->init(); ( new Pixlora_AI_Module() )->init(); } /** * Register WordPress and Elementor hooks. */ private function register_hooks() { add_action( 'elementor/elements/categories_registered', array( $this, 'register_category' ) ); add_action( 'elementor/widgets/register', array( $this, 'register_widgets' ) ); add_action( 'elementor/frontend/after_enqueue_styles', array( $this, 'enqueue_frontend_styles' ) ); add_action( 'elementor/frontend/after_register_scripts', array( $this, 'register_frontend_scripts' ) ); add_action( 'elementor/frontend/after_register_styles', array( $this, 'register_frontend_styles' ) ); } /** * Register stylesheets used by individual widgets. * * Registering (not enqueuing) lets Elementor load them on demand through * each widget's get_style_depends(). * * @since 1.2.0 */ public function register_frontend_styles() { wp_register_style( 'pixlora-posts', PIXLORA_URL . 'assets/css/posts.css', array(), PIXLORA_VERSION ); wp_register_style( 'pixlora-portfolio', PIXLORA_URL . 'assets/css/portfolio.css', array(), PIXLORA_VERSION ); wp_register_style( 'pixlora-slider', PIXLORA_URL . 'assets/css/slider.css', array(), PIXLORA_VERSION ); } /** * Register scripts used by widgets. * * Registering (not enqueuing) lets Elementor load them on demand through * each widget's get_script_depends(). */ public function register_frontend_scripts() { wp_register_script( 'pixlora-nav', PIXLORA_URL . 'assets/js/nav.js', array(), PIXLORA_VERSION, true ); wp_register_script( 'pixlora-portfolio', PIXLORA_URL . 'assets/js/portfolio.js', array(), PIXLORA_VERSION, true ); wp_register_script( 'pixlora-slider', PIXLORA_URL . 'assets/js/slider.js', array(), PIXLORA_VERSION, true ); } /** * Add a dedicated widget category in the Elementor panel. * * @param \Elementor\Elements_Manager $elements_manager Elementor elements manager. */ public function register_category( $elements_manager ) { $elements_manager->add_category( 'pixlora-elements', array( 'title' => esc_html__( 'Pixlora Elements', 'pixlora-elements' ), 'icon' => 'fa fa-plug', ) ); $this->promote_category( $elements_manager ); } /** * Move the Pixlora category near the top of the widget panel. * * Elementor appends new categories to the end of an ordered array and * offers no filter for their position, so the private property is * reordered directly. Every step is guarded: if Elementor changes its * internals the category simply stays where it was. * * @param \Elementor\Elements_Manager $elements_manager Elementor elements manager. */ private function promote_category( $elements_manager ) { /** * Filter the categories our category should be placed after. * * The first one present in the panel wins. * * @param array $after_candidates Ordered list of category slugs. */ $after_candidates = apply_filters( 'pixlora_category_after', array( 'favorites', 'basic', 'layout' ) ); try { $property = new \ReflectionProperty( get_class( $elements_manager ), 'categories' ); } catch ( \ReflectionException $e ) { return; } $property->setAccessible( true ); $categories = $property->getValue( $elements_manager ); if ( ! is_array( $categories ) || ! isset( $categories['pixlora-elements'] ) ) { return; } $after = ''; foreach ( $after_candidates as $candidate ) { if ( isset( $categories[ $candidate ] ) ) { $after = $candidate; break; } } $category = $categories['pixlora-elements']; unset( $categories['pixlora-elements'] ); if ( $after ) { $position = array_search( $after, array_keys( $categories ), true ) + 1; } else { // No anchor found: fall back to the very top of the panel. $position = 0; } $categories = array_merge( array_slice( $categories, 0, $position, true ), array( 'pixlora-elements' => $category ), array_slice( $categories, $position, null, true ) ); $property->setValue( $elements_manager, $categories ); } /** * Register the plugin widgets. * * @param \Elementor\Widgets_Manager $widgets_manager Elementor widgets manager. */ public function register_widgets( $widgets_manager ) { require_once PIXLORA_PATH . 'includes/widgets/class-pixlora-widget-base.php'; $widgets = array( 'class-pixlora-site-logo-widget.php' => 'Pixlora_Site_Logo_Widget', 'class-pixlora-nav-menu-widget.php' => 'Pixlora_Nav_Menu_Widget', 'class-pixlora-social-icons-widget.php' => 'Pixlora_Social_Icons_Widget', 'class-pixlora-copyright-widget.php' => 'Pixlora_Copyright_Widget', 'class-pixlora-button-widget.php' => 'Pixlora_Button_Widget', 'class-pixlora-link-list-widget.php' => 'Pixlora_Link_List_Widget', 'class-pixlora-posts-widget.php' => 'Pixlora_Posts_Widget', 'class-pixlora-portfolio-widget.php' => 'Pixlora_Portfolio_Widget', 'class-pixlora-slider-widget.php' => 'Pixlora_Slider_Widget', // Theme builder widgets: these read from the current query. 'class-pixlora-post-title-widget.php' => 'Pixlora_Post_Title_Widget', 'class-pixlora-post-content-widget.php' => 'Pixlora_Post_Content_Widget', 'class-pixlora-post-excerpt-widget.php' => 'Pixlora_Post_Excerpt_Widget', 'class-pixlora-featured-image-widget.php' => 'Pixlora_Featured_Image_Widget', 'class-pixlora-post-meta-widget.php' => 'Pixlora_Post_Meta_Widget', 'class-pixlora-post-comments-widget.php' => 'Pixlora_Post_Comments_Widget', 'class-pixlora-archive-title-widget.php' => 'Pixlora_Archive_Title_Widget', 'class-pixlora-archive-posts-widget.php' => 'Pixlora_Archive_Posts_Widget', 'class-pixlora-search-form-widget.php' => 'Pixlora_Search_Form_Widget', ); foreach ( $widgets as $file => $class ) { require_once PIXLORA_PATH . 'includes/widgets/' . $file; if ( class_exists( $class ) ) { $widgets_manager->register( new $class() ); } } } /** * Enqueue frontend styles. */ public function enqueue_frontend_styles() { $style_path = PIXLORA_PATH . 'assets/css/frontend.css'; if ( ! file_exists( $style_path ) ) { return; } wp_enqueue_style( 'pixlora-frontend', PIXLORA_URL . 'assets/css/frontend.css', array(), PIXLORA_VERSION ); } /** * Prevent cloning. */ private function __clone() {} /** * Prevent unserializing. */ public function __wakeup() { throw new \Exception( 'Cannot unserialize a singleton.' ); } }