/* 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
Mostbet Azerbaycan Mosbet Casino – Shaldip Vinyl LLP

Mostbet Azerbaycan Mosbet Casino

Mostbet Azerbaycan Mosbet CasinoBəzi matçlarda video clip lent və ya infoqrafika mövcuddur.

Mostbet onlayn kazino yeni və ölməz istifadəçilər ötrü bir neçə bonusa malikdir. Şirkətin formal saytı funksionallıq və əlavə istifadəçi seçimləri baxımından yüksək platformadır. Mostbet AZ kazinosunun formal saytında siz mobil tətbiqetməni təhlükəsiz yükləyə, əlbəəl bir zamanda yeni hesabı qeydiyyatdan keçirə bilərsiniz (bir kliklə). Sonrakı yoxlamanı sadələşdirmək üçün saytda mobil proqramda olmayan genişləndirilmiş qeydiyyat metodu mövcuddur (həmçinin Telegram vasitəsilə qeydiyyat).

  • Bu seçimlərin altında əsl üfüqi menyu yerləşir, o, aşağıdakılar kimi yerdəki mahiyyət oyuncaq seçimlərinə çıxışı təklif edir.
  • “Populyar” bölməsində, həmçinin Mostbet oyunları və qəza oyunlarını da görəcəksiniz.
  • Bununla belə, əsla bir şeyin belə asanlıqla gəlməyəcəyinə hazır olmalısınız.
  • Bu metodun ən yüngül və hündür olmasına baxmayaraq, onu son dərəcə ehtiyatla müalicə etməyinizi tövsiyə edirik.
  • Hal-hazırda bu bölmədə 5000-dən daha slot və slot maşınları mövcuddur.
  • Qanuni bir bahis olmadığına dair əlamətlərimiz olmasa da, adi dördgözlü olmağı məsləhət görürük.

Mostbet Mobil Versiya

Bunun ötrü pul risk etməyə ehtiyac yoxdur, vur-tut öz zövqün ötrü oynamalısan. Mosbet-də mərc edərkən, müxtəlif strategiyalardan istifadə edə bilərsiniz. Oyunçu vaxtı müstəqil olaraq müəyyənləşdirir və növbəti sessiyanın keçiriləcəyi slotları seçir. Təqdim olunan filtrlər sistemi axtarış prosesini asanlaşdırmağa imkan verir. Oyunçular Mosbet kataloqunda əyləncələri janr və ya provayder qədər parametrlərə görə çeşidləyə bilərlər. Siz həmçinin hədis xüsusiyyətləri ilə axtarışa başlaya bilərsiniz.

Müasir Oyunçular ötrü Bonuslar Və Promosyonlar

Eyni mərhələdə, istifadəçi casino pullarından istifadə eləmək və mərc oynamaqla özünü yükləmək istəmədiyi təqdirdə bonusdan imtina edə bilər. Əgər bonus xüsusi olaraq idman mərcləri və ya hər hansı casino oyunları üçün nəzərdə tutulubsa, başqa hallarda istifadə oluna bilməz. Xoş gəldin bonusu oyunçuya saytda qaldığı ara mostbet aviator yukle ərzində vahid dəfə verilir. Eyni depozitə üçün oxşarı vaxtda casino və idman mərc oyunlarına üçün bonus almaq mümkün deyil.

  • Tətbiq iyirmi dörd/yeddi işləyir, bunun sayəsində sizin ötrü uyar olan hər yerdə və istənilən müddət oynamaq və udmaq mümkündür.
  • Beləliklə, mərclərin yerləşdirilməsi vur-tut formal internet saytında və ya mobil versiyada yox, həm də tətbiqdə əlçatan olub.
  • Bukmeker kontoru təklər, ekspress mərclər və xokkey üçün sistem mərclərini götürmə edir.
  • Stolüstü oyunları Mostbet AZ-90-ın onlayn kazinosu vasitəsilə də əldə görmək olar.
  • Yalnız bundan sonra onlar ard götürülə və ya məhdudiyyətsiz mərc üçün istifadə edilə bilər.

Sosial Media Ilə

Bu, ən riskli bir seçimdir, çünki hadisələrdən biri istənilən nəticəni verməsə belə, elliklə kupon ölçüsü itirilir. Əgər sayta daxil ola bilmirsinizsə, burada əylənmək icazəniz yoxsa bilər. VPN-i yandırmağa və ya digər hiylələrə əl atmağa çalışmayın. Onların sizinlə görüşəcəyi bir portal yığmaq ən yaxşıdır.

  • Canlı mərc funksiyaları və real ara yeniləmələri ilə oyunun mərkəzində olun.
  • Sonuncu fürsət isə mübahisəlidir, çünki istənilən oyunda hesablamalar və strategiyalar üçün həmişə yer mülk.
  • Tələbinizi aldıqdan və şəxsiyyətinizi təsdiq etdikdən sonra hesabınızı istədiyiniz müddətə bağlayacaqlar.

Elektron Poçta Ilə Qeydiyyat

Hər mərc qalibiyyətindən sonra siz mahiyyət Mostbet balansınızda qazanc əldə edəcəksiniz. Təsdiqdən sonra məlumatlarınızdan istifadə edərək para alacaqsınız. Bu məsləhətləri dinləməklə siz hökmən əsl peşəkara çevrilə biləcəksiniz və arzu edirik ki, bu mümkün kəmiyyət cəld əsas borc. Vaxtınızı ayırın və xeyir əldə eləmək üçün irfan, təcrübə və intuisiyanızı tədricən artırın.

Canlı Kazino Oyunları

Az tanımlı turnirlər və növlər 100-dən 500-ə qədər effekt variantlarını iç edə bilər. Koefitsientlərə gəlincə, onları bazarda orta miqdar edə bilərsiniz. Kibersporta və Canlı oyunlara ənənəvi şəkildə aşağı koefitsientlər qoyulur. Mostbet mobile mahiyyət səhifəsində cari aksiyalar, bonuslar, bukmekerin şəxsi təklifləri haqqında elan bloku yer alır. Həmçinin yuxarı hissədə əsl menyuya, qeydiyyata və daxil olma düymələri mövcuddur.

  • Hər vahid şirkət mümkün kəmiyyət daha müştəri cəlb etməyə çalışır və lap atəşin marketinq vasitələrindən biri bonus proqramıdır.
  • Mostbetdə lap populyar qumar əyləncələrindən biri “Aviator” kraş-oyunu say edilir.
  • Biz müştəri etibar proqramının bir mostbet-az90 parçası olaraq, müştərilər müxtəlif şəkildə ödənə bilərlər.
  • Təhlükəsizlik xidməti 1-5 günəş ərzində ərizənizi yoxlayacaq və köçürməni təsdiq edəcək.
  • Pul çıxara duymaq ötrü oyunçu şəxsiyyətin yoxlanılması prosedurundan keçməli və təqdim olunan şəxsi məlumatları təsdiqləməlidir.

Mostbet Bahisçisinin Rəsmi Saytı: Bonuslar, Qeydiyyat, Tətbiqetm

Ən təntənəli reytinqli provayderlərdən slot alan kazino oyunlarda cekpotlar kimi böyük hədiyyələr təklif edir. Şans oyunları olan slotlarda qalib gəlmək şansınız ən yüksəkdir. Meyvə temalı slot maşınlarından stolüstü oyunlara, canlı diler oyunlarına və lotereyalara miqdar hər mövzuda oyun tapıb həzz şəhla bilərsiniz. Mostbet Kazino qeydiyyat prosesini mümkün miqdar sadələşdirib ki, istənilən yaşda və ölkədən olan müştərilər profil açarkən azar çəkib daha ara itirməsinlər.

Mostbet Pul Düzmək Metodları

Bonus hər şeydən ibtidai fribeti – müəyyən pul məbləğində pulsuz qoyuluşu nəzərdə tutur. Həmçinin bonus-kod oyunçuya hətta qeydiyyat ötrü 125% istifadə edilsə belə sürmə faizi verə bilər. Bu maddədə oyunçu bonuslar üçün promo – kodların haradan əldə edilməsini və onları necə aktivləşdirməyi öyrənir. Mostbet AZ həmçinin ən sədaqətli oyunçuları üçün VIP bonus təklif edir. Bu bonus uzun müddətdir saytda olan və laziminca miqdarda əmanət yatırmış oyunçuları bağışlamaq ötrü nəzərdə tutulub.

Casino Mostbet-aze45: Slot Maşınları Və Slotlar

Tətbiqdən istifadə edən mərcsevərlərin rəylərinə baxdıqda onların tətbiqi sevidiyini və mərclərini ən lap tətbiq üzərində yerləşdirdiklərini üçün bilərik. Buna cəhət tətbiqin dizaynı, istənilən vaxt, istənilən yerdə tətbiqə əlçatanlıq və daha mürəkkəbliyə qaçmadan vahid toxunuşla mərclər yerləşdirməkdir. Həm MostBet Android app, həm də iOS app funskiyaları baxımdan vebsayt versiyadan aydın fərqlərə sahibdir.

Mostbet Casino Azerbaycan

Sosial şəbəkələrdən istifadə edərək Mosbet-də hesab yarada bilərsiniz. Bunu eləmək üçün təklif olunan variantlardan birini seçin, məsələn, Telegram və ya Google. Qeydiyyat prosesi zamanı oyunçu uyar valyuta seçməli olacaq və əgər varsa, promosyon kodu daxil mostbet edə bilər. Oyunçu Mosbet-dən qeydiyyat bonusunu aktivləşdirə və ya bu mərhələdə promosyonlarda iştirak etməməyi seçə bilər. Əvvəlcədən tövsiyə olunur ki, sosial qəfəs profilində özünüz haqqında aktual məlumatlar yerləşdirəsiniz.

Mostbet-aze45 Casino-da Oynamaq üçün Qeydiyyatdan Keçmək Lazımdırmı?

  • Mostbet-27 Bukmə Şirkəti həmçinin öz ölkəsində bloklanmış olsa belə, müştərilərə sayta iç olmaq imkanı verən rəsmi veb-sayt güzgülərinə malikdir.
  • Oyun hesabı ötrü valyutalar arasında manat da mal və sətirdə ölkənin elli xətləri və turnirləri var.
  • Bunun üçün sadəcə olaraq cihazınızda quraşdırılmış brauzer vasitəsilə şirkətin veb saytına batil olun, sonra isə Android və ya İOS-da onlayn yukle proqramı.
  • İdman mərcləri MostBet bukmeker kontorunun əsl xidmətidir.
  • Köhnə iPhone və iPad-lər proqramın düzgün işləməsini təmin edir.
  • Biz hələ bütün üstünlükləri sadalamamışıq, vur-tut yalnız əsl üstünlükləri fikir etmişik.

Bədii Casino Mosbet

  • Hər bir hadisənin oyun öncəsi analitikasının aparılması mütləqdir.
  • Bundan artıq, siz bilavasitə kuponda sistemlər, hətta zəncirlər yarada bilərsiniz.
  • Qarşılaşmadan başlanğıc ümumən oyunlar mövcuddur, siz ümumiyyətlə saytda mərc edə bilərsiniz.
  • Bu növ cihazlarda mərc görmək və slot maşınları əylənmək ötrü proqramları App Store vasitəsilə yükləmək daha yaxşıdır.
  • Həmçinin təzə oyunçular üçün qeydiyyatdan keçdikdə əlbəəl Frispinlər və əvəzsiz mərc haqqları hədiyə olunur.
  • Mostbet AZ 91 dəyişən bonus proqramının yaradılması kimi məqamlara lazımi diqqət yetirir.
  • Bütün məqam ondan ibarətdir ki, siz ekspress obrazlı tariflərlə alınan pulu yerə qoymalısınız.
  • Bir iPhone görə proqram quraşdırmaq vahid neçə klik tələb edir və burada əsl şey AppStore-da tətbiqi olan səhifəni tapmaqdır, bu da problem yaratmır.
  • Bukmeker istifadəçilərinin rahatlığı üçün mobil versiya da təklif edir.

Azerbaycan İdman Mərcləri

Tətbiqdə Niyə Mostbet Giriş Prosesini Edə Bilmirəm?

Oyunçunun Mostbet-də şəxsi Kabineti

Mostbet Azerbaijan-a Iç Olmaqda Problemlər

Mostbet Qeydiyyat Keçdikdə 555 Azn Bonusunu Necə Əldə Görmək Olar?

Mostbet Dəstək Xidmətinin Üstünlükləri:

Mostbet-az91 Saytına Necə Iç Olmaq Olar?

Get In Contact