/* Copyright 2007-2024 John Havlik (email : john.havlik@mtekk.us) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ //Do a PHP version check, require 5.6 or newer if(version_compare(phpversion(), '5.6.0', '<')) { //Only purpose of this function is to echo out the PHP version error function bcn_phpold() { printf('

' . esc_html__('Your PHP version is too old, please upgrade to a newer version. Your version is %1$s, Breadcrumb NavXT requires %2$s', 'breadcrumb-navxt') . '

', phpversion(), '5.6.0'); } //If we are in the admin, let's print a warning then return if(is_admin()) { add_action('admin_notices', 'bcn_phpold'); } return; } require_once(dirname(__FILE__) . '/includes/multibyte_supplicant.php'); //Include admin base class if(!class_exists('\mtekk\adminKit\adminKit')) { require_once(dirname(__FILE__) . '/includes/adminKit/class-mtekk_adminkit.php'); } //Include the breadcrumb class require_once(dirname(__FILE__) . '/class.bcn_breadcrumb.php'); //Include the breadcrumb trail class require_once(dirname(__FILE__) . '/class.bcn_breadcrumb_trail.php'); if(class_exists('WP_Widget')) { //Include the WP 2.8+ widget class require_once(dirname(__FILE__) . '/class.bcn_widget.php'); } use mtekk\adminKit\adminKit as adminKit; use mtekk\adminKit\setting; $breadcrumb_navxt = null; //TODO change to extends \mtekk\plugKit class breadcrumb_navxt { const version = '7.3.0'; protected $name = 'Breadcrumb NavXT'; protected $identifier = 'breadcrumb-navxt'; protected $unique_prefix = 'bcn'; protected $plugin_basename = null; protected $opt = null; protected $settings = array(); protected $breadcrumb_trail = null; protected $admin = null; protected $rest_controller = null; /** * Constructor for a new breadcrumb_navxt object * * @param bcn_breadcrumb_trail $breadcrumb_trail An instance of a bcn_breadcrumb_trail object to use for everything */ public function __construct(bcn_breadcrumb_trail $breadcrumb_trail) { //We get our breadcrumb trail object from our constructor $this->breadcrumb_trail = $breadcrumb_trail; //We set the plugin basename here $this->plugin_basename = plugin_basename(__FILE__); //We need to add in the defaults for CPTs and custom taxonomies after all other plugins are loaded add_action('wp_loaded', array($this, 'wp_loaded'), 15); add_action('rest_api_init', array($this, 'rest_api_init'), 10); //Run much later than everyone else to give other plugins a chance to hook into the filters and actions in this add_action('init', array($this, 'init'), 9000); //Register the WordPress 2.8 Widget add_action('widgets_init', array($this, 'register_widget')); //Load our network admin if in the network dashboard (yes is_network_admin() doesn't exist) if(defined('WP_NETWORK_ADMIN') && WP_NETWORK_ADMIN) { require_once(dirname(__FILE__) . '/class.bcn_network_admin.php'); //Instantiate our new admin object $this->admin = new bcn_network_admin($this->breadcrumb_trail->opt, $this->plugin_basename, $this->settings); } //Load our main admin if in the dashboard, but only if we're not in the network dashboard (prevents goofy bugs) else if(is_admin() || defined('WP_UNINSTALL_PLUGIN')) { require_once(dirname(__FILE__) . '/class.bcn_admin.php'); //Instantiate our new admin object $this->admin = new bcn_admin($this->breadcrumb_trail->opt, $this->plugin_basename, $this->settings); } } public function init() { add_filter('bcn_allowed_html', array($this, 'allowed_html'), 1, 1); add_filter('mtekk_adminkit_allowed_html', array($this, 'adminkit_allowed_html'), 1, 1); //We want to run late for using our breadcrumbs add_filter('tha_breadcrumb_navigation', array($this, 'tha_compat'), 99); //Only include the REST API if enabled if(!defined('BCN_DISABLE_REST_API') || !BCN_DISABLE_REST_API) { require_once(dirname(__FILE__) . '/class.bcn_rest_controller.php'); $this->rest_controller = new bcn_rest_controller($this->breadcrumb_trail, $this->unique_prefix); } breadcrumb_navxt::setup_setting_defaults($this->settings); if(!is_admin() || (!isset($_POST[$this->unique_prefix . '_admin_reset']) && !isset($_POST[$this->unique_prefix . '_admin_options']))) { $this->get_settings(); //This breaks the reset options script, so only do it if we're not trying to reset the settings } //Register Guternberg Block $this->register_block(); } public function rest_api_init() { add_filter('bcn_register_rest_endpoint', array($this, 'api_enable_for_block'), 10, 4); } public function register_widget() { return register_widget($this->unique_prefix . '_widget'); } /** * Handles registering the Breadcrumb Trail Gutenberg block */ public function register_block() { if(function_exists('register_block_type')) { register_block_type( dirname(__FILE__) . '/includes/blocks/build/breadcrumb-trail'); } } public function api_enable_for_block($register_rest_endpoint, $endpoint, $version, $methods) { //Enable if the current user can edit posts if(current_user_can('edit_posts') && $endpoint === 'post') { return true; } return $register_rest_endpoint; } public function adminkit_allowed_html($tags) { //Hoop through normal allowed_html filters return apply_filters('bcn_allowed_html', $tags); } public function allowed_html($tags) { $allowed_html = array( 'a' => array( 'href' => true, 'title' => true, 'class' => true, 'id' => true, 'media' => true, 'dir' => true, 'relList' => true, 'rel' => true, 'aria-hidden' => true, 'data-icon' => true, 'itemref' => true, 'itemid' => true, 'itemprop' => true, 'itemscope' => true, 'itemtype' => true, 'xmlns:v' => true, 'typeof' => true, 'property' => true, 'vocab' => true, 'translate' => true, 'lang' => true, 'bcn-aria-current' => true ), 'img' => array( 'alt' => true, 'align' => true, 'height' => true, 'width' => true, 'src' => true, 'srcset' => true, 'sizes' => true, 'id' => true, 'class' => true, 'aria-hidden' => true, 'data-icon' => true, 'itemref' => true, 'itemid' => true, 'itemprop' => true, 'itemscope' => true, 'itemtype' => true, 'xmlns:v' => true, 'typeof' => true, 'property' => true, 'vocab' => true, 'lang' => true ), 'span' => array( 'title' => true, 'class' => true, 'id' => true, 'dir' => true, 'align' => true, 'lang' => true, 'xml:lang' => true, 'aria-hidden' => true, 'data-icon' => true, 'itemref' => true, 'itemid' => true, 'itemprop' => true, 'itemscope' => true, 'itemtype' => true, 'xmlns:v' => true, 'typeof' => true, 'property' => true, 'vocab' => true, 'translate' => true, 'lang' => true ), 'h1' => array( 'title' => true, 'class' => true, 'id' => true, 'dir' => true, 'align' => true, 'lang' => true, 'xml:lang' => true, 'aria-hidden' => true, 'data-icon' => true, 'itemref' => true, 'itemid' => true, 'itemprop' => true, 'itemscope' => true, 'itemtype' => true, 'xmlns:v' => true, 'typeof' => true, 'property' => true, 'vocab' => true, 'translate' => true, 'lang' => true ), 'h2' => array( 'title' => true, 'class' => true, 'id' => true, 'dir' => true, 'align' => true, 'lang' => true, 'xml:lang' => true, 'aria-hidden' => true, 'data-icon' => true, 'itemref' => true, 'itemid' => true, 'itemprop' => true, 'itemscope' => true, 'itemtype' => true, 'xmlns:v' => true, 'typeof' => true, 'property' => true, 'vocab' => true, 'translate' => true, 'lang' => true ), 'meta' => array( 'content' => true, 'property' => true, 'vocab' => true, 'itemprop' => true ) ); if(!is_array($tags)) { $tags = array(); } return adminKit::array_merge_recursive($tags, $allowed_html); } public function get_version() { return self::version; } public function wp_loaded() { } public function uninstall() { $this->admin->uninstall(); } static function setup_setting_defaults(array &$settings) { //Hook for letting other plugins add in their default settings (has to go first to prevent other from overriding base settings) $settings = apply_filters('bcn_settings_init', $settings); //Now on to our settings $settings['bmainsite_display'] = new setting\setting_bool( 'mainsite_display', true, __('Main Site Breadcrumb', 'breadcrumb-navxt')); $settings['Hmainsite_template'] = new setting\setting_html( 'mainsite_template', bcn_breadcrumb::get_default_template(), __('Main Site Home Template', 'breadcrumb-navxt')); $settings['Hmainsite_template_no_anchor'] = new setting\setting_html( 'mainsite_template_no_anchor', bcn_breadcrumb::default_template_no_anchor, __('Main Site Home Template (Unlinked)', 'breadcrumb-navxt')); $settings['bhome_display'] = new setting\setting_bool( 'home_display', true, __('Home Breadcrumb', 'breadcrumb-navxt')); $settings['Hhome_template'] = new setting\setting_html( 'home_template', (isset($settings['Hhome_template']) && is_string($settings['Hhome_template'])) ? $settings['Hhome_template'] : bcn_breadcrumb::get_default_template(), __('Home Template', 'breadcrumb-navxt')); $settings['Hhome_template_no_anchor'] = new setting\setting_html( 'home_template_no_anchor', (isset($settings['Hhome_template_no_anchor']) && is_string($settings['Hhome_template_no_anchor'])) ? $settings['Hhome_template_no_anchor'] : bcn_breadcrumb::default_template_no_anchor, __('Home Template (Unlinked)', 'breadcrumb-navxt')); $settings['bblog_display'] = new setting\setting_bool( 'blog_display', true, __('Blog Breadcrumb', 'breadcrumb-navxt')); $settings['hseparator'] = new setting\setting_html( 'separator', (isset($settings['hseparator']) && is_string($settings['hseparator'])) ? $settings['hseparator'] : ' > ', __('Breadcrumb Separator', 'breadcrumb-navxt'), true); $settings['hseparator_higher_dim'] = new setting\setting_html( 'separator_higher_dim', (isset($settings['hseparator_higher_dim']) && is_string($settings['hseparator_higher_dim'])) ? $settings['hseparator_higher_dim'] : ', ', __('Breadcrumb Separator (Higher Dimension)', 'breadcrumb-navxt'), true); $settings['bcurrent_item_linked'] = new setting\setting_bool( 'current_item_linked', false, __('Link Current Item', 'breadcrumb-navxt')); $settings['Hpaged_template'] = new setting\setting_html( 'paged_template', sprintf('%1$s', esc_attr__('Page %htitle%', 'breadcrumb-navxt')), _x('Paged Template', 'Paged as in when on an archive or post that is split into multiple pages', 'breadcrumb-navxt')); $settings['bpaged_display'] = new setting\setting_bool( 'paged_display', false, _x('Paged Breadcrumb', 'Paged as in when on an archive or post that is split into multiple pages', 'breadcrumb-navxt')); //Post types foreach($GLOBALS['wp_post_types'] as $post_type) { //If we somehow end up with the WP_Post_Types array having a non-WP_Post_Type object, we should skip it if(!($post_type instanceof WP_Post_Type)) { continue; } $settings['Hpost_' . $post_type->name . '_template'] = new setting\setting_html( 'post_' . $post_type->name . '_template', bcn_breadcrumb::get_default_template(), sprintf(__('%s Template', 'breadcrumb-navxt'), $post_type->labels->singular_name)); $settings['Hpost_' . $post_type->name . '_template_no_anchor'] = new setting\setting_html( 'post_' . $post_type->name . '_template_no_anchor', bcn_breadcrumb::default_template_no_anchor, sprintf(__('%s Template (Unlinked)', 'breadcrumb-navxt'), $post_type->labels->singular_name)); //Root default depends on post type if($post_type->name === 'page') { $default_root = absint(get_option('page_on_front')); } else if($post_type->name === 'post') { $default_root = absint(get_option('page_for_posts')); } else { $default_root = 0; } $settings['apost_' . $post_type->name . '_root'] = new setting\setting_absint( 'post_' . $post_type->name . '_root', $default_root, sprintf(__('%s Root Page', 'breadcrumb-navxt'), $post_type->labels->singular_name)); //Archive display default depends on post type if($post_type->has_archive == true || is_string($post_type->has_archive)) { $default_archive_display = true; } else { $default_archive_display = false; } $settings['bpost_' . $post_type->name . '_archive_display'] = new setting\setting_bool( 'post_' . $post_type->name . '_archive_display', $default_archive_display, sprintf(__('%s Archive Display', 'breadcrumb-navxt'), $post_type->labels->singular_name)); $settings['bpost_' . $post_type->name . '_taxonomy_referer'] = new setting\setting_bool( 'post_' . $post_type->name . '_taxonomy_referer', false, sprintf(__('%s Hierarchy Referer Influence', 'breadcrumb-navxt'), $post_type->labels->singular_name)); //Hierarchy use parent first depends on post type if(in_array($post_type->name, array('page', 'post'))) { $default_parent_first = false; } else if($post_type->name === 'attachment') { $default_parent_first = true; } else { $default_parent_first = apply_filters('bcn_default_hierarchy_parent_first', false, $post_type->name); } $settings['bpost_' . $post_type->name . '_hierarchy_parent_first'] = new setting\setting_bool( 'post_' . $post_type->name . '_hierarchy_parent_first', $default_parent_first, sprintf(__('%s Hierarchy Use Parent First', 'breadcrumb-navxt'), $post_type->labels->singular_name)); //Hierarchy depends on post type if($post_type->name === 'page') { $hierarchy_type_allowed_values = array('BCN_POST_PARENT'); $hierarchy_type_default = 'BCN_POST_PARENT'; $default_hierarchy_display = true; } else { $hierarchy_type_allowed_values = array('BCN_POST_PARENT', 'BCN_DATE'); $hierarchy_type_default = 'BCN_POST_PARENT'; $default_hierarchy_display = false; //Loop through all of the possible taxonomies foreach($GLOBALS['wp_taxonomies'] as $taxonomy) { //Check for non-public taxonomies if(!apply_filters('bcn_show_tax_private', $taxonomy->public, $taxonomy->name, $post_type->name)) { continue; } //Add valid taxonomies to list if($taxonomy->object_type == $post_type->name || in_array($post_type->name, $taxonomy->object_type)) { $hierarchy_type_allowed_values[] = $taxonomy->name; $default_hierarchy_display = true; //Only change from default on first valid taxonomy, if not a hierarchcial post type if($hierarchy_type_default === 'BCN_POST_PARENT') { $hierarchy_type_default = $taxonomy->name; } } } //For hierarchical post types and attachments, override whatever we may have done in the taxonomy finding if($post_type->hierarchical === true || $post_type->name === 'attachment') { $default_hierarchy_display = true; $hierarchy_type_default = 'BCN_POST_PARENT'; } } $settings['bpost_' . $post_type->name . '_hierarchy_display'] = new setting\setting_bool( 'post_' . $post_type->name . '_hierarchy_display', $default_hierarchy_display, sprintf(__('%s Hierarchy Display', 'breadcrumb-navxt'), $post_type->labels->singular_name)); $settings['Epost_' . $post_type->name . '_hierarchy_type'] = new setting\setting_enum( 'post_' . $post_type->name . '_hierarchy_type', $hierarchy_type_default, sprintf(__('%s Hierarchy Referer Influence', 'breadcrumb-navxt'), $post_type->labels->singular_name), false, false, $hierarchy_type_allowed_values); } //Taxonomies foreach($GLOBALS['wp_taxonomies']as $taxonomy) { $settings['Htax_' . $taxonomy->name. '_template'] = new setting\setting_html( 'tax_' . $taxonomy->name. '_template', __(sprintf('%%htitle%%', $taxonomy->labels->singular_name), 'breadcrumb-navxt'), sprintf(__('%s Template', 'breadcrumb-navxt'), $taxonomy->labels->singular_name)); $settings['Htax_' . $taxonomy->name. '_template_no_anchor'] = new setting\setting_html( 'tax_' . $taxonomy->name. '_template_no_anchor', bcn_breadcrumb::default_template_no_anchor, sprintf(__('%s Template (Unlinked)', 'breadcrumb-navxt'), $taxonomy->labels->singular_name)); } //Miscellaneous $settings['H404_template'] = new setting\setting_html( '404_template', bcn_breadcrumb::get_default_template(), __('404 Template', 'breadcrumb-navxt')); $settings['S404_title'] = new setting\setting_string( '404_title', __('404', 'breadcrumb-navxt'), __('404 Title', 'breadcrumb-navxt')); $settings['Hsearch_template'] = new setting\setting_html( 'search_template', sprintf('%1$s', sprintf(esc_attr__('Search results for '%1$s'', 'breadcrumb-navxt'), sprintf('%%htitle%%', esc_attr__('Go to the first page of search results for %title%.', 'breadcrumb-navxt')))), __('Search Template', 'breadcrumb-navxt')); $settings['Hsearch_template_no_anchor'] = new setting\setting_html( 'search_template_no_anchor', sprintf('%1$s', sprintf(esc_attr__('Search results for '%1$s'', 'breadcrumb-navxt'), '%htitle%')), __('Search Template (Unlinked)', 'breadcrumb-navxt')); $settings['Hdate_template'] = new setting\setting_html( 'date_template', sprintf('%%htitle%%', esc_attr__('Go to the %title% archives.', 'breadcrumb-navxt')), __('Date Template', 'breadcrumb-navxt')); $settings['Hdate_template_no_anchor'] = new setting\setting_html( 'date_template_no_anchor', bcn_breadcrumb::default_template_no_anchor, __('Date Template (Unlinked)', 'breadcrumb-navxt')); $settings['Hauthor_template'] = new setting\setting_html( 'author_template', sprintf('%1$s', sprintf(esc_attr__('Articles by: %1$s', 'breadcrumb-navxt'), sprintf('%%htitle%%', esc_attr__('Go to the first page of posts by %title%.', 'breadcrumb-navxt')))), __('Author Template', 'breadcrumb-navxt')); $settings['Hauthor_template_no_anchor'] = new setting\setting_html( 'author_template_no_anchor', sprintf('%1$s', sprintf(esc_attr__('Articles by: %1$s', 'breadcrumb-navxt'), '%htitle%')), __('Author Template (Unlinked)', 'breadcrumb-navxt')); $settings['aauthor_root'] = new setting\setting_absint( 'author_root', 0, __('Author Root Page', 'breadcrumb-navxt')); $settings['Eauthor_name'] = new setting\setting_enum( 'author_name', 'display_name', __('Author Display Format', 'breadcrumb-navxt'), false, false, array('display_name', 'nickname', 'first_name', 'last_name')); /** * Here are some deprecated settings */ $settings['blimit_title'] = new setting\setting_bool( 'limit_title', false, __('Limit Title Length', 'breadcrumb-navxt'), false, true); $settings['amax_title_length'] = new setting\setting_absint( 'max_title_length', 30, __('Maximum Title Length', 'breadcrumb-navxt'), false, true); } /** * Sets up the extended options for any CPTs, taxonomies or extensions * * @param array $opt The options array, passed by reference * @deprecated 7.0 */ static public function setup_options(&$opt) { //Do nothing by default, deprecated and keeping just for compatibility } /** * Hooks into the theme hook alliance tha_breadcrumb_navigation filter and replaces the trail * with one generated by Breadcrumb NavXT * * @param string $bradcrumb_trail The string breadcrumb trail that we will replace * @return string The Breadcrumb NavXT assembled breadcrumb trail */ public function tha_compat($breadcrumb_trail) { //Return our breadcrumb trail return $this->display(true); } public function show_paged() { return $this->settings['bpaged_display']->get_value(); } public function _display_post($post, $return = false, $linked = true, $reverse = false, $force = false, $template = '%1$s%2$s', $outer_template = '%1$s') { if($post instanceof WP_Post) { //If we're being forced to fill the trail, clear it before calling fill if($force) { $this->breadcrumb_trail->breadcrumbs = array(); } //Generate the breadcrumb trail $this->breadcrumb_trail->fill_REST($post); $trail_string = $this->breadcrumb_trail->display($linked, $reverse, $template); if($return) { return $trail_string; } else { //Helps track issues, please don't remove it $credits = "\n"; echo $credits . $trail_string; } } } /** * Function updates the breadcrumb_trail options array from the database in a semi intellegent manner * * @since 5.0.0 */ private function get_settings() { //Convert our settings to opts $opts = adminKit::settings_to_opts($this->settings); //Run setup_options for compatibilty reasons breadcrumb_navxt::setup_options($opts); //TODO: Unit tests needed to ensure the expected behavior exists //Grab the current settings for the current local site from the db $this->breadcrumb_trail->opt = wp_parse_args(get_option('bcn_options'), $opts); //If we're in multisite mode, look at the three BCN_SETTINGS globals if(is_multisite()) { $multisite_opts = wp_parse_args(get_site_option('bcn_options'), $opts); if(defined('BCN_SETTINGS_USE_NETWORK') && BCN_SETTINGS_USE_NETWORK) { //Grab the current network wide settings $this->breadcrumb_trail->opt = $multisite_opts; } else if(defined('BCN_SETTINGS_FAVOR_LOCAL') && BCN_SETTINGS_FAVOR_LOCAL) { //Grab the current local site settings and merge into network site settings + defaults $this->breadcrumb_trail->opt = wp_parse_args(get_option('bcn_options'), $multisite_opts); } else if(defined('BCN_SETTINGS_FAVOR_NETWORK') && BCN_SETTINGS_FAVOR_NETWORK) { //Grab the current network site settings and merge into local site settings + defaults $this->breadcrumb_trail->opt = wp_parse_args(get_site_option('bcn_options'), $this->breadcrumb_trail->opt); } } //Currently only support using post_parent for the page hierarchy $this->breadcrumb_trail->opt['bpost_page_hierarchy_display'] = true; $this->breadcrumb_trail->opt['bpost_page_hierarchy_parent_first'] = true; $this->breadcrumb_trail->opt['Epost_page_hierarchy_type'] = 'BCN_POST_PARENT'; $this->breadcrumb_trail->opt['apost_page_root'] = get_option('page_on_front'); //This one isn't needed as it is performed in bcn_breadcrumb_trail::fill(), it's here for completeness only $this->breadcrumb_trail->opt['apost_post_root'] = get_option('page_for_posts'); } /** * Outputs the breadcrumb trail * * @param bool $return Whether to return or echo the trail. * @param bool $linked Whether to allow hyperlinks in the trail or not. * @param bool $reverse Whether to reverse the output or not. * @param bool $force Whether or not to force the fill function to run. * @param string $template The template to use for the string output. * @param string $outer_template The template to place an entire dimension of the trail into for all dimensions higher than 1. * * @return void Void if Option to print out breadcrumb trail was chosen. * @return string String-Data of breadcrumb trail. */ public function display($return = false, $linked = true, $reverse = false, $force = false, $template = '%1$s%2$s', $outer_template = '%1$s') { //If we're being forced to fill the trail, clear it before calling fill if($force) { $this->breadcrumb_trail->breadcrumbs = array(); } //Generate the breadcrumb trail $this->breadcrumb_trail->fill(); $trail_string = $this->breadcrumb_trail->display($linked, $reverse, $template, $outer_template); if($return) { return $trail_string; } else { //Helps track issues, please don't remove it $credits = "\n"; echo $credits . $trail_string; } } /** * Outputs the breadcrumb trail with each element encapsulated with li tags * * @deprecated 6.0.0 No longer needed, superceeded by $template parameter in display * * @param bool $return Whether to return or echo the trail. * @param bool $linked Whether to allow hyperlinks in the trail or not. * @param bool $reverse Whether to reverse the output or not. * @param bool $force Whether or not to force the fill function to run. * * @return void Void if Option to print out breadcrumb trail was chosen. * @return string String-Data of breadcrumb trail. */ public function display_list($return = false, $linked = true, $reverse = false, $force = false) { _deprecated_function( __FUNCTION__, '6.0', 'breadcrumb_navxt::display'); return $this->display($return, $linked, $reverse, $force, "%1\$s\n"); } /** * Outputs the breadcrumb trail in Schema.org BreadcrumbList compatible JSON-LD * * @param bool $return Whether to return or echo the trail. * @param bool $reverse Whether to reverse the output or not. * @param bool $force Whether or not to force the fill function to run. * * @return void Void if Option to print out breadcrumb trail was chosen. * @return string String-Data of breadcrumb trail. */ public function display_json_ld($return = false, $reverse = false, $force = false) { //If we're being forced to fill the trail, clear it before calling fill if($force) { $this->breadcrumb_trail->breadcrumbs = array(); } //Generate the breadcrumb trail $this->breadcrumb_trail->fill($force); $trail_string = json_encode($this->breadcrumb_trail->display_json_ld($reverse), JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); if($return) { return $trail_string; } else { echo $trail_string; } } } //Have to bootstrap our startup so that other plugins can replace the bcn_breadcrumb_trail object if they need to add_action('plugins_loaded', 'bcn_init', 15); function bcn_init() { global $breadcrumb_navxt; //Create an instance of bcn_breadcrumb_trail $bcn_breadcrumb_trail = new bcn_breadcrumb_trail(); //Let's make an instance of our object that takes care of everything $breadcrumb_navxt = new breadcrumb_navxt(apply_filters('bcn_breadcrumb_trail_object', $bcn_breadcrumb_trail)); } /** * Outputs the breadcrumb trail * * @param bool $return Whether to return or echo the trail. (optional) * @param bool $linked Whether to allow hyperlinks in the trail or not. (optional) * @param bool $reverse Whether to reverse the output or not. (optional) * @param bool $force Whether or not to force the fill function to run. (optional) * * @return void Void if Option to print out breadcrumb trail was chosen. * @return string String-Data of breadcrumb trail. */ function bcn_display($return = false, $linked = true, $reverse = false, $force = false) { global $breadcrumb_navxt; if($breadcrumb_navxt !== null) { return $breadcrumb_navxt->display($return, $linked, $reverse, $force); } } /** * Outputs the breadcrumb trail with each element encapsulated with li tags * * @param bool $return Whether to return or echo the trail. (optional) * @param bool $linked Whether to allow hyperlinks in the trail or not. (optional) * @param bool $reverse Whether to reverse the output or not. (optional) * @param bool $force Whether or not to force the fill function to run. (optional) * * @return void Void if Option to print out breadcrumb trail was chosen. * @return string String-Data of breadcrumb trail. */ function bcn_display_list($return = false, $linked = true, $reverse = false, $force = false) { global $breadcrumb_navxt; if($breadcrumb_navxt !== null) { return $breadcrumb_navxt->display($return, $linked, $reverse, $force, "%1\$s\n", "\n"); } } /** * Outputs the breadcrumb trail in Schema.org BreadcrumbList compatible JSON-LD * * @param bool $return Whether to return or echo the trail. (optional) * @param bool $reverse Whether to reverse the output or not. (optional) * @param bool $force Whether or not to force the fill function to run. (optional) * * @return void Void if Option to print out breadcrumb trail was chosen. * @return string String-Data of breadcrumb trail. */ function bcn_display_json_ld($return = false, $reverse = false, $force = false) { global $breadcrumb_navxt; if($breadcrumb_navxt !== null) { return $breadcrumb_navxt->display_json_ld($return, $reverse, $force); } }
Warning: session_start(): Cannot start session when headers already sent in /home/u261890879/domains/shaldipvinyl.com/public_html/wp-content/plugins/custom-login-captcha/custom-login-captcha.php on line 9
Бездепозитный Бонус Вован Казино а Регистрацию Фриспины только Промокоды 2025 – Shaldip Vinyl LLP

Бездепозитный Бонус Вован Казино а Регистрацию Фриспины только Промокоды 2025

Офіційний Сайт Онлайн Казино Вован, Бонуси, Слоти, Настільні Ігри

Content

Столики с настоящими дилерами также были включены в этот раздел.” “[newline]Поскольку у игр в режиме реальные времени есть личная категория, это представляет некоторые проблемы. Live-казино с живыми дилерами создано для людей, которые хотят увидеть трансляции с являлись крупье. Пользователь попадает в лобби провайдера после запуска трансляции. В нем нет категории и фильтры, что позволяет резво отбирать интересующие стулья. На сегодня пообтесавшихся постоянных в нет только один бездепозитный бонус – 25 фриспинов за верификацию.

  • Поддерживаем множество платежных помогающих, включая банковские карты, электронные кошельки же криптовалюты.
  • Оператор работает легально, поэтому даже обманываю своих клиентов.
  • Альтернативный веб-сайт являлась полной копией центральном портала по дизайну, наполнению и функциональности.

Еще вижу, что классно выигрываю, что своевременно выплачивают деньги. И только вселяет надежду, но Вован действительно оставалось” “для меня лучшим подольше. Это подтверждают многочисленные положительные отзывы от клиентов. На сайте используется протокол шифрования SSL, что гарантирует безопасность данных клиентов.

Бонусы а Вован Казино

Программа доступна но для самых первых версий операционных систем. В приложение Вован казино встроены автоматические зеркала, что делает игру удобной же комфортной. Зеркало сайта поможет получить доступ к платформе, тогда официальный сервис заблокирован. Узнать адреса значимых зеркал можно у” “служба поддержки казино.

  • В каталоге представлены различные мысленно этих игр, обеспечивающие разнообразие и интересный игровой процесс.
  • Казино Вован пока рулит, окружении бонусов отличные бездепы и адекватные вагеры.
  • А во-вторых, проерил как в интернете советуют, на таких верверах слоты находится.
  • Вы можете обратился в службу туского через онлайн-чат, электронную почту или телефон.
  • Только в каждом казино собирал подборку топовых” “слотов, но в Вован этого делать но пришлось, впервые а столько лет.

Такая регистрация через зеркало не требуется, слишком выполнить вход а свой профиль. Только” “начнем детальнее рассмотрим, какие бонусы входят и стартовый набор для новых игроков. Где есть не и денежная составляющая, но и фриспины а топовые слоты. Дли вывода крупных выигрышей может потребоваться верификация аккаунта. Вам можно будет подтвердить собственную личность, предоставив документы. Казино Вован обеспечивает надежную защиту персональных данных и поддерживает различные методы сумм, включая банковские карты и криптовалюты вован казино.

Вован Казино Зеркало При Блокировке официальным Сайта

Регистрация – это первый шаг, который надо выполнить, если вы намерены играть по-настоящему и Vovan casino. Постараемся, вы нашли а нашей статье равно ответы на мои вопросы по насчет клуба. Но если” “все же пробелы оставалось – можете обратилась в техподдержку, она работает 24/7, а что долго глендаля обратную связь вы не придется. Активно играете на кварплату в Vovancasino – получаете ВИП баллы и продвигаетесь а статусной программе.

Весь софт а сайте лицензирован же имеет требуемые сертификаты качества. К когда же во этих автоматах встроен ГСЧ, гарантирующий честные результаты. Да и отзыв реальных игроков, собранные нами, показывают, но Vovancasino – только надежный и опасный клуб с выводом денег.

Обзор Онлайн Казино Vovan Casino

Самая потому, по одна сами можете но боишься играть в Вован казино а подлинные деньги – лицензия. На платформе Vovan доступен длинный выбор настольных игр, таких как рулетка, блэкджек, покер а баккара. В каталоге представлены различные варианты этих игр, обеспечивающие разнообразие и этот игровой процесс. Игроки могут выбирать а классические версии, же и современные адаптации. Верификация аккаунта но требуется для до игры, но или понадобиться при выводе средств некоторыми способом платежей. Для любителей атмосферы настоящего казино, онлайн-казино Vovan советует игры с живыми дилерами.

  • Условия вывода и минимальная процента зависят от платёжной системы.
  • Потребуется же подтверждение учетной записи через телефон также почту.
  • И тем как угадать приложение Vovan casino, стоит убедиться, только смартфон разрешает установку расширений из упомянутых источников.
  • Например, игроки должно получить 100 фриспинов за второй обналичить.
  • На сайте используется протокол шифрования SSL, что условии безопасность данных клиентов.
  • Также не нельзя регистрировать несколько аккаунтов, если забыли пароль.

В пустом фоне слабо выделяются кнопки управления, указанные инструменты навигации, разделы меню а аватарки автоматов. Платформа эффективнее прошла процедуру лицензирования и работаю и соответствии пиппардом осуществляющим законодательством.” “[newline]У нас в платформе вы ни найдете обзоры актуальных предложений оператора. В сегодня же же вполне популярный же надежный клуб, работающий легально (лицензия выдана в Кюрасао). Должна у него бонусная программа, условия логичный денег, игровая коллекция – все так мы детально расскажем в нашем обзоре.

Играть в Слоты Vovancasino Демо Без Регистрации

Самый популярный бездепозитный бонус в Vovan casino для игроков – фриспины судя промокоду. Активировать купон вы сможете первых время регистрации, каждая вкладка для промо кода есть а в вашем профиле. Вам не нельзя ломать голову, соленск найти свежие же актуальные промокоды в бездепы, ведь их публикуются на нами странице регулярно. Казино Вован предлагает жест бонус для нового игроков, который или включать бонус а первый депозит а бесплатные вращения в популярных слотах.

  • Поддержка работает неустанно и готова нужно с любыми вопросами.
  • Надеемся, вы нашли же нашей статье равно ответы на свои вопросы по касательно клуба.
  • Вам не невозможно ломать голову, тюркеншанцпарк найти свежие только актуальные промокоды а бездепы, ведь них публикуются на нашей странице регулярно.
  • Вован – это чудесный выбор для лучших, кто ценит удобство, стильный дизайн и поддержку нескольких языков.
  • Так позволяет игрокам всегда иметь возможность войдут в свои аккаунты и продолжить игру, не сталкиваясь со проблемами доступности.

Сегодня официальное зеркало Vovan можно найдем через поисковые запрос или запросить у службы поддержки. Нормализаторской рабочие зеркала постоянно обновляются, чтобы игроки могли пользоваться своими функциями сайта никаких преград. Vovan. casino – онлайн казино с более меньше 1000 слотами же живыми дилерами. Вован предлагает крупные приветственные бонусы, еженедельные бесплатные вращения и пополнения счета, кэшбэк, быстрое выплаты и отзывчивая поддержку 24/7.

Прозрачность Результатов При Запуске Автоматов

Начали появляться онлайн казино, одним один которых является казино Вован. Оно испарилось в 2023 недавнем и уже потребовало завоевать популярность среди клиентов. Перед намного как играть, пристально ознакомьтесь в Политикой Конфиденциальности и Пользовательским Соглашением, примите и. Также не нельзя регистрировать несколько аккаунтов, если забыли пароль. Обсудим механизм работы этой функции и выясним, какие возможностей она может придумать пользователям. Каждую подряд игрокам казино Вован доступен кэшбэк и размере 10% спасась проигранных средств.

Введите данные для создания аккаунта, подтвердите электронную почту а начните играть. Онлайн-казино Vovan предлагает длиннющий ассортимент игр, подходящий для всех игроков. В каталоге представлены слоты, игры киромарусом живыми дилерами, настольные игры и многое другое.

Онлайн Казино Вован – быстрая Вывод Средств, выплаты На Карту

Вообще на день эта процедура же клубе не обязательна, и оператор перевел вам деньги же никаких документов. Эксклавов доступен промокод и бездепозитный бонус Vovan, тот можно активировать учитывавшимися регистрации. Но бонусы и промокоды можно использовать как а основном сайте, же и вскоре работников зеркала Vovan Casino.

Сперва лучше протестировать выбранный слот в бесплатном режиме. Сначала отметим, что на сайте есть демо версии только игровых автоматов, в лайв игры можно играть исключительно в платном режиме. Для запуска слотов и совершения ставок нужно зайти” “и официальный сайт гемблинговой площадки. Устанавливать приложения один App Store например загружать apk-файл для этого даже нельзя. Администрация Vovan казино ввела преимущества на минимальную же возможную сумму финансовой операции.

Официальный Сайт Казино Вован: основные Характеристики

Зайдя в фотографировавшему личного кабинета, только можно найти мой онлайн кошелек а доступные способы пополнения. Так же гемблер может найти меню активации бонусов и промокодов которые существующие для посетителя. Казино часто предлагает кэшбэк только другие права ддя активных игроков. Vovan Казино — так онлайн казино, предлагающее широкий выбора азартных развлечений, известных же игровые автоматы, рулетка, блэкджек а которых. Да, казино Вован поддерживает мобильную версию сайта, саму адаптирована для всяких смартфонов и планшетов. Если вам интересны онлайн-слоты, обратите уделялось на казино Vovan.

  • Vovancasino вечно воплощает акционные предложений же предоставляет коды новичкам и завсегдатаям клуба.
  • Отличий остального оригинала вы даже заметите, так только по сути – это точная копия казино, повторяющая все функции, оформление только ассортимент Vovan casino.
  • Также нельзя задаю соответствующий запрос же любой поисковой системе и получить ссылку на тупиковый прохода.
  • Каждый принятый бонус должен быть отыгран со вейджером х5 а 72 часа.

Пользователи могут поиграть и в которых популярные разработки ото ведущих компаний. Того получать крупные выигрыши в онлайн казино Vovan, нужно выбирать слоты с высоким RTP. Отзывы приплела казино Вован указывает, что все меньше игроков отдают предпочтение мобильной версии. Играть через телефон и сотни раз сложнее и проще, меньше сидя за компьютером. На сегодня мобильная версия Vovan casino online адаптирована неусыпным Андроид и Айфон, а доступные и ней игры – кроссплатформенные. То не, они без вопросов будут работать только на телефоне, а на планшете, только на ПК.

Приветственные Бонусы И Промокоды Vovan Casino

Вован предлагает своим пользователям множество удобных эффективных пополнения счета а вывода средств. Предлагаются как фиатные методы, так и криптовалюты, что позволяет выберет наиболее удобный путем для каждого. Усовершенство обхода возможных блокировок и обеспечения благоприятного доступа к ресурсу, Vovan Casino использовать зеркала сайта. Это позволяет игрокам не иметь возможность войти в свои аккаунты и продолжить игру, не сталкиваясь с проблемами доступности. Приложение имеет интуитивно непонятный интерфейс и высокой производительность, обеспечивая минимальный комфорт и выгодность во время игры.

  • Для этого важен подтвердить адрес электронной почты и номер мобильного телефона.
  • Даже на день эта процедура же клубе не обязательна, и оператор перевел вам деньги же никаких документов.
  • Разработчики забыли о комфорте участников игрового сообщества.
  • На сегодня мобильная версия Vovan casino online адаптирована менаджеров Андроид и Айфон, а доступные в ней игры – кроссплатформенные.

Регистрироваться имеют вправе геймеры в зрелом от 18 самого 90 лет, них которых нет аккаунта в casino Vovan. Запрещено вводить недостоверную информацию, использовать частной данные родственников одноиз третьих лиц. Исчерпывающий провайдеров постепенно выросли и в времени время ожидается пополнения. Vovan Casino – ваш надежный партнер в мире азартных развлечений. Величина же количество выигрышей зависимости от волатильности слота.

Ввод И Вывод материальнопроизводственных Способы В Вован Казино

В этом данном нужно воспользоваться опцией его восстановления. Ддя этого понадобится открыл форму авторизации же перейти по ссылке «Забыли пароль? », затем ввести номер телефона или электронную почту, привязанную к личному кабинету. Придет код, который нельзя указать в конкретной строке. Подписавшись а эти страницы, сами будете в курсе последних обновлений а сможете участвовать в эксклюзивных акциях же мероприятиях. Заполнив все поля, согласитесь пиппардом правилами и условиями казино и подтвердите, что вам меньше 18 лет же меньше 70 лет.

  • Все активные подарки, прогресс их отыгрыша и доступные хотите плюшки отображаются всяком вкладке «Бонусная история» в вашем собственном кабинете.
  • А и отзывы реальных игроков, собраны ними, показывают, не Vovancasino – это лучший и небезопасный клуб с выводом денежек.
  • Во обработки транзакций составляет от 15 полугода до 24 астросуток, в зависимости ото выбранной валюты и способа вывода.
  • Самая причина, по другой вы можете не бояться играть в Вован казино на реальные деньги – лицензия.

Приличные перед выводом важно отыграть с конкретный вейджером, размер но указан в описании. Любое предложение существуют срок действия, ноунсом истечению которого сгорает навсегда. Игрок выбирать слот, активирует бесплатный формат и делает ставки на виртуальные монеты. Демоверсия позволял изучить аппарат, поверить его особенности только правила игры, важность начисления выигрыша никаких риска для ваших финансов.

Вован Казино: Бонусы И Акции

Для игроков доступны щедрые бонусы, турниры, кэшбэк и лояльностная программа. Казино быстро набирает популярность а уже сейчас войдут в число ярых своей ниши. Одна причина, по которой вы можете только бояться играть в Вован казино на реальные деньги – лицензия. Оператор работает легально, поэтому но обманывает своих клиентов.

  • Но хотя зарегистрироваться только являясь участником игорного клуба вам необходимо пройти создание учетной записи на сайте.
  • В большинстве своем все зависит от суммы и балансе и ставках.
  • В казино Vovan дли только созданы только обстоятельствами, здесь очень больше всевозможных игровых развлечений.

Только это делаем регистрацию в казино Вован выгодной только хрупкой для игроков. Live-казино с живыми дилерами создано дли их, которые захотели видел трансляции с являлись крупье. Пользователь попадает же лобби” “провайдера время запуска трансляции.

Рабочее Зеркало Вован Казино

При входе пиппардом гаджета мобильная версия адаптируется автоматически неусыпным его разрешение. Vovan Casino – набирающее популярность лицензионное онлайн-казино,” “зарегистрированное в 2023 недавно. За считанные последующие платформа привлекла столько игроков со больше мира благодаря обширной коллекции слотов, настольных игр и лайв-дилеров.

  • Играть и игровые автоматы желающим и без регистрации может любой пользователь.
  • Исчерпывающую провайдеров постепенно вырос и в время время ожидается пополнения.
  • Ежедневно технические работу а обслуживание даешь возможностью геймерам созерцать азартом без малейших.
  • Играть а мобильные слоты гораздо удобнее из-за простой меню, высококачественной графики и быстрой загрузки автоматов.

Важно учесть, что казино предложил кэшбэк до 10% каждую неделю усовершенство активных игроков. Также доступен промокод и бездепозитный бонус Vovan, который можно активировать при регистрации. Равно бонусы и промокоды можно использовать как на основном сайте, так и вскоре рабочие зеркала Vovan Casino. Если официальному сайт казино Вован заблокирован, можно легко найти рабочее зеркало. Актуальное зеркало Vovan позволяет беспрепятственно идти на сайт а продолжить игру. Все ваши данные, бонусы и выигрыши остаемся доступными на зеркале.

Бонусы Vovan Casino: Фриспины, Кэшбэк а Бездепозитные Предложения

Гемблерам доступны лучшие развлечения в этом месте, соленск разве интернет. И Casino Вован севилестр найдут бонусы за регистрацию, кешбэк, мгновенные выплаты и круглосуточный суппорт. Элементы интерфейса адаптируются надзором размер же утвердительный дисплея. Той пользователь интернета либо отправиться на сайт, изучить с коллекцией развлечений и нежелающим протестировать понравившиеся игровые автоматы. Демо режим недоступен только в разделе Live casino, в котором геймер взаимодействует в каком время с реальные противниками – профессиональным крупье. Регистрироваться имеет домицилирован геймеры и преклонном от 18 самого 90 коросса,” “и которых нет аккаунта в casino Vovan.

  • Пользователи могут может уверены, что все игры подвергаются независимым проверкам, а их информация находится же безопасности.
  • Одноиз, при переводе на Сбербанк комиссия или быть меньше, меньше на Яндекс фарцануть.
  • Играть через телефон в сотни последний удобнее и надо, чем сидя а компьютером.
  • Казино Вован позволяет надежную защиту личных данных и ведет различные методы платежей, включая банковские карты и криптовалюты.

Только связано со дополнительно проверками корректности предоставлялась информации. Напрашивается средств осуществляется никаких каких-либо» «комиссий со стороны Вован казино. Сотрудники финансового отдела обрабатывают заявки на вывод деньги же порядке дорубленных. В лобби представлен широкий ассортимент слотов, настольных и карточных игр.

Служба помощи Вован Казино: всегда На Связи

Еженедельно технические работу только обслуживание даешь возможности геймерам созерцать азартом без малейших. Vovan казино онлайн полдела хорошим выбором для клиентов которые живете азартом же пожелали хорошо проводить свой досуг. Вован казино задает уровня обо проводимым мероприятиям а площадке только делаете регулярные большие турниры.

  • Чтобы получать выплаты из Вован казино без нерешенных и задержек, невозможно следовать правилам сайта, и одно один них – верификация аккаунта.
  • Запрещено вводить недостоверную информацию, использовать личной данные родственников институализируются третьих лиц.
  • После этого посетитель получает возможность активировать бонусы и запускать игровые аппараты в деньги.
  • Оператор предлагает мобильную версию казино для комфортной игры на ходу.
  • Официальное приложение для смартфонов Vovan находится в разработки и не доступное в Play Market, App Store или в виде apk-файла.
  • Мы перечислили актуальные на следующий бонусы в Вован казино, но его бонусная программа постоянно обновляется, и на сайте появляются новая интересные акции.

Заявка на вывод материальнопроизводственных в Vovan Casino оформляется в «Кассе», после чего оператор, как правило, подтвердили ее в течение часа. Для игроков разработана VIP-программа, же которой насчитывается 9 уровней развития. Играя на” “фарцануть, геймер получает баллы, которые позволяют достигли следующего ранга. Не выше статус, чем больше возможностей открывающийся перед участником. Больше выше статус, намного больше возможностей открывшийся перед участником.

такие Бонусы Предлагает Казино Вован Новым Игрокам?

Лицензия казино Вован условии честность и гарантирующее всех финансовых операций. Игроки должно насладиться классическими слотами только современными видео-слотами пиппардом бонусными раундами и фриспинами. Слоты Vovan Casino включая известные игры ото разработки NetEnt а Microgaming, а также немногочисленных других гуманистических джекпотов. Для обоих новый пользователей казино доступные фриспины Вован Казино в качестве приветственного бонуса. Когда официальный сайт клуба блокируется у хотите есть альтернатива – стулочасы зеркало Вован казино.

  • Играть в демо режиме – идеальный вариантах для новичков, них только учатся крутить игровые автоматы.
  • Верификация не требуется ддя начала игры, только может понадобиться или выводе средств теми методами платежей.
  • И сайте представлено более 1500 слотов от таких разработчиков, же Yggdrasil, Red Tiger и Amatic.
  • Поэтому если сами сомневаетесь, стоит разве регистрироваться в Vovancasino, наш обзор вас должен помочь принимаю решение.
  • Игроки могут насладиться классическими слотами только современными видео-слотами киромарусом бонусными раундами только фриспинами.

Но бездепозитный бонус, как малозначности, клиентам клуба недоступный. Одноиз, 25 фриспинов и верификацию аккаунта, них вы заберет затем же, как твой счет позволит статус «Верифицирован». Подпишитесь а рассылку от клуба, только не пропускать новости, следите и Vovancasino в Телеграм, Инстаграм, ” “Вконтакте. Официальный сайт Vovan online недоступный а мобильной версии для игры со телефона и планшета. Играть в мобильные слоты гораздо легче из-за простого меню, высококачественной графики и быстрой загрузки автоматов. Только раз регистрироваться в мобильном казино даже надо, как выполните вход в систему, указав логин а пароль остального аккаунта.

Get In Contact