plugin_name = self::PLUGIN_NAME; $this->user = new Prodigy_User(); $this->wp_cookie_compatibility = new Prodigy_Wp_Cookie_Compatibility(); $this->order = new Prodigy_Order(); $this->cart = new Prodigy_Cart( Prodigy_Request_Maker::get_instance(), $this->order, new Cart_Error_Handler() ); $this->load_dependencies(); $this->set_locale(); if ( is_admin() ) { $this->define_admin_hooks(); } $this->define_public_hooks(); $this->set_elementor(); add_action( 'init', array( $this, 'register_post_types' ) ); add_action( 'init', array( $this, 'register_taxonomies' ) ); add_action( 'init', array( $this, 'register_tags' ) ); add_action( 'init', array( $this, 'register_brands' ) ); add_action( 'init', array( $this, 'load_instances' ) ); add_action( 'init', array( $this, 'includes' ) ); add_action( 'init', array( $this, 'load_global_scripts' ) ); add_action( 'init', array( $this, 'start_sync_process' ) ); add_action( 'init', array( $this, 'prodigy_register_elementor' ) ); add_action( 'init', array( $this, 'update_plugin_version' ) ); add_action( 'init', array( $this, 'prodigy_set_cart_cookie' ) ); add_action( 'init', array( $this, 'set_auth_user_logic' ) ); add_action( 'init', array( $this, 'init_early_taxonomy_validation' ) ); add_action( 'init', array( $this, 'init_cron_events' ) ); add_action( 'widgets_init', array( $this, 'prodigy_register_widgets' ) ); add_action( 'admin_notices', array( new Prodigy_Admin_Notification(), 'display_admin_notice' ) ); // Remove the Content-Security-Policy headers for AJAX requests (need for Ariba) add_action( 'admin_init', array( $this, 'disable_frame_headers_for_ajax' ), 0 ); add_action( 'admin_init', array( $this, 'remove_frame_headers_for_ajax' ), PHP_INT_MAX ); add_action( 'admin_init', array( $this, 'sync_content' ), 999 ); add_action( 'admin_init', array( $this, 'maybe_sync_prodigy_pages_after_elementor_import' ), 1000 ); add_action( 'prodigy_after_register_post_type', array( $this, 'maybe_flush_rewrite_rules' ) ); add_action( 'elementor/import-export/import-kit/runner/after-run', array( $this, 'sync_prodigy_pages_after_elementor_import' ), 20 ); add_action( 'elementor/import-export-customization/import-kit/runner/after-run', array( $this, 'sync_prodigy_pages_after_elementor_import' ), 20 ); add_action( 'save_post_page', array( $this, 'ensure_elementor_page_editable_on_save' ), 20, 3 ); add_action( 'added_post_meta', array( $this, 'ensure_elementor_page_editable_on_meta_update' ), 20, 4 ); add_action( 'updated_post_meta', array( $this, 'ensure_elementor_page_editable_on_meta_update' ), 20, 4 ); add_filter( 'widget_text', 'do_shortcode' ); add_filter( 'request', array( $this, 'resolve_prodigy_page_request' ), 1 ); add_filter( 'pre_option_page_for_posts', array( $this, 'ignore_posts_page_for_prodigy_page_request' ), 1 ); add_action( 'activated_plugin', array( $this, 'prodigy_activation_redirect' ) ); add_filter( 'get_user_option_metaboxhidden_nav-menus', array( $this, 'custom_display_appearance_menus', ), 10, 3 ); add_action( 'after_switch_theme', array( $this, 'customize_current_theme' ) ); add_action( 'divi_extensions_init', array( $this, 'divi_initialize_extension' ) ); add_filter( 'allowed_redirect_hosts', array( $this, 'allowed_prodigy_redirect_urls' ) ); add_filter( 'robots_txt', array( $this, 'add_filter_robots_rules' ) ); add_filter( 'wp_robots', array( $this, 'add_noindex_for_filter_pages' ) ); $filters = array( 'script_loader_src', 'style_loader_src', ); foreach ( $filters as $filter ) { add_filter( $filter, array( $this, 'my_make_asset_url_relative' ), 999 ); } $this->init_wp_rocket_compatibility(); } public function disable_frame_headers_for_ajax() { if ( ! wp_doing_ajax() ) { return; } remove_action( 'admin_init', 'send_frame_options_header' ); } public function remove_frame_headers_for_ajax() { if ( ! wp_doing_ajax() ) { return; } header_remove( 'X-Frame-Options' ); header_remove( 'Content-Security-Policy' ); } /** * Load the required dependencies for this plugin. * * Include the following files that make up the plugin: * * - Prodigy_Loader. Orchestrates the hooks of the plugin. * - Prodigy_Admin. Defines all hooks for the admin area. * - Prodigy_Public. Defines all hooks for the public side of the site. * * @since 2.0.0 * @access private */ private function load_dependencies(): void { /** * prodigy trait sidebar */ require_once PRODIGY_PLUGIN_PATH . 'includes/helpers/traits/trait-prodigy-sidebar.php'; require_once PRODIGY_PLUGIN_PATH . 'includes/frontend/traits/trait-prodigy-mlc-charge.php'; /** * prodigy enums */ require_once PRODIGY_PLUGIN_PATH . 'includes/helpers/enums/prodigy-enums.php'; /** * prodigy global functions */ require_once PRODIGY_PLUGIN_PATH . 'includes/helpers/prodigy-core-functions.php'; /** * Add support template functions */ require_once PRODIGY_PLUGIN_PATH . 'includes/frontend/prodigy-template-functions.php'; /** * Set template hooks */ require_once PRODIGY_PLUGIN_PATH . 'includes/frontend/prodigy-template-hooks.php'; $this->loader = new Prodigy_Loader(); } /** * Define the locale for this plugin for internationalization. * * Uses the Prodigy_i18n class in order to set the domain and to register the hook * with WordPress. * * @since 1.0.0 * @access private */ private function set_locale(): void { $plugin_i18n = new Prodigy_i18n(); $this->loader->add_action( 'plugins_loaded', $plugin_i18n, 'load_plugin_textdomain' ); } /** * Register all of the hooks related to the admin area functionality * of the plugin. * * @since 1.0.0 * @access private */ private function define_admin_hooks(): void { $plugin_admin = new Prodigy_Admin( $this->get_plugin_name(), PRODIGY_VERSION ); $this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueue_styles' ); $this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueue_scripts' ); } /** * The name of the plugin used to uniquely identify it within the context of * WordPress and to define internationalization functionality. * * @return string The name of the plugin. * @since 1.0.0 */ public function get_plugin_name() { return $this->plugin_name; } /** * Keep Prodigy system pages addressable when another rewrite resolves their * pretty URL as an archive. * * @param array $query_vars * * @return array */ public function resolve_prodigy_page_request( array $query_vars ): array { $query_vars = Prodigy_Url_Helper::resolve_prodigy_page_query_vars( $query_vars ); return self::resolve_static_elementor_page_query_vars( $query_vars ); } /** * @param array $query_vars * * @return array */ public static function resolve_static_elementor_page_query_vars( array $query_vars ): array { if ( is_admin() || isset( $query_vars['page_id'] ) ) { return $query_vars; } $page_id = self::get_page_id_for_current_request_path(); if ( ! empty( $page_id ) ) { return array( 'page_id' => $page_id ); } return $query_vars; } /** * Do not let a WordPress "Posts page" assignment turn Prodigy system pages * into the blog index. * * @param mixed $pre_option * * @return mixed */ public function ignore_posts_page_for_prodigy_page_request( $pre_option ) { if ( Prodigy_Url_Helper::is_prodigy_page_request() || self::get_page_id_for_current_request_path() > 0 ) { return 0; } return $pre_option; } /** * Register all of the hooks related to the public-facing functionality * of the plugin. * * @since 1.0.0 * @access private */ private function define_public_hooks(): void { $plugin_public = new Prodigy_Public( $this->get_plugin_name() ); $this->loader->add_action( 'wp_enqueue_scripts', $plugin_public, 'enqueue_styles' ); $this->loader->add_action( 'wp_enqueue_scripts', $plugin_public, 'enqueue_scripts' ); } /** * Init elementor engine * * @return void */ public function set_elementor() { if ( is_plugin_active( 'elementor-pro/elementor-pro.php' ) && did_action( 'elementor/loaded' ) ) { add_action( 'elementor/init', array( $this, 'init_elementor' ) ); add_action( 'elementor/init', array( $this, 'prodigy_elementor_source' ) ); } } /** * Initialize WP Rocket compatibility */ private function init_wp_rocket_compatibility() { require_once PRODIGY_PLUGIN_PATH . 'includes/class-prodigy-wp-rocket-compatibility.php'; } /** * Refresh permalinks after change entity slugs * * @return void */ public static function maybe_flush_rewrite_rules(): void { if ( Prodigy_Widget_Options::$bool_mapper[ get_option( 'prodigy_queue_flush_rewrite_rules' ) ] ) { update_option( 'prodigy_queue_flush_rewrite_rules', 'no' ); flush_rewrite_rules(); } } /** * Reconnect Prodigy system pages after an Elementor kit import. * * @return void */ public function sync_prodigy_pages_after_elementor_import(): void { self::sync_prodigy_system_pages_from_elementor(); update_option( 'prodigy_elementor_system_pages_synced', 'yes' ); update_option( 'prodigy_elementor_pages_editable_synced', 'yes' ); } /** * @return void */ public function maybe_sync_prodigy_pages_after_elementor_import(): void { $system_pages_synced = 'yes' === get_option( 'prodigy_elementor_system_pages_synced' ); $elementor_pages_synced = 'yes' === get_option( 'prodigy_elementor_pages_editable_synced' ); if ( $system_pages_synced && $elementor_pages_synced && ! self::has_stale_prodigy_system_page_assignments() && ! self::is_prodigy_pages_settings_screen() ) { return; } self::sync_prodigy_system_pages_from_elementor(); update_option( 'prodigy_elementor_system_pages_synced', 'yes' ); update_option( 'prodigy_elementor_pages_editable_synced', 'yes' ); } /** * @param int $post_id * @param \WP_Post $post * @param bool $update * * @return void */ public function ensure_elementor_page_editable_on_save( int $post_id, \WP_Post $post, bool $update ): void { if ( wp_is_post_autosave( $post_id ) || wp_is_post_revision( $post_id ) ) { return; } self::ensure_elementor_page_is_editable( $post_id ); } /** * @param int $meta_id * @param int $post_id * @param string $meta_key * @param mixed $meta_value * * @return void */ public function ensure_elementor_page_editable_on_meta_update( int $meta_id, int $post_id, string $meta_key, $meta_value ): void { if ( '_elementor_data' !== $meta_key ) { return; } self::ensure_elementor_page_is_editable( $post_id ); } /** * @return bool */ public static function sync_prodigy_system_pages_from_elementor(): bool { $changed = false; $changed = self::sync_prodigy_system_page_from_elementor( 'cart', 'cart', 'pg-cart-widget', 'Cart' ) || $changed; $changed = self::sync_prodigy_system_page_from_elementor( 'thank', 'thank-you', 'pg-thank-you-page', 'Thank you' ) || $changed; $changed = self::sync_elementor_page_edit_mode() || $changed; $changed = self::sync_elementor_static_page_links() || $changed; $changed = self::normalize_prodigy_page_assignments() || $changed; update_option( 'prodigy_queue_flush_rewrite_rules', 'no' ); flush_rewrite_rules( false ); return $changed; } /** * WordPress cannot display a page as normal content while the same page is * assigned as the Posts page. * * @return bool */ public static function normalize_prodigy_page_assignments(): bool { $posts_page_id = (int) get_option( 'page_for_posts' ); $prodigy_page_ids = array_filter( array( (int) get_option( 'prodigy_cart_page_id' ), (int) get_option( 'prodigy_thank_page_id' ), ) ); if ( $posts_page_id > 0 && in_array( $posts_page_id, $prodigy_page_ids, true ) ) { update_option( 'page_for_posts', 0 ); return true; } return false; } /** * @return bool */ private static function has_stale_prodigy_system_page_assignments(): bool { foreach ( array( 'prodigy_cart_page_id', 'prodigy_thank_page_id' ) as $option_name ) { $page_id = (int) get_option( $option_name ); if ( $page_id > 0 && ! self::is_published_page( $page_id ) ) { return true; } } return false; } /** * @return bool */ private static function is_prodigy_pages_settings_screen(): bool { $page = isset( $_GET['page'] ) && is_string( $_GET['page'] ) ? sanitize_key( wp_unslash( $_GET['page'] ) ) : ''; $tab = isset( $_GET['tab'] ) && is_string( $_GET['tab'] ) ? sanitize_key( wp_unslash( $_GET['tab'] ) ) : ''; return 'prodigy_settings' === $page && 'pages' === $tab; } /** * @param string $page_type * @param string $page_slug * @param string $widget_type * @param string $page_title * * @return bool */ private static function sync_prodigy_system_page_from_elementor( string $page_type, string $page_slug, string $widget_type, string $page_title ): bool { $option_name = 'prodigy_' . $page_type . '_page_id'; $current_page_id = absint( get_option( $option_name ) ); if ( self::is_elementor_page_with_widget( $current_page_id, $widget_type ) || self::is_page_matching_slug_or_title( $current_page_id, $page_slug, $page_title ) ) { return false; } $page_id = self::find_elementor_page_by_slug_and_widget( $page_slug, $widget_type ); if ( empty( $page_id ) ) { $page_id = self::find_page_by_slug_or_title( $page_slug, $page_title ); } if ( empty( $page_id ) || $page_id === $current_page_id ) { return false; } self::ensure_elementor_page_is_editable( $page_id ); update_option( $option_name, $page_id ); return true; } /** * @param string $page_slug * @param string $widget_type * * @return int */ private static function find_elementor_page_by_slug_and_widget( string $page_slug, string $widget_type ): int { $page = get_page_by_path( $page_slug ); if ( $page instanceof \WP_Post && self::is_elementor_page_with_widget( (int) $page->ID, $widget_type ) ) { return (int) $page->ID; } $pages = get_posts( array( 'fields' => 'ids', 'meta_query' => array( array( 'key' => '_elementor_data', 'value' => $widget_type, 'compare' => 'LIKE', ), ), 'no_found_rows' => true, 'post_status' => 'publish', 'post_type' => 'page', 'posts_per_page' => 1, 's' => $page_slug, ) ); return isset( $pages[0] ) ? (int) $pages[0] : 0; } /** * @param int $page_id * @param string $widget_type * * @return bool */ private static function is_elementor_page_with_widget( int $page_id, string $widget_type ): bool { if ( ! self::is_published_page( $page_id ) ) { return false; } $elementor_data = get_post_meta( $page_id, '_elementor_data', true ); return is_string( $elementor_data ) && false !== strpos( $elementor_data, $widget_type ); } /** * @param int $page_id * * @return bool */ private static function is_published_page( int $page_id ): bool { if ( empty( $page_id ) ) { return false; } $page = get_post( $page_id ); if ( ! $page instanceof \WP_Post || 'page' !== $page->post_type || 'publish' !== $page->post_status ) { return false; } return true; } /** * @param int $page_id * @param string $slug * @param string $title * * @return bool */ private static function is_page_matching_slug_or_title( int $page_id, string $slug, string $title ): bool { if ( ! self::is_published_page( $page_id ) ) { return false; } $page = get_post( $page_id ); return $page instanceof \WP_Post && ( $slug === $page->post_name || $title === $page->post_title ); } /** * @return bool */ private static function sync_elementor_static_page_links(): bool { $page_ids = array( 'policy' => self::find_elementor_page_by_slug_or_title( 'policy', 'Policy' ), 'terms' => self::find_elementor_page_by_slug_or_title( 'terms', 'Terms' ), ); $replacements = array(); foreach ( $page_ids as $slug => $page_id ) { if ( empty( $page_id ) ) { continue; } $replacements[ $slug ] = wp_make_link_relative( get_permalink( $page_id ) ); } if ( empty( $replacements ) ) { return false; } global $wpdb; $changed = false; $post_types = self::get_elementor_content_post_types(); $type_placeholders = implode( ', ', array_fill( 0, count( $post_types ), '%s' ) ); $posts = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM {$wpdb->posts} WHERE post_type IN ({$type_placeholders}) AND post_status != %s", array_merge( $post_types, array( 'auto-draft' ) ) ) ); foreach ( $posts as $post_id ) { $elementor_data = get_post_meta( (int) $post_id, '_elementor_data', true ); if ( ! is_string( $elementor_data ) || '' === $elementor_data ) { continue; } $updated_elementor_data = self::replace_static_page_links_in_string( $elementor_data, $replacements ); if ( $updated_elementor_data !== $elementor_data ) { update_post_meta( (int) $post_id, '_elementor_data', wp_slash( $updated_elementor_data ) ); $changed = true; continue; } $decoded_data = json_decode( $elementor_data, true ); if ( ! is_array( $decoded_data ) ) { continue; } $updated_data = self::replace_static_page_links_in_elementor_data( $decoded_data, $replacements ); if ( $updated_data === $decoded_data ) { continue; } update_post_meta( (int) $post_id, '_elementor_data', wp_slash( wp_json_encode( $updated_data ) ) ); $changed = true; } return $changed; } /** * @return array */ private static function get_elementor_content_post_types(): array { $post_types = array( 'page' ); if ( post_type_exists( 'elementor_library' ) ) { $post_types[] = 'elementor_library'; } return $post_types; } /** * @param string $slug * @param string $title * * @return int */ private static function find_elementor_page_by_slug_or_title( string $slug, string $title ): int { $page_id = self::find_page_by_slug_or_title( $slug, $title ); return self::is_elementor_page( $page_id ) ? $page_id : 0; } /** * @param string $slug * @param string $title * * @return int */ private static function find_page_by_slug_or_title( string $slug, string $title ): int { $page = get_page_by_path( $slug ); if ( $page instanceof \WP_Post && 'page' === $page->post_type && 'publish' === $page->post_status ) { return (int) $page->ID; } global $wpdb; return (int) $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM {$wpdb->posts} WHERE post_type = 'page' AND post_status = 'publish' AND ( post_name = %s OR post_title = %s ) ORDER BY CASE WHEN post_name = %s THEN 0 ELSE 1 END, ID DESC LIMIT 1", $slug, $title, $slug ) ); } /** * @return int */ private static function get_page_id_for_current_request_path(): int { if ( is_admin() ) { return 0; } $request_path = self::get_relative_url_path( Prodigy_Url_Helper::prodigy_get_request_uri() ); if ( '' === $request_path ) { return 0; } $page = get_page_by_path( $request_path ); if ( $page instanceof \WP_Post && 'page' === $page->post_type && 'publish' === $page->post_status ) { return (int) $page->ID; } return 0; } /** * @param string $url * * @return string */ private static function get_relative_url_path( string $url ): string { $path = (string) wp_parse_url( $url, PHP_URL_PATH ); if ( '' === $path ) { return ''; } $home_path = (string) wp_parse_url( home_url( '/' ), PHP_URL_PATH ); if ( '/' !== $home_path && 0 === strpos( $path, $home_path ) ) { $path = substr( $path, strlen( $home_path ) ); } return trim( $path, '/' ); } /** * @param int $page_id * * @return bool */ private static function is_elementor_page( int $page_id ): bool { $page = get_post( $page_id ); if ( ! $page instanceof \WP_Post || 'page' !== $page->post_type || 'publish' !== $page->post_status ) { return false; } $elementor_data = get_post_meta( $page_id, '_elementor_data', true ); return is_string( $elementor_data ) && '' !== $elementor_data; } /** * @return bool */ private static function sync_elementor_page_edit_mode(): bool { $page_ids = get_posts( array( 'fields' => 'ids', 'meta_key' => '_elementor_data', 'no_found_rows' => true, 'post_status' => array( 'publish', 'draft', 'pending', 'private', 'future' ), 'post_type' => 'page', 'posts_per_page' => -1, ) ); $changed = false; foreach ( $page_ids as $page_id ) { $changed = self::ensure_elementor_page_is_editable( (int) $page_id ) || $changed; } return $changed; } /** * @param int $page_id * * @return bool */ private static function ensure_elementor_page_is_editable( int $page_id ): bool { $page = get_post( $page_id ); if ( ! $page instanceof \WP_Post || 'page' !== $page->post_type ) { return false; } $elementor_data = get_post_meta( $page_id, '_elementor_data', true ); if ( ! is_string( $elementor_data ) || '' === trim( $elementor_data ) ) { return false; } $changed = false; if ( 'builder' !== get_post_meta( $page_id, '_elementor_edit_mode', true ) ) { update_post_meta( $page_id, '_elementor_edit_mode', 'builder' ); $changed = true; } if ( 'wp-page' !== get_post_meta( $page_id, '_elementor_template_type', true ) ) { update_post_meta( $page_id, '_elementor_template_type', 'wp-page' ); $changed = true; } return $changed; } /** * @param mixed $value * @param array $replacements * * @return mixed */ private static function replace_static_page_links_in_elementor_data( $value, array $replacements ) { if ( is_array( $value ) ) { foreach ( $value as $key => $item ) { $value[ $key ] = self::replace_static_page_links_in_elementor_data( $item, $replacements ); } return $value; } if ( ! is_string( $value ) ) { return $value; } return self::replace_static_page_links_in_string( $value, $replacements ); } /** * @param string $value * @param array $replacements * * @return string */ private static function replace_static_page_links_in_string( string $value, array $replacements ): string { foreach ( $replacements as $slug => $replacement ) { $value = preg_replace( '#(?flush_rules( true ); } /** * Adaptation of script connections for single domain approach * * @param string $src * * @return string */ public function my_make_asset_url_relative( string $src ): string { // Elementor screenshot proxy requires absolute URLs to fetch assets. if ( is_admin() || isset( $_GET['screenshot_proxy'] ) ) { return $src; } $host = wp_parse_url( home_url(), PHP_URL_HOST ); $src_host = wp_parse_url( $src, PHP_URL_HOST ); if ( ! $src_host || strcasecmp( $src_host, $host ) !== 0 ) { return $src; } return wp_make_link_relative( $src ); } /** * @return void */ public function init_cron_events() { new Prodigy_Cron_Scheduler(); Prodigy_Process_Factory::dispatch_cache_cleanup(); } /** * Allow Hosted System domain * * @param array $hosts * * @return array */ public function allowed_prodigy_redirect_urls( array $hosts ): array { $hosts[] = sprintf( '%1$s.%2$s', get_option( 'pg_url_domain_hosted_system' ), PRODIGY_CHECKOUT_DOMAIN ); return $hosts; } /** * @param string $output * * @return string */ public function add_filter_robots_rules( string $output ): string { $output .= "\nDisallow: /*?*attr%5B\n"; return $output; } /** * @param array $robots * * @return array */ public function add_noindex_for_filter_pages( array $robots ): array { if ( ! empty( $_GET['attr'] ) ) { $robots['noindex'] = true; $robots['nofollow'] = true; } return $robots; } /** * @throws \Exception */ public function set_auth_user_logic(): void { // Skip authentication logic for Elementor proxy requests // Hide elementor errors if ( isset( $_GET['screenshot_proxy'] ) ) { return; } // PunchOut return page renders an auto-submit form back to Ariba. // It is protected by a nonce + one-time transient return_key and must not // require customer auth: the hosted system may have already invalidated // the punchout session, and a 401 here would redirect to the login page // before the return form is rendered. if ( Prodigy_Punchout_Return::is_punchout_return_request() ) { return; } if ( $this->user->is_logout_action() ) { return; } $user_logged_in = Prodigy_User::is_logged_in(); $require_login = Prodigy_Platform_Settings::is_enable_login_option(); $session_token = Prodigy_Parameters::get_parameter( $_GET, 'session_token' ); if ( empty( $session_token ) ) { $session_token = Prodigy_Parameters::get_parameter( $_REQUEST, 'session_token' ); } $has_session_token = is_string( $session_token ) && $session_token !== ''; $request_uri = Prodigy_Url_Helper::prodigy_get_request_uri(); if ( $has_session_token && $user_logged_in ) { $has_paired_session_cookie = Prodigy_Cookies::has_cookie( Prodigy_User::PRODIGY_USER_PAIRED_SESSION_COOKIE_NAME ); $paired_session_token = Prodigy_Cookies::get_cookie( Prodigy_User::PRODIGY_USER_PAIRED_SESSION_COOKIE_NAME ); if ( $has_paired_session_cookie && $session_token !== $paired_session_token ) { $refresh_key = Prodigy_Cookies::get_cookie( Prodigy_User::REFRESH_COOKIE_NAME ); $this->user->hosted_system_logout_process( $refresh_key ); $this->user->logout(); $this->user->delete_user_cookie(); $user_logged_in = false; } elseif ( $has_paired_session_cookie ) { $request_uri = Prodigy_Url_Helper::prodigy_parse_request_uri( - 1 ); $redirect_url = $this->user->clear_url( $request_uri ); Prodigy_Url_Helper::login_redirect( $redirect_url ); } else { $this->user->process_login_redirect(); } } if ( $this->user->should_return_early( $user_logged_in, $require_login, $has_session_token ) ) { return; } if ( $user_logged_in ) { $this->user->get_user_info_from_hosted_system(); } else { $this->user->handle_unauthenticated_user( $require_login, $request_uri ); } } /** Init Divi plugin */ public function divi_initialize_extension(): void { require_once PRODIGY_PLUGIN_PATH . 'includes/support/addons/divi/includes/Divi.php'; } /** Set up migrations */ public function update_plugin_version(): void { $migration = new Prodigy_Migration(); $migration->run_upgrade_process(); } /** Init elementor */ public function init_elementor(): void { require_once PRODIGY_PLUGIN_PATH . 'includes/support/addons/elementor/builder/conditions/prodigy.php'; require_once PRODIGY_PLUGIN_PATH . 'includes/support/addons/elementor/builder/conditions/product-archive.php'; require_once PRODIGY_PLUGIN_PATH . 'includes/support/addons/elementor/builder/conditions/shop-page.php'; require_once PRODIGY_PLUGIN_PATH . 'includes/support/addons/elementor/builder/documents/product-archive.php'; require_once PRODIGY_PLUGIN_PATH . 'includes/support/addons/elementor/builder/documents/product.php'; require_once PRODIGY_PLUGIN_PATH . 'includes/support/addons/elementor/builder/module.php'; require_once PRODIGY_PLUGIN_PATH . 'includes/support/addons/elementor/builder/conditions/prodigy-post.php'; require_once PRODIGY_PLUGIN_PATH . 'includes/support/addons/elementor/builder/conditions/prodigy-product-names.php'; require_once PRODIGY_PLUGIN_PATH . 'includes/support/addons/elementor/builder/conditions/prodigy-taxonomy.php'; require_once PRODIGY_PLUGIN_PATH . 'includes/support/addons/elementor/builder/conditions/prodigy-sub-taxonomy.php'; new Module(); } /** * Start a content synchronization process * * @return void * @throws Demo\Exception\Prodigy_Demo_Content_Exception */ public function start_sync_process(): void { // Skip sync process for Elementor proxy requests // Hide elementor errors if ( isset( $_GET['screenshot_proxy'] ) ) { return; } $page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : ''; if ( $page === 'prodigy-setup' ) { return; } $uri = Prodigy_Url_Helper::prodigy_get_request_uri(); if ( $uri === '/favicon.ico' ) { return; } if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) { return; } $sync_type_to_start = get_option( Prodigy_Synchronization::PRODIGY_PROCESS_TYPE ); $sync_type_to_start_auto_sync = get_option( Prodigy_Synchronization::PRODIGY_PROCESS_TYPE_AUTO_SYNC ); $sync = new Prodigy_Synchronization(); if ( $sync_type_to_start === Prodigy_Synchronization::PRODIGY_DEMO_PROCESS ) { $sync->run_sync_process( Prodigy_Api_Client::SYNC_DEMO_URL, Prodigy_Synchronization::PRODIGY_DEMO_PROCESS ); delete_option( Prodigy_Synchronization::PRODIGY_PROCESS_TYPE ); return; } if ( $sync_type_to_start === Prodigy_Synchronization::PRODIGY_MANUAL_PROCESS ) { $sync->run_sync_process( Prodigy_Api_Client::SYNC_CONTENT_URL, Prodigy_Synchronization::PRODIGY_MANUAL_PROCESS ); delete_option( Prodigy_Synchronization::PRODIGY_PROCESS_TYPE ); return; } if ( $sync_type_to_start_auto_sync === Prodigy_Synchronization::PRODIGY_AUTO_SYNC ) { $sync->run_sync_process( Prodigy_Api_Client::SYNC_CONTENT_URL, Prodigy_Synchronization::PRODIGY_AUTO_SYNC ); delete_option( Prodigy_Synchronization::PRODIGY_PROCESS_TYPE_AUTO_SYNC ); return; } } /** Init sync process */ public function sync_content(): void { new Prodigy_Process_Factory(); } /** Init Elementor integration */ public function prodigy_register_elementor(): void { if ( is_plugin_active( 'elementor/elementor.php' ) ) { require_once 'support/addons/elementor/prodigy.php'; } } /** * Rewrite elementor templates library */ public function prodigy_elementor_source(): void { include 'support/addons/elementor/classes/prodigy-manager.php'; include 'support/addons/elementor/classes/prodigy-api.php'; include 'support/addons/elementor/classes/prodigy-custom-source.php'; ElementorPlugin::instance()->templates_manager = new Prodigy_Manager( ElementorPlugin::instance()->templates_manager ); $this->enable_cloud_templates(); } private function enable_cloud_templates(): void { add_action( 'elementor/init', function () { add_filter( 'elementor/connect/is_connected', '__return_true', 999 ); add_filter( 'elementor/connect/app/library/is_connected', '__return_true', 999 ); add_filter( 'elementor/editor/is_cloud_templates_enabled', '__return_true', 999 ); if ( class_exists( '\ElementorPro\Plugin' ) ) { add_filter( 'elementor_pro/editor/is_cloud_templates_enabled', '__return_true', 999 ); } if ( class_exists( '\Elementor\Core\Common\Modules\Connect\Module' ) ) { $connect_module = \Elementor\Plugin::$instance->common->get_component( 'connect' ); if ( $connect_module ) { $library_app = $connect_module->get_app( 'library' ); if ( $library_app ) { add_filter( 'elementor/connect/app/library/is_connected', '__return_true', 999 ); } } } }, 5 ); add_filter( 'elementor/connect/is_connected', '__return_true', 999 ); add_filter( 'elementor/connect/app/library/is_connected', '__return_true', 999 ); add_filter( 'elementor/editor/is_cloud_templates_enabled', '__return_true', 999 ); if ( class_exists( '\ElementorPro\Plugin' ) ) { add_filter( 'elementor_pro/editor/is_cloud_templates_enabled', '__return_true', 999 ); } add_filter( 'elementor/ajax/get_library_data', array( $this, 'filter_library_data_for_cloud_templates' ), 10, 2 ); } public function filter_library_data_for_cloud_templates( $data ) { if ( is_array( $data ) ) { $data['cloud_templates_enabled'] = true; $data['is_connected'] = true; } return $data; } public function filter_elementor_ajax_response( $response ) { if ( is_array( $response ) && isset( $response['data'] ) ) { if ( is_array( $response['data'] ) ) { $response['data']['is_connected'] = true; $response['data']['cloud_templates_enabled'] = true; } } return $response; } /** * Register widgets */ public function prodigy_register_widgets(): void { if ( isset( self::$widgets ) ) { foreach ( self::$widgets as $widget ) { register_widget( new $widget() ); } } } /** * @throws \Exception */ public function load_instances(): void { $request_maker = Prodigy_Request_Maker::get_instance(); $error_handler = new Cart_Error_Handler(); $api_listener = ( new Prodigy_Callback_Api_Listener( $this->order, $request_maker, $this->cart ) ); new Prodigy_Migration(); if ( is_admin() ) { /** Admin part */ if ( ! wp_doing_ajax() ) { new Prodigy_Admin_Setup_Wizard( $this->user ); } new Prodigy_Admin_Products_List(); new Prodigy_Admin_Categories_List(); new Prodigy_Admin_Settings(); new Prodigy_Admin_Attributes_List(); new Prodigy_Install_Demo_Content(); new Prodigy_Admin_Wizard(); } /** Frontend part */ new Prodigy_Themes_Support(); new Prodigy_Cart_Rules(); new Prodigy_Page( $this->order, $request_maker, $this->cart, $api_listener ); new Prodigy_Product_Page( $this->order, $request_maker, $this->cart, $api_listener ); new Prodigy_Cart_Page( $this->order, $request_maker, $this->cart, $error_handler, $api_listener ); $shop_product_data_mapper = new Prodigy_Shop_Products_Data_Mapper(); $active_filter = new Prodigy_Active_Filter_Data_Mapper(); $filter_data_mapper = new Prodigy_Filter_Data_Mapper(); $short_code_active_filter = new Prodigy_Short_Code_Active_Filter(); $price_filter = new Prodigy_Price_Filter_Data_Mapper(); new Prodigy_Shop_Page( $this->order, $request_maker, $this->cart, $api_listener, $shop_product_data_mapper, $active_filter, $filter_data_mapper, $short_code_active_filter, $price_filter ); new Prodigy_Buy_Now( $request_maker, $this->order, $this->cart ); new Prodigy_Punchout_Return(); /** Shortcodes part */ new Prodigy_Short_Code_Cart(); new Prodigy_Short_Code_Attributes_Filter(); new Prodigy_Short_Code_Price_Filter(); new Prodigy_Short_Code_Active_Filter(); new Prodigy_Short_Code_Breadcrumbs_List(); new Prodigy_Short_Code_Categories(); new Prodigy_Short_Code_Categories_Filter(); new Prodigy_Short_Code_Category_Link(); new Prodigy_Short_Code_My_Account(); new Prodigy_Short_Code_Products(); new Prodigy_Short_Code_Related_Products(); new Prodigy_Short_Code_Search(); new Prodigy_Short_Code_Cart_Page(); new Prodigy_Short_Code_Thank_You(); new Prodigy_Short_Code_Banner(); /** Main part */ new Prodigy_Customizer(); new Prodigy_Blocks(); new Prodigy_User_Content(); /** API */ new Prodigy_Api_Attributes(); new Prodigy_Api_Category(); new Prodigy_Api_Product(); new Prodigy_Api_Taxonomies(); new Prodigy_Product_Comments(); new Prodigy_Api_Product_Review(); new Prodigy_Api_Batch_Taxonomies(); new Prodigy_Api_Import(); new Prodigy_Api_Settings(); /** Helpers */ new Prodigy_Ajax(); } /** * Load global JS */ public function load_global_scripts(): void { wp_register_script( 'global', dirname( plugin_dir_url( __FILE__ ) ) . '/web/global/global.js', array( 'jquery' ), PRODIGY_VERSION, false ); wp_enqueue_script( 'global' ); wp_localize_script( 'global', 'data', array( 'site_url' => get_site_url(), 'url' => admin_url( 'admin-ajax.php' ), 'nonce' => wp_create_nonce( 'prodigyajax-nonce' ), 'post_type' => self::get_prodigy_product_type(), 'plugin_directory' => get_prodigy_plugin_directory_name(), ) ); } /** * Get the current prodigy product type (slug) * * @return string */ public static function get_prodigy_product_type(): string { return self::PRODIGY_POST_TYPE_DEFAULT; } /** * After installing the plugin, set the default field "Product categories" to active * appearance->menus->screen-options * * @param $result * @param $option * @param $user * * @return array */ public function custom_display_appearance_menus( $result, $option, $user ) { $current_type_category = self::get_prodigy_category_type(); if ( get_option( 'pg_appearance_menus_checked_first' ) < self::APPEARANCE_MENUS_CHECKED_FIRST ) { $prodigy_appearance_menus = (int) get_option( 'pg_appearance_menus_checked_first' ); ?> ID, 'metaboxhidden_nav-menus', $result ); } update_option( 'pg_appearance_menus_checked_first', ++$prodigy_appearance_menus ); } return $result; } /** * Get current prodigy category type (slug) * * @return string */ public static function get_prodigy_category_type(): string { return self::PRODIGY_TAXONOMY_CATEGORY_DEFAULT; } /** * Redirect on wizard after activated plugin * * @param $plugin */ public function prodigy_activation_redirect( $plugin ): void { if ( $plugin === PRODIGY_PLUGIN_DIRECTORY_NAME . '/prodigy-commerce.php' ) { $nonce = wp_create_nonce( 'wizard-form' ); $redirect_url = admin_url( 'index.php?page=prodigy-setup&_wpnonce=' . $nonce ); wp_redirect( sanitize_url( $redirect_url ) ); exit; } } /** * @return void * @throws \Exception */ public function prodigy_set_cart_cookie(): void { // Skip cart session setup for Elementor proxy requests // Hide elementor errors if ( isset( $_GET['screenshot_proxy'] ) ) { return; } $shop_page_uri = Prodigy_Url_Helper::prodigy_parse_request_uri(); if ( ! is_admin() && substr_count( $shop_page_uri, 'api-listener' ) && ! Prodigy_User::is_logged_in() ) { $this->cart->set_cart_user_session(); } } public function includes(): void { // Wizard. if ( isset( $_GET['page'] ) && $_GET['page'] === 'prodigy-setup' ) { require_once PRODIGY_PLUGIN_PATH . 'admin/class-prodigy-admin-setup-wizard.php'; } if ( isset( $_GET['prodigy-clear-wizard'] ) && $_GET['prodigy-clear-wizard'] == 1 ) { update_option( Prodigy_Admin_Setup_Wizard::OPTION_STEP_WIZARD, Prodigy_Admin_Setup_Wizard::DEFAULT_STEP ); } } /** * Register prodigy post type */ public function register_post_types(): void { add_post_type_support( self::get_prodigy_product_type(), 'thumbnail' ); $labels = array( 'menu_name' => __( 'Prodigy', 'prodigy-commerce' ), 'all_items' => __( 'Products', 'prodigy-commerce' ), 'name' => __( 'Prodigy Products', 'prodigy-commerce' ), ); register_post_type( self::PRODIGY_POST_TYPE_DEFAULT, array( 'labels' => $labels, 'description' => '', 'public' => true, 'hierarchical' => false, 'supports' => array( 'title', 'excerpt', 'thumbnail', 'comments' ), 'taxonomies' => array( self::PRODIGY_TAXONOMY_CATEGORY_DEFAULT, self::PRODIGY_TAXONOMY_TAG_DEFAULT ), 'has_archive' => false, 'rewrite' => array( 'slug' => self::get_prodigy_product_slug() ), 'query_var' => true, 'menu_icon' => 'dashicons-prodigy-logo', ) ); register_post_type( self::PRODIGY_VARIATION_POST_TYPE, array( 'label' => __( 'Variations', 'prodigy-commerce' ), 'public' => false, 'hierarchical' => false, 'supports' => false, 'rewrite' => false, ) ); do_action( 'prodigy_after_register_post_type' ); } /** * Get actual post-slug * * @return false|mixed|void */ public static function get_prodigy_product_slug() { return get_option( 'pg_product_type_slug', self::PRODIGY_DEFAULT_PRODUCT_SLUG ); } /** * Register prodigy taxonomies. */ public function register_taxonomies(): void { if ( ! is_blog_installed() ) { return; } if ( taxonomy_exists( self::get_prodigy_category_type() ) ) { return; } $labels = array( 'name' => __( 'Prodigy Product Categories', 'prodigy-commerce' ), 'singular_name' => __( 'Prodigy Category', 'prodigy-commerce' ), 'menu_name' => __( 'Categories', 'prodigy-commerce' ), 'search_items' => __( 'Search Categories', 'prodigy-commerce' ), 'all_items' => __( 'All Categories', 'prodigy-commerce' ), 'parent_item' => __( 'Parent Category', 'prodigy-commerce' ), 'parent_item_colon' => __( 'Parent Category', 'prodigy-commerce' ), 'edit_item' => __( 'Edit Category', 'prodigy-commerce' ), 'update_item' => __( 'Update Category', 'prodigy-commerce' ), 'add_new_item' => __( 'Add New Category', 'prodigy-commerce' ), 'new_item_name' => __( 'New Category Name', 'prodigy-commerce' ), 'not_found' => __( 'No Categories Found', 'prodigy-commerce' ), ); $args = array( 'hierarchical' => true, 'show_ui' => true, 'show_admin_column' => true, 'show_in_rest' => true, 'query_var' => true, 'label' => __( 'Categories', 'prodigy-commerce' ), 'labels' => $labels, 'capabilities' => array( 'pg_manage_terms' => 'pg_manage_product_terms', ), 'rewrite' => array( 'slug' => self::get_prodigy_category_slug(), ), ); register_taxonomy( self::PRODIGY_TAXONOMY_CATEGORY_DEFAULT, array( self::PRODIGY_POST_TYPE_DEFAULT ), $args ); $attributes = Prodigy_Product_Attributes::get_attribute_taxonomies(); if ( ! empty( $attributes ) ) { foreach ( $attributes as $attribute ) { $args = array( 'hierarchical' => false, 'show_ui' => false, 'show_admin_column' => false, 'query_var' => true, ); register_taxonomy( $attribute->slug, array( self::PRODIGY_POST_TYPE_DEFAULT ), $args ); } } } /** * Get actual taxonomy slug * * @return false|mixed|void */ public static function get_prodigy_category_slug() { return get_option( 'pg_category_type_slug', self::PRODIGY_DEFAULT_CATEGORY_SLUG ); } /** * Register prodigy tags */ public function register_tags(): void { $labels = array( 'name' => __( 'Prodigy Product Tags', 'prodigy-commerce' ), 'singular_name' => __( 'Prodigy Tag', 'prodigy-commerce' ), 'menu_name' => __( 'Tags', 'prodigy-commerce' ), 'search_items' => __( 'Search Tags', 'prodigy-commerce' ), 'all_items' => __( 'All Tags', 'prodigy-commerce' ), 'edit_item' => __( 'Edit Tag', 'prodigy-commerce' ), 'update_item' => __( 'Update Tag', 'prodigy-commerce' ), 'add_new_item' => __( 'Add New Tag', 'prodigy-commerce' ), 'new_item_name' => __( 'New Tag Name', 'prodigy-commerce' ), 'popular_items' => __( 'Popular Tags', 'prodigy-commerce' ), 'separate_items_with_commas' => __( 'Separate tags with commas', 'prodigy-commerce' ), 'add_or_remove_items' => __( 'Add or remove tags', 'prodigy-commerce' ), 'choose_from_most_used' => __( 'Choose from the most used tags', 'prodigy-commerce' ), 'not_found' => __( 'No tags found', 'prodigy-commerce' ), ); $args = array( 'hierarchical' => false, 'show_ui' => true, 'show_admin_column' => true, 'query_var' => true, 'label' => __( 'Product tags', 'prodigy-commerce' ), 'labels' => $labels, 'capabilities' => array( 'pg_manage_terms' => 'pg_manage_product_terms', ), 'rewrite' => array( 'slug' => self::get_prodigy_tag_slug(), ), ); register_taxonomy( self::PRODIGY_TAXONOMY_TAG_DEFAULT, array( self::PRODIGY_POST_TYPE_DEFAULT ), $args ); } /** * Get actual tag slug * * @return false|mixed|void */ public static function get_prodigy_tag_slug() { return get_option( 'pg_tag_type_slug', self::PRODIGY_DEFAULT_TAG_SLUG ); } /** * Register prodigy tags */ public function register_brands(): void { $args = array( 'hierarchical' => false, 'show_ui' => false, 'show_admin_column' => false, 'query_var' => true, 'label' => __( 'Product brands', 'prodigy-commerce' ), 'labels' => array(), 'rewrite' => array( 'slug' => self::get_prodigy_brand_slug(), ), ); register_taxonomy( self::PRODIGY_TAXONOMY_BRAND_DEFAULT, array( self::PRODIGY_POST_TYPE_DEFAULT ), $args ); } /** * Get actual taxonomy slug * * @return false|mixed|void */ public static function get_prodigy_brand_slug() { return get_option( 'pg_brand_type_slug', self::PRODIGY_DEFAULT_BRAND_SLUG ); } /** * Run the loader to execute all of the hooks with WordPress. * * @since 1.0.0 */ public function run() { $this->loader->run(); } /** * The reference to the class that orchestrates the hooks with the plugin. * * @return Prodigy_Loader Orchestrates the hooks of the plugin. * @since 1.0.0 */ public function get_loader() { return $this->loader; } /** * Initialize early taxonomy validation */ public function init_early_taxonomy_validation(): void { add_action( 'template_redirect', array( $this, 'validate_taxonomy_terms_early' ), 1 ); } /** * Validate taxonomy terms early in the request cycle */ public function validate_taxonomy_terms_early() { if ( is_admin() || wp_doing_ajax() || wp_doing_cron() ) { return; } // Skip validation for Elementor proxy requests // Hide elementor errors if ( isset( $_GET['screenshot_proxy'] ) ) { return; } Prodigy_Url_Helper::validate_prodigy_taxonomy_url(); } }