set_basename( true, __FILE__ ); } else { /** * DO NOT REMOVE THIS IF, IT IS ESSENTIAL FOR THE * `function_exists` CALL ABOVE TO PROPERLY WORK. */ if ( ! function_exists( 'cod_fs' ) ) { // Create a helper function for easy SDK access. function cod_fs() { global $cod_fs; if ( ! isset( $cod_fs ) ) { // Include Freemius SDK. require_once dirname( __FILE__ ) . '/vendor/freemius/start.php'; $cod_fs = fs_dynamic_init( array( 'id' => '42199', 'slug' => 'codeselector', 'type' => 'plugin', 'public_key' => 'pk_107b18e4b8173a37a842854d4d5a0', 'is_premium' => false, 'premium_suffix' => 'Pro', 'has_premium_version' => true, 'has_addons' => false, 'has_paid_plans' => true, 'is_org_compliant' => true, 'menu' => array( 'first-path' => 'plugins.php', 'support' => false, ), ) ); } return $cod_fs; } // Init Freemius. cod_fs(); // Signal that SDK was initiated. do_action( 'cod_fs_loaded' ); } /** * Main codeSelector. Plugin Class (Singleton). */ final class CodeSelector_Plugin { /** * Minimum required Elementor version. * * @var string */ const MINIMUM_ELEMENTOR_VERSION = '3.5.0'; /** * Minimum required PHP version. * * @var string */ const MINIMUM_PHP_VERSION = '7.4'; /** * Singleton instance. * * @var CodeSelector_Plugin|null */ private static $instance = null; /** * Get or initialize singleton instance. * * @return CodeSelector_Plugin */ public static function instance() { if ( is_null( self::$instance ) ) { self::$instance = new self(); } return self::$instance; } /** * Private constructor: hooks into init and plugins_loaded. */ private function __construct() { add_action( 'init', array( $this, 'load_textdomain' ), 1 ); add_action( 'plugins_loaded', array( $this, 'init' ) ); } /** * Load plugin translations from /languages directory. * * @return void */ public function load_textdomain() { load_plugin_textdomain( 'codeselector', false, dirname( plugin_basename( CODESELECTOR_FILE ) ) . '/languages' ); } /** * Validate environment compatibility and bootstrap Elementor hooks. * * @return void */ public function init() { // 1. Check if Elementor is active and loaded. if ( ! did_action( 'elementor/loaded' ) ) { add_action( 'admin_notices', array( $this, 'admin_notice_missing_elementor' ) ); return; } // 2. Check minimum Elementor version. if ( defined( 'ELEMENTOR_VERSION' ) && ! version_compare( ELEMENTOR_VERSION, self::MINIMUM_ELEMENTOR_VERSION, '>=' ) ) { add_action( 'admin_notices', array( $this, 'admin_notice_minimum_elementor_version' ) ); return; } // 3. Check minimum PHP version. if ( version_compare( PHP_VERSION, self::MINIMUM_PHP_VERSION, '<' ) ) { add_action( 'admin_notices', array( $this, 'admin_notice_minimum_php_version' ) ); return; } // Load native sanitizer module. require_once CODESELECTOR_PATH . 'includes/class-codeselector-sanitizer.php'; // Register Marketincode category in Elementor panel. add_action( 'elementor/elements/categories_registered', array( $this, 'register_elementor_category' ) ); // Register widget in Elementor (3.5+ / 4.x API). add_action( 'elementor/widgets/register', array( $this, 'register_widgets' ) ); // Enqueue Visual-to-Code Bridge assets strictly inside Elementor editor environment. add_action( 'elementor/editor/after_enqueue_styles', array( $this, 'enqueue_editor_styles' ) ); add_action( 'elementor/editor/after_enqueue_scripts', array( $this, 'enqueue_editor_scripts' ) ); add_action( 'elementor/preview/enqueue_styles', array( $this, 'enqueue_preview_styles' ) ); } /** * Enqueue Elementor side-panel styles. * * @return void */ public function enqueue_editor_styles() { $css_file = CODESELECTOR_PATH . 'assets/css/editor-panel.css'; $ver = CODESELECTOR_VERSION . '.' . ( file_exists( $css_file ) ? filemtime( $css_file ) : '1' ); wp_enqueue_style( 'codeselector-editor-panel', CODESELECTOR_URL . 'assets/css/editor-panel.css', array(), $ver ); } /** * Enqueue Visual-to-Code Bridge script and localized strings in Elementor editor. * * @return void */ public function enqueue_editor_scripts() { if ( function_exists( 'wp_enqueue_media' ) ) { wp_enqueue_media(); } $js_file = CODESELECTOR_PATH . 'assets/js/editor-bridge.js'; $ver = CODESELECTOR_VERSION . '.' . ( file_exists( $js_file ) ? filemtime( $js_file ) : '1' ); wp_enqueue_script( 'codeselector-editor-bridge', CODESELECTOR_URL . 'assets/js/editor-bridge.js', array(), $ver, true ); $i18n_strings = array( 'lineUpper' => esc_html__( 'LINE', 'codeselector' ), 'lineTitle' => esc_html__( 'Line', 'codeselector' ), 'ready' => esc_html__( 'READY', 'codeselector' ), 'wantChangeImg' => esc_html__( '๐ผ๏ธ Want to replace this image?', 'codeselector' ), 'changeBtn' => esc_html__( 'Replace', 'codeselector' ), 'closeBtn' => esc_html__( 'Close', 'codeselector' ), 'closeEsc' => esc_html__( 'Close (Esc)', 'codeselector' ), 'editingImgLive' => esc_html__( '๐ผ๏ธ Editing image live', 'codeselector' ), 'imageWord' => esc_html__( 'Image', 'codeselector' ), 'ofWord' => esc_html__( 'of', 'codeselector' ), 'editWord' => esc_html__( 'Edit', 'codeselector' ), 'openWpMedia' => esc_html__( '๐ Open WordPress Media Library', 'codeselector' ), 'imgUrlLabel' => esc_html__( 'Image URL (src)', 'codeselector' ), 'imgAltLabel' => esc_html__( 'SEO Alt Text (alt)', 'codeselector' ), 'imgAltPlaceholder' => esc_html__( 'Image description...', 'codeselector' ), 'saveToCode' => esc_html__( 'Save to Code', 'codeselector' ), 'imgUpdatedTag' => esc_html__( 'โ Image tag updated', 'codeselector' ), 'imgUpdatedLine' => esc_html__( 'โ Image updated on line', 'codeselector' ), 'imgSaved' => esc_html__( 'โ Image saved', 'codeselector' ), 'wpMediaTitle' => esc_html__( 'codeSelector. โ Select Image', 'codeselector' ), 'wpMediaUseBtn' => esc_html__( 'Use in this block', 'codeselector' ), 'saveBtn' => esc_html__( 'Save', 'codeselector' ), 'editingLivePrefix' => esc_html__( 'โ๏ธ Editing', 'codeselector' ), 'editingLiveWord' => esc_html__( 'live', 'codeselector' ), 'inlineHint' => esc_html__( 'Enter or click outside = Save ยท Esc = Cancel', 'codeselector' ), 'elementSynced' => esc_html__( 'Element synced:', 'codeselector' ), 'updatedTag' => esc_html__( 'updated', 'codeselector' ), 'updatedOnLine' => esc_html__( 'โ Updated on line', 'codeselector' ), 'savedToast' => esc_html__( 'โ Saved', 'codeselector' ), 'editCancelled' => esc_html__( 'Edit cancelled', 'codeselector' ), 'previewArrow' => esc_html__( 'Preview โ', 'codeselector' ), ); wp_add_inline_script( 'codeselector-editor-bridge', 'window.CodeSelectorConfig = ' . wp_json_encode( array( 'version' => CODESELECTOR_VERSION, 'i18n' => $i18n_strings, ) ) . ';', 'before' ); } /** * Enqueue visual feedback styles inside Elementor preview iframe. * * @return void */ public function enqueue_preview_styles() { $css_file = CODESELECTOR_PATH . 'assets/css/preview-bridge.css'; $ver = CODESELECTOR_VERSION . '.' . ( file_exists( $css_file ) ? filemtime( $css_file ) : '1' ); wp_enqueue_style( 'codeselector-preview-bridge', CODESELECTOR_URL . 'assets/css/preview-bridge.css', array(), $ver ); } /** * Register "Marketincode" category in Elementor widget panel. * * @param \Elementor\Elements_Manager $elements_manager Elementor categories manager. * @return void */ public function register_elementor_category( $elements_manager ) { $elements_manager->add_category( 'marketincode', array( 'title' => esc_html__( 'Marketincode', 'codeselector' ), 'icon' => 'eicon-code', ) ); } /** * Load and register codeSelector. widget in Elementor. * * @param \Elementor\Widgets_Manager $widgets_manager Elementor widgets manager. * @return void */ public function register_widgets( $widgets_manager ) { require_once CODESELECTOR_PATH . 'widgets/class-codeselector-widget.php'; $widget = new \CodeSelector_Widget(); if ( method_exists( $widgets_manager, 'register' ) ) { $widgets_manager->register( $widget ); } else { // Backward compatibility fallback for older Elementor versions. $widgets_manager->register_widget_type( $widget ); } } /** * Admin notice when Elementor is not active. * * @return void */ public function admin_notice_missing_elementor() { if ( ! current_user_can( 'activate_plugins' ) ) { return; } $message = sprintf( /* translators: %1$s: Brand name (Marketincode) */ esc_html__( 'codeSelector. (%1$s) requires Elementor to be installed and activated.', 'codeselector' ), esc_html__( 'Marketincode', 'codeselector' ) ); printf( '
%s
%s
%s