<?php
/**
 * Plugin Name: OrokuBlocks for Elementor
 * Plugin URI: https://orokublocks.com/plugin
 * Description: Incredible widgets for WordPress and Elementor.
 * Version: 1.1.1
 * Requires at least: 6.9
 * Requires PHP: 7.4
 * Author: OrokuBlocks
 * Author URI: https://orokublocks.com/
 * License: GPLv3
 * License URI: http://www.gnu.org/licenses/gpl-3.0.html
 * Text Domain: orokublocks
 * Domain Path: /languages
 * Requires Plugins: elementor
 */

// Exit if accessed directly
if ( ! defined( 'ABSPATH' ) ) {
  exit;
}

if ( ! function_exists( 'orokublocks_fs' ) ) {
  // Create a helper function for easy SDK access.
  function orokublocks_fs() {
      global $orokublocks_fs;

      if ( ! isset( $orokublocks_fs ) ) {
          // Include Freemius SDK.
          require_once dirname( __FILE__ ) . '/vendor/freemius/start.php';

          $orokublocks_fs = fs_dynamic_init( array(
              'id'                  => '29122',
              'slug'                => 'orokublocks',
              'premium_slug'        => 'orokublocks-pro',
              'type'                => 'plugin',
              'public_key'          => 'pk_83d4319abdb797adb9be54503d806',
              'is_premium'          => false,
              'premium_suffix'      => '(Pro)',
              'has_premium_version' => true,
              'has_addons'          => false,
              'has_paid_plans'      => true,
              'is_org_compliant'    => true,
              'has_affiliation'     => 'selected',
              'menu'                => array(
                'slug'           => 'orokublocks',
                'override_exact' => true,
                'contact'        => false,
                'support'        => false,
                'affiliation'    => false,
                'parent'         => array(
                  'slug' => 'orokublocks',
                )
              )
          ) );
      }

      return $orokublocks_fs;
  }

  // Init Freemius.
  orokublocks_fs();
  // Signal that SDK was initiated.
  do_action( 'orokublocks_fs_loaded' );

  function orokublocks_fs_settings_url() {
    return admin_url( 'admin.php?page=orokublocks#tab=general' );
  }

  orokublocks_fs()->add_filter('connect_url', 'orokublocks_fs_settings_url');
  orokublocks_fs()->add_filter('after_skip_url', 'orokublocks_fs_settings_url');
  orokublocks_fs()->add_filter('after_connect_url', 'orokublocks_fs_settings_url');
  orokublocks_fs()->add_filter('after_pending_connect_url', 'orokublocks_fs_settings_url');

  function orokublocks_fs_custom_icon() {
    return dirname( __FILE__ ) . '/admin/assets/image/logo.png';
  }

  orokublocks_fs()->add_filter( 'plugin_icon', 'orokublocks_fs_custom_icon' );

  function orokublocks_fs_custom_connect_message_on_update( $message, $user_first_name, $product_title, $user_login, $site_link, $freemius_link ) {
    return sprintf(
      /* translators: 1: br tags, 2: opening strong tag, 3: closing strong tag, 4: opening strong tag, 5: closing strong tag, 6: opening strong tag, 7: closing strong tag. */
      esc_html__( 'Opt-in so you never miss an important update and help us make the plugin more compatible with your site and better at doing what you need it to.%1$sBy selecting %2$sAllow & Continue%3$s you will also gain access to the %4$sAccount%5$s and %6$sUpgrade%7$s menus, which will allow you to upgrade the plugin in the future if you wish to do so.', 'orokublocks' ),
      '<br><br>',
      '<strong>',
      '</strong>',
      '<strong>',
      '</strong>',
      '<strong>',
      '</strong>'
    );
  }

  orokublocks_fs()->add_filter( 'connect_message', 'orokublocks_fs_custom_connect_message_on_update', 10, 6 );
  orokublocks_fs()->add_filter( 'connect_message_on_update', 'orokublocks_fs_custom_connect_message_on_update', 10, 6 );
}

if ( orokublocks_fs()->is_registered() ) {
  add_action( 'orokublocks_admin_menu_after_submenu_items', function () {
  ?>
    <li class="oroku-menu__item">
      <a class="oroku-menu__link" href="<?php echo esc_url( admin_url( 'admin.php?page=orokublocks-account' ) ); ?>">
        <?php esc_html_e( 'Account', 'orokublocks' ); ?>
      </a>
    </li>
  <?php
  });
}

final class OrokuBlocks {
  /**
   * @var string Current version
   */
  public $version = '';

  /**
   * @var string Plugin name
   */
  public $name = '';
  
  /**
   * @var string Pathname of the current file
   * 
   * @access private
   */
  private $file = '';

  /**
   * @var string Plugin folder path
   */
  public $path = '';

  /**
   * @var string Plugin folder url
   */
  public $url = '';

  /**
   * @var array Supported plugin integrations
   * 
   * @access private
   */
  private $plugins = [];

  /**
   * @var array Widget categories by id
   */
  public $categories = [];

  /**
   * @var array Widget tags by id
   */
  public $tags = [];

  /**
   * @var array Widgets by id
   */
  public $widgets = [];

  /**
   * @var OrokuBlocks_Admin Singleton instance
   */
  public $admin = null;

  /**
   * @var OrokuBlocks_Settings Singleton instance
   */
  public $settings = null;

  /**
   * Prevent more than one instance from being created
   * 
   * @since 1.0.0
   * 
   * @access private
   */
  private function __construct() {}

  /**
   * Prevent cloning
   * 
   * @since 1.0.0
   * 
   * @access private
   */
  private function __clone() {}

  /**
   * Returns the OrokuBlocks class instance
   * 
   * @since 1.0.0
   * 
   * @return OrokuBlocks $instance  OrokuBlocks class instance
   */
  public static function getInstance() {
    static $instance = null;

    if ( $instance === null ) {
      $instance = new OrokuBlocks();

      // setup
      $instance->initialize();
      $instance->includeFiles();
      $instance->addActions();
    }

    return $instance;
  }

  /**
   * Initialize property values
   * 
   * @since 1.0.0
   * 
   * @access private
   */
  private function initialize() {
    $this->version = '1.1.0';
    $this->name = 'OrokuBlocks';
    $this->file = __FILE__;
    $this->path = plugin_dir_path( $this->file );
    $this->url = plugin_dir_url( $this->file );
    $this->plugins = [
      'gamipress',
      'sportspress',
      'woocommerce'
    ];
  }

  /**
   * Include files
   * 
   * @since 1.0.0
   * 
   * @access private
   */
  private function includeFiles() {
    /**
     * Load router.
     * 
     * @since 1.0.0
     */
    require_once $this->path . '/includes/classes/class-orokublocks-router.php';

    /**
     * Load settings functionality.
     * 
     * @since 1.0.0
     */
    require_once $this->path . '/admin/includes/classes/class-orokublocks-settings.php';

    /**
     * Load admin related functionality
     * only when on the WordPress admin.
     */
    if ( is_admin() ) {
      /**
       * Load admin functionality.
       * 
       * @since 1.0.0
       */
      require_once $this->path . '/admin/includes/classes/class-orokublocks-admin.php';
    }

    /**
     * Load WordPress integrations.
     * 
     * @since 1.0.0
     */
    require_once $this->path . '/includes/classes/class-orokublocks-blog.php';

    /**
     * Load plugin integrations.
     * 
     * @since 1.0.0
     */
    foreach ( $this->plugins as $plugin ) {
      // load the plugin integration file only if the plugin is active
      if ( $this->pluginIsActive( $plugin ) ) {
        require_once $this->path . '/includes/classes/plugins/class-orokublocks-' . $plugin . '.php';
      }
    }

    if ( $this->pluginIsActive( 'elementor' ) ) {
      /**
       * Load widgets functionality.
       * 
       * @since 1.0.0
       */
      require_once $this->path . '/includes/classes/class-orokublocks-widget.php';
    }
  }

  /**
   * Setup variables
   * 
   * @since 1.0.0
   */
  public function setup() {
    $this->categories = [
      'general' => [
        'id'    => 'general',
        'name'  => __( 'General', 'orokublocks' ),
        'theme' => 'secondary'
      ],
      'gamipress' => [
        'id'      => 'gamipress',
        'name'  => __( 'GamiPress', 'orokublocks' ),
        'plugin'  => 'gamipress'
      ],
      'sportspress' => [
        'id'      => 'sportspress',
        'name'  => __( 'SportsPress', 'orokublocks' ),
        'plugin'  => 'sportspress'
      ],
      'woocommerce' => [
        'id'      => 'woocommerce',
        'name'  => __( 'WooCommerce', 'orokublocks' ),
        'plugin'  => 'woocommerce'
      ]
    ];

    $this->tags = [
      'freemium'  => [
        'id'    => 'freemium',
        'name'  => 'Freemium',
        'theme' => 'positive'
      ],
      'pro'       => [
        'id'    => 'pro',
        'name'  => 'Pro',
        'theme' => 'highlight'
      ]
    ];

    $this->widgets = [
      /**
       * General
       */
      'scoring_rating'              => [
        'id'          => 'scoring_rating',
        'name'        => __( 'Scoring Rating', 'orokublocks' ),
        'categories'  => [ 'general' ],
        'tags'        => [ 'freemium' ],
        'urls'        => [
          'documentation' => 'https://orokublocks.com/documentation/scoring-rating',
          'demo'          => 'https://orokublocks.com/widgets/scoring-rating'
        ],
        'versions'  => [
          'v1'  => [
            'pro' => false
          ],
          'v2'  => [
            'pro' => false
          ],
          'v3'  => [
            'pro' => true
          ],
          'v4'  => [
            'pro' => true
          ]
        ]
      ],
      'item_review'                 => [
        'id'          => 'item_review',
        'name'        => __( 'Item Review', 'orokublocks' ),
        'categories'  => [ 'general' ],
        'tags'        => [ 'freemium' ],
        'urls'        => [
          'documentation' => 'https://orokublocks.com/documentation/item-review',
          'demo'          => 'https://orokublocks.com/widgets/item-review'
        ],
        'versions'  => [
          'v1'  => [
            'pro' => false
          ],
          'v2'  => [
            'pro' => false
          ],
          'v3'  => [
            'pro' => true
          ],
          'v4'  => [
            'pro' => true
          ],
          'v5'  => [
            'pro' => true
          ]
        ]
      ],
      'affiliate_referral'          => [
        'id'          => 'affiliate_referral',
        'name'        => __( 'Affiliate and Referral', 'orokublocks' ),
        'categories'  => [ 'general' ],
        'tags'        => [ 'freemium' ],
        'urls'        => [
          'documentation' => 'https://orokublocks.com/documentation/affiliate-referral',
          'demo'          => 'https://orokublocks.com/widgets/affiliate-referral'
        ],
        'versions'  => [
          'v1'  => [
            'pro' => false
          ],
          'v2'  => [
            'pro' => false
          ],
          'v3'  => [
            'pro' => true
          ],
          'v4'  => [
            'pro' => true
          ]
        ]
      ],
      'promo_discount'              => [
        'id'          => 'promo_discount',
        'name'        => __( 'Promo and Discount', 'orokublocks' ),
        'categories'  => [ 'general' ],
        'tags'        => [ 'freemium' ],
        'urls'        => [
          'documentation' => 'https://orokublocks.com/documentation/promo-discount',
          'demo'          => 'https://orokublocks.com/widgets/promo-discount'
        ],
        'versions'  => [
          'v1'  => [
            'pro' => false
          ],
          'v2'  => [
            'pro' => false
          ],
          'v3'  => [
            'pro' => true
          ],
          'v4'  => [
            'pro' => true
          ]
        ]
      ],
      'testimonial_recommendation'  => [
        'id'          => 'testimonial_recommendation',
        'name'        => __( 'Testimonial and Recommendation', 'orokublocks' ),
        'categories'  => [ 'general' ],
        'tags'        => [ 'freemium' ],
        'urls'        => [
          'documentation' => 'https://orokublocks.com/documentation/testimonial-recommendation',
          'demo'          => 'https://orokublocks.com/widgets/testimonial-recommendation'
        ],
        'versions'  => [
          'v1'  => [
            'pro' => false
          ],
          'v2'  => [
            'pro' => false
          ],
          'v3'  => [
            'pro' => true
          ],
          'v4'  => [
            'pro' => true
          ]
        ]
      ],
      /**
       * GamiPress
       */
      'gamipress_achievement' => [
        'id'          => 'gamipress_achievement',
        'name'        => __( 'Achievement', 'orokublocks' ),
        'plugin'      => 'gamipress',
        'categories'  => [ 'gamipress' ],
        'tags'        => [ 'freemium' ],
        'urls'        => [
          'documentation' => 'https://orokublocks.com/documentation/achievement',
          'demo'          => 'https://orokublocks.com/widgets/achievement'
        ],
        'versions'  => [
          'v1'  => [
            'pro' => false
          ],
          'v2'  => [
            'pro' => true
          ],
          'v3'  => [
            'pro' => true
          ],
          'v4'  => [
            'pro' => true
          ]
        ]
      ],
      'gamipress_rank'        => [
        'id'          => 'gamipress_rank',
        'name'        => __( 'Rank', 'orokublocks' ),
        'plugin'      => 'gamipress',
        'categories'  => [ 'gamipress' ],
        'tags'        => [ 'pro' ],
        'urls'        => [
          'documentation' => 'https://orokublocks.com/documentation/rank',
          'demo'          => 'https://orokublocks.com/widgets/rank'
        ],
        'versions'  => [
          'v1'  => [
            'pro' => true
          ],
          'v2'  => [
            'pro' => true
          ],
          'v3'  => [
            'pro' => true
          ],
          'v4'  => [
            'pro' => true
          ]
        ]
      ],
      'gamipress_point'       => [
        'id'          => 'gamipress_point',
        'name'        => __( 'Point', 'orokublocks' ),
        'plugin'      => 'gamipress',
        'categories'  => [ 'gamipress' ],
        'tags'        => [ 'pro' ],
        'urls'        => [
          'documentation' => 'https://orokublocks.com/documentation/point',
          'demo'          => 'https://orokublocks.com/widgets/point'
        ],
        'versions'  => [
          'v1'  => [
            'pro' => true
          ],
          'v2'  => [
            'pro' => true
          ],
          'v3'  => [
            'pro' => true
          ],
          'v4'  => [
            'pro' => true
          ]
        ]
      ],
      /**
       * SportsPress
       */
      'sportspress_player_card' => [
        'id'          => 'sportspress_player_card',
        'name'        => __( 'Player Card', 'orokublocks' ),
        'plugin'      => 'sportspress',
        'categories'  => [ 'sportspress' ],
        'tags'        => [ 'freemium' ],
        'urls'        => [
          'documentation' => 'https://orokublocks.com/documentation/player-card',
          'demo'          => 'https://orokublocks.com/widgets/player-card'
        ],
        'versions'  => [
          'v1'  => [
            'pro' => false
          ],
          'v2'  => [
            'pro' => true
          ],
          'v3'  => [
            'pro' => true
          ],
          'v4'  => [
            'pro' => true
          ]
        ]
      ],
      'sportspress_score' => [
        'id'          => 'sportspress_score',
        'name'        => __( 'Score', 'orokublocks' ),
        'plugin'      => 'sportspress',
        'categories'  => [ 'sportspress' ],
        'tags'        => [ 'pro' ],
        'urls'        => [
          'documentation' => 'https://orokublocks.com/documentation/score',
          'demo'          => 'https://orokublocks.com/widgets/score'
        ],
        'versions'  => [
          'v1'  => [
            'pro' => true
          ],
          'v2'  => [
            'pro' => true
          ],
          'v3'  => [
            'pro' => true
          ],
          'v4'  => [
            'pro' => true
          ]
        ],
        'required_pro_version'  => '1.1.0'
      ],
      /**
       * WooCommerce
       */
      'woocommerce_product' => [
        'id'          => 'woocommerce_product',
        'name'        => __( 'Product', 'orokublocks' ),
        'plugin'      => 'woocommerce',
        'categories'  => [ 'woocommerce' ],
        'tags'        => [ 'freemium' ],
        'urls'        => [
          'documentation' => 'https://orokublocks.com/documentation/product-card',
          'demo'          => 'https://orokublocks.com/widgets/product-card'
        ],
        'versions'  => [
          'v1'  => [
            'pro' => false
          ],
          'v2'  => [
            'pro' => true
          ],
          'v3'  => [
            'pro' => true
          ],
          'v4'  => [
            'pro' => true
          ]
        ]
      ]
    ];

    /**
     * Setup settings
     * 
     * @since 1.0.0
     */
    $this->settings = OrokuBlocks_Settings::getInstance();

    /**
     * Setup admin related functionality
     * only when on the WordPress admin
     * 
     * @since 1.0.0
     */
    if ( is_admin() ) {
      $this->admin = OrokuBlocks_Admin::getInstance();
    }

    if ( $this->pluginIsActive( 'elementor' ) ) {
      /**
       * Load widget files and instantiate them
       * 
       * @since 1.0.0
       */
      foreach ( $this->widgets as $widget_id => $widget ) {
        // if the widget requires a plugin and it's not active, do not load its file nor instantiate it
        if ( array_key_exists( 'plugin', $widget ) && ( ! $this->pluginIsActive( $widget['plugin'] ) ) ) {
          continue;
        }

        // Load widget file
        $widget_path_id = OrokuBlocks_Router::widgetPathIdGet( $widget_id );

        require_once OrokuBlocks_Router::widgetPathGet( $widget_id ) . '/class-orokublocks-' . $widget_path_id . '.php';
        
        // Instantiate widget
        $widget_classname = OrokuBlocks_Router::widgetClassNameGet( $widget_id );
        
        if ( class_exists( $widget_classname ) ) {
          $this->widgets[$widget_id]['instance'] = $widget_classname::getInstance();
        }
      }
    }
  }

  /**
   * Register actions
   * 
   * @since 1.0.0
   * 
   * @access private
   */
  private function addActions() {
    add_action( 'wp_enqueue_scripts', array( $this, 'enqueueStyles' ) );
    add_action( 'wp_enqueue_scripts', array( $this, 'enqueueScripts' ) );

    add_action( 'init', array( $this, 'setup' ) );

    if ( $this->pluginIsActive( 'elementor' ) ) {
      // Register Elementor categories if the plugin is active
      add_action( 'elementor/elements/categories_registered', array( $this, 'registerElementorCategories' ) );
      // Register Elementor editor styles if the plugin is active
      add_action( 'elementor/editor/after_enqueue_styles', array( $this, 'registerElementorEditorStyles' ) );
    }
  }

  /**
   * Enqueue styles and fonts
   * 
   * @since 1.0.0
   */
  public function enqueueStyles() {
    // Fonts
    wp_enqueue_style( 'orokublocks-fonts', 'https://fonts.googleapis.com/css2?family=Inter:opsz,wght@14..32,100..900&display=swap' );

    // Main styles
    wp_enqueue_style( 'orokublocks-styles', $this->url . 'assets/css/style.css', [], '1.0.0' );
  }

  /**
   * Enqueue scripts
   * 
   * @since 1.0.0
   */
  public function enqueueScripts() {
    // Main scripts
    wp_enqueue_script( 'orokublocks-script', $this->url . 'assets/js/main.js', [], '1.0.0', true );
  }

  /**
   * Returns true if using pro version, false otherwise
   * 
   * @since 1.0.0
   * 
   * @return bool     True if pro version, false otherwise
   */
  public function isProVersion() {
    return class_exists( 'OrokuBlocks_Pro' );
  }

  /**
   * Returns true if using pro version and it is valid, false otherwise
   * 
   * @since 1.0.0
   * 
   * @return bool     True if pro version and it is valid, false otherwise
   */
  public function isProVersionValid() {
    return $this->isProVersion() && OrokuBlocks_Pro_License::isValid();
  }

  /**
   * Return social links data
   * 
   * @since 1.0.0
   * 
   * @return array $social_links        Social links data.
   */
  public function socialLinksGet() {
    $social_links = [
      'x'         => [
        'name'  => 'X / Twitter',
        'url'   => 'https://x.com/OrokuBlocks'
      ],
      'youtube'   => [
        'name'  => 'YouTube',
        'url'   => 'https://www.youtube.com/@OrokuBlocks'
      ],
      'wordpress' => [
        'name'  => 'WordPress',
        'url'   => 'https://wordpress.org/plugins/orokublocks/'
      ]
    ];

    return $social_links;
  }

  /**
   * Returns unlock pro url
   * 
   * @since 1.0.0
   * 
   * @return string $unlock_pro_url      Url of the unlock pro page.
   */
  public function getUnlockProUrl() {
    $unlock_pro_url = 'https://orokublocks.com/pricing';

    return $unlock_pro_url;
  }

  /**
   * Returns freemius pricing page url.
   * 
   * @since 1.0.0
   * 
   * @return string $pricing_page_url      Url of the pricing page.
   */
  public function getFreemiusPricingUrl() {
    $pricing_page_url = admin_url( 'admin.php?page=orokublocks-pricing' );

    return $pricing_page_url;
  }

  /**
   * Returns freemius account page url.
   * 
   * @since 1.0.0
   * 
   * @return string $account_page_url      Url of the account page.
   */
  public function getFreemiusAccountUrl() {
    $account_page_url = admin_url( 'admin.php?page=orokublocks-account' );

    return $account_page_url;
  }

  /**
   * Returns true if the provided widget id belongs to a pro widget, false otherwise
   * 
   * @since 1.0.0
   * 
   * @param string $widget_id           Id of the widget to validate.
   * @param string $widget_version      Widget version. Optional.
   * @return bool  $widget_is_pro       True if pro widget, false otherwise
   */
  public function isWidgetVersionPro( $widget_id, $widget_version = 'v1' ) {
    $widget_is_pro = false;

    if ( $this->widgetExists( $widget_id ) ) {
      $widget_is_pro = $this->widgets[$widget_id]['versions'][$widget_version]['pro'];
    }

    return $widget_is_pro;
  }

  /**
   * Return true if the provided widget id has at least one free version
   * 
   * @since 1.0.0
   * 
   * @param string $widget_id                     Id of the widget to validate.
   * @return bool  $widget_has_free_version       True if widget has at least one free version, false otherwise
   */
  public function widgetHasFreeVersion( $widget_id ) {
    $widget_has_free_version = false;

    if ( $this->widgetExists( $widget_id ) ) {
      foreach ( $this->widgets[$widget_id]['versions'] as $widget_version => $widget ) {
        if ( ! $widget['pro'] ) {
          return true;
        }
      }
    }

    return $widget_has_free_version;
  }

  /**
   * Return widget version ids
   * 
   * @since 1.0.0
   * 
   * @param string  $widget_id            Id of the widget.
   * @param bool    $is_pro_version       True to return pro widget versions, false otherwise.
   * @return array  $widget_versions      Widget pro versions. 
   */
  private function getWidgetVersions( $widget_id, $is_pro_version ) {
    $versions = [];

    if ( $this->widgetExists( $widget_id ) ) {
      foreach ( $this->widgets[$widget_id]['versions'] as $widget_version => $widget ) {
        if ( $widget['pro'] === $is_pro_version ) {
          $versions[] = $widget_version;
        }
      }
    }

    return $versions;
  }

  /**
   * Return widget free version ids
   * 
   * @since 1.0.0
   * 
   * @param string $widget_id           Id of the widget.
   * @return array $free_versions       Widget pro versions. 
   */
  public function getWidgetFreeVersions( $widget_id ) {
    $free_versions = $this->getWidgetVersions( $widget_id, false );

    return $free_versions;
  }

  /**
   * Return widget pro version ids
   * 
   * @since 1.0.0
   * 
   * @param string $widget_id           Id of the widget.
   * @return array $pro_versions        Widget pro versions. 
   */
  public function getWidgetProVersions( $widget_id ) {
    $pro_versions = $this->getWidgetVersions( $widget_id, true );

    return $pro_versions;
  }

  /**
   * Returns true if the provided id corresponds to an existing widget
   * 
   * @since 1.0.0
   * 
   * @param string  $widget_id          Id of the widget to validate.
   * @return bool   $widget_is_valid    True if widget exists, false otherwise.
   */
  public function widgetExists( $widget_id ) {
    $widget_is_valid = array_key_exists( $widget_id, $this->widgets );

    return $widget_is_valid;
  }

  /**
   * Returns true if the provided id corresponds to an enabled widget
   * 
   * @since 1.0.0
   * 
   * @param string  $widget_id            Id of the widget to validate.
   * @return bool   $widget_is_enabled    True if widget is enabled, false otherwise.
   */
  public function widgetIsEnabled( $widget_id ) {
    $enabled_widgets = $this->settings->getSettings()['widget_enabled'];

    $widget_is_enabled = array_key_exists( $widget_id, $enabled_widgets ) && $enabled_widgets[$widget_id];

    return $widget_is_enabled;
  }

  /**
   * Require a template file by name
   * 
   * @since 1.0.0
   * 
   * @param string  $template_path    Path of the template to require.
   * @param array   $args             Arguments to pass to the template. Optional.
   */
  public function requireTemplate( $template_path, $args = [] ) {
    require $template_path . '.php';
  }

  /**
   * Include a template file by name
   * 
   * @since 1.0.0
   * 
   * @param string  $template_path    Path of the template to include.
   * @param array   $args             Arguments to pass to the template. Optional.
   */
  public function includeTemplate( $template_path, $args = [] ) {
    $file_path = $template_path . '.php';

    if ( is_file( $this->path . $file_path ) ) {
      include $file_path;
    }
  }

  /**
   * Include a widget by id and version
   * 
   * @since 1.0.0
   * 
   * @param string  $widget_id          Id of the widget template to include.
   * @param string  $widget_version     Widget version. Optional.
   * @param array   $args               Arguments to pass to the template. Optional.
   */
  public function includeWidget( $widget_id, $widget_version = 'v1', $args = [] ) {
    if ( $this->widgetExists( $widget_id ) ) {
      $widget_path_id = OrokuBlocks_Router::widgetPathIdGet( $widget_id );
      $widget_path = 'widgets/' . $widget_path_id . '/template/' . $widget_path_id;

      if ( $widget_version !== '' ) {
        $widget_path .= '-' . $widget_version;
      }

      if ( $this->isWidgetVersionPro( $widget_id, $widget_version ) ) {
        $this->isProVersion() && orokublocks_pro()->includeTemplate( $widget_path, $args );
      } else {
        $this->includeTemplate( $widget_path, $args );
      }
    }
  }

  /**
   * Return true if the plugin that corresponds to the provided plugin name is active
   * 
   * @since 1.0.0
   * 
   * @return bool       True if plugin is active, false if plugin is not active or provided plugin name is invalid.
   */
  public function pluginIsActive( $plugin_name = '' ) {
    $plugin_path = $plugin_name . '/' . $plugin_name . '.php';

    return is_plugin_active( $plugin_path );
  }

  /**
   * Returns incremental id for provided component
   * 
   * @since 1.0.0
   * 
   * @param string $component_id        Id of the component to generate an id for.
   * @return int                        Generated id for provided component.
   */
  public static function generateId( $component_id ) {
    static $component_ids = [];

    if ( ! array_key_exists( $component_id, $component_ids ) ) {
      $component_ids[$component_id] = 0;
    }

    return ++$component_ids[$component_id];
  }

  /**
   * Registers widget categories for Elementor
   * 
   * @since 1.0.0
   * 
   * @param object $elements_manager      Elementor elements manager instance.
   */
  public function registerElementorCategories( $elements_manager ) {
    $elements_manager->add_category(
      'orokublocks',
      [
        'title' => 'OrokuBlocks'
      ]
    );
  }

  /**
   * Enqueue styles for the Elementor editor
   * 
   * @since 1.0.0
   */
  public function registerElementorEditorStyles() {
    wp_enqueue_style( 'orokublocks-elementor-editor-font-styles', $this->url . 'admin/assets/css/font.css', [], '1.0.0' );
    wp_enqueue_style( 'orokublocks-elementor-editor-styles', $this->url . 'admin/assets/css/elementor-editor.css', [], '1.0.0' );
  }
}

/**
 * Returns the class instance
 * 
 * @since 1.0.0
 * 
 * @return OrokuBlocks  Class instance
 */
function orokublocks() {
  return OrokuBlocks::getInstance();
}

// initialize singleton
orokublocks();