Changeset 1707679
- Timestamp:
- 08/03/2017 10:50:33 AM (9 years ago)
- Location:
- shop-menu/trunk
- Files:
-
- 1 added
- 4 edited
-
readme.txt (modified) (2 diffs)
-
shop-menu.php (modified) (2 diffs)
-
wpalchemy/CHANGELOG.md (added)
-
wpalchemy/MediaAccess.php (modified) (9 diffs)
-
wpalchemy/MetaBox.php (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
shop-menu/trunk/readme.txt
r1118446 r1707679 3 3 Donate link: 4 4 Tags: menu, shop, shortcode, ajax 5 Requires at least: 3.56 Tested up to: 4. 1.17 Stable tag: 1. 4.05 Requires at least: 4.0 6 Tested up to: 4.8.1 7 Stable tag: 1.5.0 8 8 License: GPLv2 or later 9 9 License URI: http://www.gnu.org/licenses/gpl-2.0.html … … 34 34 == Changelog == 35 35 36 = 1.5.0 = 37 * ライブラリを更新しました 38 36 39 = 1.4.0 = 37 40 * 商品一覧のデザインを変更しました -
shop-menu/trunk/shop-menu.php
r1118446 r1707679 4 4 Plugin URI: http://residentbird.main.jp/bizplugin/ 5 5 Description: 商品一覧、メニュー一覧を作成するプラグインです 6 Version: 1. 4.06 Version: 1.5.0 7 7 Author:Hideki Tanaka 8 8 Author URI: http://residentbird.main.jp/bizplugin/ … … 17 17 18 18 class SM{ 19 const VERSION = "1. 4.0";19 const VERSION = "1.5.0"; 20 20 const SHORTCODE = "showshopmenu"; 21 21 const SHORTCODE_PRICE = "showprice"; -
shop-menu/trunk/wpalchemy/MediaAccess.php
r725643 r1707679 6 6 * @license http://en.wikipedia.org/wiki/MIT_License The MIT License 7 7 * @package WPAlchemy 8 * @version 0.2. 18 * @version 0.2.2 9 9 * @link http://github.com/farinspace/wpalchemy/ 10 10 * @link http://farinspace.com/ … … 119 119 $this->tab = $name; 120 120 121 $this;121 return $this; 122 122 } 123 123 … … 152 152 { 153 153 $groupname = isset($attr['groupname']) ? $attr['groupname'] : $this->groupname ; 154 154 155 155 $attr_default = array 156 156 ( … … 201 201 202 202 $tab = ! empty($tab) ? $tab : 'library' ; 203 203 204 204 return 'media-upload.php?post_id=' . $post_ID . '&tab=' . $tab . '&TB_iframe=1'; 205 205 } … … 219 219 { 220 220 $groupname = isset($groupname) ? $groupname : $this->groupname ; 221 221 222 222 return $this->button_class_name . '-' . $groupname . ' thickbox'; 223 223 } … … 255 255 256 256 $tab = isset($attr['tab']) ? $attr['tab'] : $this->tab ; 257 257 258 258 $attr_default = array 259 259 ( … … 341 341 var url = src ? src : href ; 342 342 343 wpalchemy_mediafield.val(url) ;343 wpalchemy_mediafield.val(url).trigger('change'); 344 344 345 345 // reset insert button label … … 366 366 } 367 367 368 $(' [class*=<?php echo $this->button_class_name; ?>]').live('click', function()368 $('body').on('click', '[class*=<?php echo $this->button_class_name; ?>]', function() 369 369 { 370 370 var name = $(this).attr('class').match(/<?php echo $this->button_class_name; ?>-([a-zA-Z0-9_-]*)/i); … … 411 411 } 412 412 } 413 414 /* End of file */ -
shop-menu/trunk/wpalchemy/MetaBox.php
r725643 r1707679 2 2 3 3 /** 4 * @author Dimas Begunoff5 * @copyright Copyright (c) 2009, Dimas Begunoff, http://farinspace.com6 * @license http://en.wikipedia.org/wiki/MIT_License The MIT License7 * @package WPAlchemy8 * @version 1.5.19 * @link http://github.com/farinspace/wpalchemy10 * @link http://farinspace.com4 * @author Dimas Begunoff 5 * @copyright Copyright (c) 2009, Dimas Begunoff, http://farinspace.com 6 * @license http://en.wikipedia.org/wiki/MIT_License The MIT License 7 * @package WPAlchemy 8 * @version 1.6.1 9 * @link http://github.com/farinspace/wpalchemy 10 * @link http://farinspace.com 11 11 */ 12 13 // todo: perhaps move _global_head and _global_foot locally, when first run14 // define a constant to prevent other instances from running again ...15 16 add_action('admin_head', array('WPAlchemy_MetaBox', '_global_head'));17 18 add_action('admin_footer', array('WPAlchemy_MetaBox', '_global_foot'));19 12 20 13 define('WPALCHEMY_MODE_ARRAY', 'array'); … … 55 48 class WPAlchemy_MetaBox 56 49 { 57 /** 58 * User defined identifier for the meta box, prefix with an underscore to 59 * prevent option(s) form showing up in the custom fields meta box, this 60 * option should be used when instantiating the class. 61 * 62 * @since 1.0 63 * @access public 64 * @var string required 65 */ 66 var $id; 67 68 /** 69 * Used to set the title of the meta box, this option should be used when 70 * instantiating the class. 71 * 72 * @since 1.0 73 * @access public 74 * @var string required 75 * @see $hide_title 76 */ 77 var $title = 'Custom Meta'; 78 79 /** 80 * Used to set the meta box content, the contents of your meta box should be 81 * defined within this file, this option should be used when instantiating 82 * the class. 83 * 84 * @since 1.0 85 * @access public 86 * @var string required 87 */ 88 var $template; 89 90 /** 91 * Used to set the post types that the meta box can appear in, this option 92 * should be used when instantiating the class. 93 * 94 * @since 1.0 95 * @access public 96 * @var array 97 */ 98 var $types; 99 100 /** 101 * @since 1.0 102 * @access public 103 * @var bool 104 */ 105 var $context = 'normal'; 106 107 /** 108 * @since 1.0 109 * @access public 110 * @var bool 111 */ 112 var $priority = 'high'; 113 114 /** 115 * @since 1.0 116 * @access public 117 * @var bool 118 */ 119 var $autosave = TRUE; 120 121 /** 122 * Used to set how the class does its data storage, data will be stored as 123 * an associative array in a single meta entry in the wp_postmeta table or 124 * data can be set and individual entries in the wp_postmeta table, the 125 * following constants should be used when setting this option, 126 * WPALCHEMY_MODE_ARRAY (default) and WPALCHEMY_MODE_EXTRACT, this option 127 * should be used when instantiating the class. 128 * 129 * @since 1.2 130 * @access public 131 * @var string 132 */ 133 var $mode = WPALCHEMY_MODE_ARRAY; 134 135 /** 136 * When the mode option is set to WPALCHEMY_MODE_EXTRACT, you have to take 137 * care to avoid name collisions with other meta entries. Use this option to 138 * automatically add a prefix to your variables, this option should be used 139 * when instantiating the class. 140 * 141 * @since 1.2 142 * @access public 143 * @var array 144 */ 145 var $prefix; 146 147 /** 148 * @since 1.0 149 * @access public 150 * @var bool 151 */ 152 var $exclude_template; 153 154 /** 155 * @since 1.0 156 * @access public 157 * @var bool 158 */ 159 var $exclude_category_id; 160 161 /** 162 * @since 1.0 163 * @access public 164 * @var bool 165 */ 166 var $exclude_category; 167 168 /** 169 * @since 1.0 170 * @access public 171 * @var bool 172 */ 173 var $exclude_tag_id; 174 175 /** 176 * @since 1.0 177 * @access public 178 * @var bool 179 */ 180 var $exclude_tag; 181 182 /** 183 * @since 1.0 184 * @access public 185 * @var bool 186 */ 187 var $exclude_post_id; 188 189 /** 190 * @since 1.0 191 * @access public 192 * @var bool 193 */ 194 var $include_template; 195 196 /** 197 * @since 1.0 198 * @access public 199 * @var bool 200 */ 201 var $include_category_id; 202 203 /** 204 * @since 1.0 205 * @access public 206 * @var bool 207 */ 208 var $include_category; 209 210 /** 211 * @since 1.0 212 * @access public 213 * @var bool 214 */ 215 var $include_tag_id; 216 217 /** 218 * @since 1.0 219 * @access public 220 * @var bool 221 */ 222 var $include_tag; 223 224 /** 225 * @since 1.0 226 * @access public 227 * @var bool 228 */ 229 var $include_post_id; 230 231 /** 232 * Callback used on the WordPress "admin_init" action, the main benefit is 233 * that this callback is executed only when the meta box is present, this 234 * option should be used when instantiating the class. 235 * 236 * @since 1.3.4 237 * @access public 238 * @var string|array optional 239 */ 240 var $init_action; 241 242 /** 243 * Callback used to override when the meta box gets displayed, must return 244 * true or false to determine if the meta box should or should not be 245 * displayed, this option should be used when instantiating the class. 246 * 247 * @since 1.3 248 * @access public 249 * @var string|array optional 250 * @param array $post_id first variable passed to the callback function 251 * @see can_output() 252 */ 253 var $output_filter; 254 255 /** 256 * Callback used to override or insert meta data before saving, you can halt 257 * saving by passing back FALSE (return FALSE), this option should be used 258 * when instantiating the class. 259 * 260 * @since 1.3 261 * @access public 262 * @var string|array optional 263 * @param array $meta meta box data, first variable passed to the callback function 264 * @param string $post_id second variable passed to the callback function 265 * @see $save_action, add_filter() 266 */ 267 var $save_filter; 268 269 /** 270 * Callback used to execute custom code after saving, this option should be 271 * used when instantiating the class. 272 * 273 * @since 1.3 274 * @access public 275 * @var string|array optional 276 * @param array $meta meta box data, first variable passed to the callback function 277 * @param string $post_id second variable passed to the callback function 278 * @see $save_filter, add_filter() 279 */ 280 var $save_action; 281 282 /** 283 * Callback used to override or insert STYLE or SCRIPT tags into the head, 284 * this option should be used when instantiating the class. 285 * 286 * @since 1.3 287 * @access public 288 * @var string|array optional 289 * @param array $content current head content, first variable passed to the callback function 290 * @see $head_action, add_filter() 291 */ 292 var $head_filter; 293 294 /** 295 * Callback used to insert STYLE or SCRIPT tags into the head, 296 * this option should be used when instantiating the class. 297 * 298 * @since 1.3 299 * @access public 300 * @var string|array optional 301 * @see $head_filter, add_action() 302 */ 303 var $head_action; 304 305 /** 306 * Callback used to override or insert SCRIPT tags into the footer, this 307 * option should be used when instantiating the class. 308 * 309 * @since 1.3 310 * @access public 311 * @var string|array optional 312 * @param array $content current foot content, first variable passed to the callback function 313 * @see $foot_action, add_filter() 314 */ 315 var $foot_filter; 316 317 /** 318 * Callback used to insert SCRIPT tags into the footer, this option should 319 * be used when instantiating the class. 320 * 321 * @since 1.3 322 * @access public 323 * @var string|array optional 324 * @see $foot_filter, add_action() 325 */ 326 var $foot_action; 327 328 /** 329 * Used to hide the default content editor in a page or post, this option 330 * should be used when instantiating the class. 331 * 332 * @since 1.3 333 * @access public 334 * @var bool optional 335 */ 336 var $hide_editor = FALSE; 337 338 /** 339 * Used in conjunction with the "hide_editor" option, prevents the media 340 * buttons from also being hidden. 341 * 342 * @since 1.5 343 * @access public 344 * @var bool optional 345 */ 346 var $use_media_buttons = FALSE; 347 348 /** 349 * Used to hide the meta box title, this option should be used when 350 * instantiating the class. 351 * 352 * @since 1.3 353 * @access public 354 * @var bool optional 355 * @see $title 356 */ 357 var $hide_title = FALSE; 358 359 /** 360 * Used to lock a meta box in place, possible values are: top, bottom, 361 * before_post_title, after_post_title, this option should be used when 362 * instantiating the class. 363 * 364 * @since 1.3.3 365 * @access public 366 * @var string optional possible values are: top, bottom, before_post_title, after_post_title 367 */ 368 var $lock; 369 370 /** 371 * Used to lock a meta box at top (below the default content editor), this 372 * option should be used when instantiating the class. 373 * 374 * @deprecated deprecated since version 1.3.3 375 * @since 1.3 376 * @access public 377 * @var bool optional 378 * @see $lock 379 */ 380 var $lock_on_top = FALSE; 381 382 /** 383 * Used to lock a meta box at bottom, this option should be used when 384 * instantiating the class. 385 * 386 * @deprecated deprecated since version 1.3.3 387 * @since 1.3 388 * @access public 389 * @var bool optional 390 * @see $lock 391 */ 392 var $lock_on_bottom = FALSE; 393 394 /** 395 * Used to set the initial view state of the meta box, possible values are: 396 * opened, closed, always_opened, this option should be used when 397 * instantiating the class. 398 * 399 * @since 1.3.3 400 * @access public 401 * @var string optional possible values are: opened, closed, always_opened 402 */ 403 var $view; 404 405 /** 406 * Used to hide the show/hide checkbox option from the screen options area, 407 * this option should be used when instantiating the class. 408 * 409 * @since 1.3.4 410 * @access public 411 * @var bool optional 412 */ 413 var $hide_screen_option = FALSE; 414 415 // private 416 417 var $meta; 418 var $name; 419 var $subname; 420 421 /** 422 * Used to provide field type hinting 423 * 424 * @since 1.3 425 * @access private 426 * @var string 427 * @see the_field() 428 */ 429 var $hint; 430 431 var $length = 0; 432 var $current = -1; 433 var $in_loop = FALSE; 434 var $in_template = FALSE; 435 var $group_tag; 436 var $current_post_id; 437 438 /** 439 * Used to store current loop details, cleared after loop ends 440 * 441 * @since 1.4 442 * @access private 443 * @var stdClass 444 * @see have_fields_and_multi(), have_fields() 445 */ 446 var $_loop_data; 447 448 function WPAlchemy_MetaBox($arr) 449 { 450 $this->_loop_data = new stdClass; 451 452 $this->meta = array(); 453 454 $this->types = array('post', 'page'); 455 456 if (is_array($arr)) 457 { 458 foreach ($arr as $n => $v) 459 { 460 $this->$n = $v; 461 } 462 463 if (empty($this->id)) die('Meta box ID required'); 464 465 if (is_numeric($this->id)) die('Meta box ID must be a string'); 466 467 if (empty($this->template)) die('Meta box template file required'); 468 469 // check for nonarray values 470 471 $exc_inc = array 472 ( 473 'exclude_template', 474 'exclude_category_id', 475 'exclude_category', 476 'exclude_tag_id', 477 'exclude_tag', 478 'exclude_post_id', 479 480 'include_template', 481 'include_category_id', 482 'include_category', 483 'include_tag_id', 484 'include_tag', 485 'include_post_id' 486 ); 487 488 foreach ($exc_inc as $v) 489 { 490 // ideally the exclude and include values should be in array form, convert to array otherwise 491 if (!empty($this->$v) AND !is_array($this->$v)) 492 { 493 $this->$v = array_map('trim',explode(',',$this->$v)); 494 } 495 } 496 497 // convert depreciated variables 498 if ($this->lock_on_top) $this->lock = WPALCHEMY_LOCK_TOP; 499 elseif ($this->lock_on_bottom) $this->lock = WPALCHEMY_LOCK_BOTTOM; 500 501 add_action('admin_init', array($this,'_init')); 502 503 // uses the default wordpress-importer plugin hook 504 add_action('import_post_meta', array($this, '_import'), 10, 3); 505 } 506 else 507 { 508 die('Associative array parameters required'); 509 } 510 } 511 512 /** 513 * Used to correct double serialized data during post/page export/import, 514 * additionally will try to fix corrupted serialized data by recalculating 515 * string length values 516 * 517 * @since 1.3.16 518 * @access private 519 */ 520 function _import($post_id, $key, $value) 521 { 522 if (WPALCHEMY_MODE_ARRAY == $this->mode AND $key == $this->id) 523 { 524 // using $wp_import to get access to the raw postmeta data prior to it getting passed 525 // through "maybe_unserialize()" in "plugins/wordpress-importer/wordpress-importer.php" 526 // the "import_post_meta" action is called after "maybe_unserialize()" 527 528 global $wp_import; 529 530 foreach ( $wp_import->posts as $post ) 531 { 532 if ( $post_id == $post['post_id'] ) 533 { 534 foreach( $post['postmeta'] as $meta ) 535 { 536 if ( $key == $meta['key'] ) 537 { 538 // try to fix corrupted serialized data, specifically "\r\n" being converted to "\n" during wordpress XML export (WXR) 539 // "maybe_unserialize()" fixes a wordpress bug which double serializes already serialized data during export/import 540 $value = maybe_unserialize( preg_replace( '!s:(\d+):"(.*?)";!es', "'s:'.strlen('$2').':\"$2\";'", stripslashes( $meta['value'] ) ) ); 541 542 update_post_meta( $post_id, $key, $value ); 543 } 544 } 545 } 546 } 547 } 548 } 549 550 /** 551 * Used to initialize the meta box, runs on WordPress admin_init action, 552 * properly calls internal WordPress methods 553 * 554 * @since 1.0 555 * @access private 556 */ 557 function _init() 558 { 559 // must be creating or editing a post or page 560 if ( ! WPAlchemy_MetaBox::_is_post() AND ! WPAlchemy_MetaBox::_is_page()) return; 561 562 if ( ! empty($this->output_filter)) 563 { 564 $this->add_filter('output', $this->output_filter); 565 } 566 567 if ($this->can_output()) 568 { 569 foreach ($this->types as $type) 570 { 571 add_meta_box($this->id . '_metabox', $this->title, array($this, '_setup'), $type, $this->context, $this->priority); 572 } 573 574 add_action('save_post', array($this,'_save')); 575 576 $filters = array('save', 'head', 'foot'); 577 578 foreach ($filters as $filter) 579 { 580 $var = $filter . '_filter'; 581 582 if (!empty($this->$var)) 583 { 584 if ('save' == $filter) 585 { 586 $this->add_filter($filter, $this->$var, 10, 2); 587 } 588 else 589 { 590 $this->add_filter($filter, $this->$var); 591 } 592 } 593 } 594 595 $actions = array('save', 'head', 'foot', 'init'); 596 597 foreach ($actions as $action) 598 { 599 $var = $action . '_action'; 600 601 if (!empty($this->$var)) 602 { 603 if ('save' == $action) 604 { 605 $this->add_action($action, $this->$var, 10, 2); 606 } 607 else 608 { 609 $this->add_action($action, $this->$var); 610 } 611 } 612 } 613 614 add_action('admin_head', array($this,'_head'), 11); 615 616 add_action('admin_footer', array($this,'_foot'), 11); 617 618 // action: init 619 if ($this->has_action('init')) 620 { 621 $this->do_action('init'); 622 } 623 } 624 } 625 626 /** 627 * Used to insert STYLE or SCRIPT tags into the head, called on WordPress 628 * admin_head action. 629 * 630 * @since 1.3 631 * @access private 632 * @see _foot() 633 */ 634 function _head() 635 { 636 $content = NULL; 637 638 ob_start(); 639 640 ?> 641 <style type="text/css"> 642 <?php if ($this->hide_editor) { ?> #wp-content-editor-container, #post-status-info, <?php if ($this->use_media_buttons) { ?> #content-html, #content-tmce<?php } else { ?> #wp-content-wrap<?php } ?> { display:none; } <?php } ?> 643 </style> 644 <?php 645 646 $content = ob_get_contents(); 647 648 ob_end_clean(); 649 650 // filter: head 651 if ($this->has_filter('head')) 652 { 653 $content = $this->apply_filters('head', $content); 654 } 655 656 echo $content; 657 658 // action: head 659 if ($this->has_action('head')) 660 { 661 $this->do_action('head'); 662 } 663 } 664 665 /** 666 * Used to insert SCRIPT tags into the footer, called on WordPress 667 * admin_footer action. 668 * 669 * @since 1.3 670 * @access private 671 * @see _head() 672 */ 673 function _foot() 674 { 675 $content = NULL; 676 677 if 678 ( 679 $this->lock OR 680 $this->hide_title OR 681 $this->view OR 682 $this->hide_screen_option 683 ) 684 { 685 ob_start(); 686 687 ?> 688 <script type="text/javascript"> 689 /* <![CDATA[ */ 690 (function($){ /* not using jQuery ondomready, code runs right away in footer */ 691 692 var mb_id = '<?php echo $this->id; ?>'; 693 var mb = $('#' + mb_id + '_metabox'); 694 695 <?php if (WPALCHEMY_LOCK_TOP == $this->lock): ?> 696 <?php if ('side' == $this->context): ?> 697 var id = 'wpalchemy-side-top'; 698 if ( ! $('#'+id).length) 699 { 700 $('<div></div>').attr('id',id).prependTo('#side-info-column'); 701 } 702 <?php else: ?> 703 var id = 'wpalchemy-content-top'; 704 if ( ! $('#'+id).length) 705 { 706 $('<div></div>').attr('id',id).insertAfter('#postdiv, #postdivrich'); 707 } 708 <?php endif; ?> 709 $('#'+id).append(mb); 710 <?php elseif (WPALCHEMY_LOCK_BOTTOM == $this->lock): ?> 711 <?php if ('side' == $this->context): ?> 712 var id = 'wpalchemy-side-bottom'; 713 if ( ! $('#'+id).length) 714 { 715 $('<div></div>').attr('id',id).appendTo('#side-info-column'); 716 } 717 <?php else: ?> 718 if ( ! $('#advanced-sortables').children().length) 719 { 720 $('#advanced-sortables').css('display','none'); 721 } 722 723 var id = 'wpalchemy-content-bottom'; 724 if ( ! $('#'+id).length) 725 { 726 $('<div></div>').attr('id',id).insertAfter('#advanced-sortables'); 727 } 728 <?php endif; ?> 729 $('#'+id).append(mb); 730 <?php elseif (WPALCHEMY_LOCK_BEFORE_POST_TITLE == $this->lock): ?> 731 <?php if ('side' != $this->context): ?> 732 var id = 'wpalchemy-content-bpt'; 733 if ( ! $('#'+id).length) 734 { 735 $('<div></div>').attr('id',id).prependTo('#post-body-content'); 736 } 737 $('#'+id).append(mb); 738 <?php endif; ?> 739 <?php elseif (WPALCHEMY_LOCK_AFTER_POST_TITLE == $this->lock): ?> 740 <?php if ('side' != $this->context): ?> 741 var id = 'wpalchemy-content-apt'; 742 if ( ! $('#'+id).length) 743 { 744 $('<div></div>').attr('id',id).insertAfter('#titlediv'); 745 } 746 $('#'+id).append(mb); 747 <?php endif; ?> 748 <?php endif; ?> 749 750 <?php if ( ! empty($this->lock)): ?> 751 $('.hndle', mb).css('cursor','pointer'); 752 $('.handlediv', mb).remove(); 753 <?php endif; ?> 754 755 <?php if ($this->hide_title): ?> 756 $('.hndle', mb).remove(); 757 $('.handlediv', mb).remove(); 758 mb.removeClass('closed'); /* start opened */ 759 <?php endif; ?> 760 761 <?php if (WPALCHEMY_VIEW_START_OPENED == $this->view): ?> 762 mb.removeClass('closed'); 763 <?php elseif (WPALCHEMY_VIEW_START_CLOSED == $this->view): ?> 764 mb.addClass('closed'); 765 <?php elseif (WPALCHEMY_VIEW_ALWAYS_OPENED == $this->view): ?> 766 /* todo: need to find a way to add this script block below, load-scripts.php?... */ 767 var h3 = mb.children('h3'); 768 setTimeout(function(){ h3.unbind('click'); }, 1000); 769 $('.handlediv', mb).remove(); 770 mb.removeClass('closed'); /* start opened */ 771 $('.hndle', mb).css('cursor','auto'); 772 <?php endif; ?> 773 774 <?php if ($this->hide_screen_option): ?> 775 $('.metabox-prefs label[for='+ mb_id +'_metabox-hide]').remove(); 776 <?php endif; ?> 777 778 mb = null; 779 780 })(jQuery); 781 /* ]]> */ 782 </script> 783 <?php 784 785 $content = ob_get_contents(); 786 787 ob_end_clean(); 788 } 789 790 // filter: foot 791 if ($this->has_filter('foot')) 792 { 793 $content = $this->apply_filters('foot', $content); 794 } 795 796 echo $content; 797 798 // action: foot 799 if ($this->has_action('foot')) 800 { 801 $this->do_action('foot'); 802 } 803 } 804 805 /** 806 * Used to setup the meta box content template 807 * 808 * @since 1.0 809 * @access private 810 * @see _init() 811 */ 812 function _setup() 813 { 814 $this->in_template = TRUE; 815 816 // also make current post data available 817 global $post; 818 819 // shortcuts 820 $mb =& $this; 821 $metabox =& $this; 822 $id = $this->id; 823 $meta = $this->_meta(NULL, TRUE); 824 825 // use include because users may want to use one templete for multiple meta boxes 826 include $this->template; 827 828 // create a nonce for verification 829 echo '<input type="hidden" name="'. $this->id .'_nonce" value="' . wp_create_nonce($this->id) . '" />'; 830 831 $this->in_template = FALSE; 832 } 833 834 /** 835 * Used to properly prefix the filter tag, the tag is unique to the meta 836 * box instance 837 * 838 * @since 1.3 839 * @access private 840 * @param string $tag name of the filter 841 * @return string uniquely prefixed tag name 842 */ 843 function _get_filter_tag($tag) 844 { 845 $prefix = 'wpalchemy_filter_' . $this->id . '_'; 846 $prefix = preg_replace('/_+/', '_', $prefix); 847 848 $tag = preg_replace('/^'. $prefix .'/i', '', $tag); 849 return $prefix . $tag; 850 } 851 852 /** 853 * Uses WordPress add_filter() function, see WordPress add_filter() 854 * 855 * @since 1.3 856 * @access public 857 * @link http://core.trac.wordpress.org/browser/trunk/wp-includes/plugin.php#L65 858 */ 859 function add_filter($tag, $function_to_add, $priority = 10, $accepted_args = 1) 860 { 861 $tag = $this->_get_filter_tag($tag);; 862 add_filter($tag, $function_to_add, $priority, $accepted_args); 863 } 864 865 /** 866 * Uses WordPress has_filter() function, see WordPress has_filter() 867 * 868 * @since 1.3 869 * @access public 870 * @link http://core.trac.wordpress.org/browser/trunk/wp-includes/plugin.php#L86 871 */ 872 function has_filter($tag, $function_to_check = FALSE) 873 { 874 $tag = $this->_get_filter_tag($tag); 875 return has_filter($tag, $function_to_check); 876 } 877 878 /** 879 * Uses WordPress apply_filters() function, see WordPress apply_filters() 880 * 881 * @since 1.3 882 * @access public 883 * @link http://core.trac.wordpress.org/browser/trunk/wp-includes/plugin.php#L134 884 */ 885 function apply_filters($tag, $value) 886 { 887 $args = func_get_args(); 888 $args[0] = $this->_get_filter_tag($tag); 889 return call_user_func_array('apply_filters', $args); 890 } 891 892 /** 893 * Uses WordPress remove_filter() function, see WordPress remove_filter() 894 * 895 * @since 1.3 896 * @access public 897 * @link http://core.trac.wordpress.org/browser/trunk/wp-includes/plugin.php#L250 898 */ 899 function remove_filter($tag, $function_to_remove, $priority = 10, $accepted_args = 1) 900 { 901 $tag = $this->_get_filter_tag($tag); 902 return remove_filter($tag, $function_to_remove, $priority, $accepted_args); 903 } 904 905 /** 906 * Used to properly prefix the action tag, the tag is unique to the meta 907 * box instance 908 * 909 * @since 1.3 910 * @access private 911 * @param string $tag name of the action 912 * @return string uniquely prefixed tag name 913 */ 914 function _get_action_tag($tag) 915 { 916 $prefix = 'wpalchemy_action_' . $this->id . '_'; 917 $prefix = preg_replace('/_+/', '_', $prefix); 918 919 $tag = preg_replace('/^'. $prefix .'/i', '', $tag); 920 return $prefix . $tag; 921 } 922 923 /** 924 * Uses WordPress add_action() function, see WordPress add_action() 925 * 926 * @since 1.3 927 * @access public 928 * @link http://core.trac.wordpress.org/browser/trunk/wp-includes/plugin.php#L324 929 */ 930 function add_action($tag, $function_to_add, $priority = 10, $accepted_args = 1) 931 { 932 $tag = $this->_get_action_tag($tag); 933 add_action($tag, $function_to_add, $priority, $accepted_args); 934 } 935 936 /** 937 * Uses WordPress has_action() function, see WordPress has_action() 938 * 939 * @since 1.3 940 * @access public 941 * @link http://core.trac.wordpress.org/browser/trunk/wp-includes/plugin.php#L492 942 */ 943 function has_action($tag, $function_to_check = FALSE) 944 { 945 $tag = $this->_get_action_tag($tag); 946 return has_action($tag, $function_to_check); 947 } 948 949 /** 950 * Uses WordPress remove_action() function, see WordPress remove_action() 951 * 952 * @since 1.3 953 * @access public 954 * @link http://core.trac.wordpress.org/browser/trunk/wp-includes/plugin.php#L513 955 */ 956 function remove_action($tag, $function_to_remove, $priority = 10, $accepted_args = 1) 957 { 958 $tag = $this->_get_action_tag($tag); 959 return remove_action($tag, $function_to_remove, $priority, $accepted_args); 960 } 961 962 /** 963 * Uses WordPress do_action() function, see WordPress do_action() 964 * @since 1.3 965 * @access public 966 * @link http://core.trac.wordpress.org/browser/trunk/wp-includes/plugin.php#L352 967 */ 968 function do_action($tag, $arg = '') 969 { 970 $args = func_get_args(); 971 $args[0] = $this->_get_action_tag($tag); 972 return call_user_func_array('do_action', $args); 973 } 974 975 /** 976 * Used to check if creating a new post or editing one 977 * 978 * @static 979 * @since 1.3.7 980 * @access private 981 * @return bool 982 * @see _is_page() 983 */ 984 function _is_post() 985 { 986 if ('post' == WPAlchemy_MetaBox::_is_post_or_page()) 987 { 988 return TRUE; 989 } 990 991 return FALSE; 992 } 993 994 /** 995 * Used to check if creating a new page or editing one 996 * 997 * @static 998 * @since 1.3.7 999 * @access private 1000 * @return bool 1001 * @see _is_post() 1002 */ 1003 function _is_page() 1004 { 1005 if ('page' == WPAlchemy_MetaBox::_is_post_or_page()) 1006 { 1007 return TRUE; 1008 } 1009 1010 return FALSE; 1011 } 1012 1013 /** 1014 * Used to check if creating or editing a post or page 1015 * 1016 * @static 1017 * @since 1.3.8 1018 * @access private 1019 * @return string "post" or "page" 1020 * @see _is_post(), _is_page() 1021 */ 1022 function _is_post_or_page() 1023 { 1024 $post_type = WPAlchemy_MetaBox::_get_current_post_type(); 1025 1026 if (isset($post_type)) 1027 { 1028 if ('page' == $post_type) 1029 { 1030 return 'page'; 1031 } 1032 else 1033 { 1034 return 'post'; 1035 } 1036 } 1037 1038 return NULL; 1039 } 1040 1041 /** 1042 * Used to check for the current post type, works when creating or editing a 1043 * new post, page or custom post type. 1044 * 1045 * @static 1046 * @since 1.4.6 1047 * @return string [custom_post_type], page or post 1048 */ 1049 function _get_current_post_type() 1050 { 1051 $uri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : NULL ; 1052 1053 if ( isset( $uri ) ) 1054 { 1055 $uri_parts = parse_url($uri); 1056 1057 $file = basename($uri_parts['path']); 1058 1059 if ($uri AND in_array($file, array('post.php', 'post-new.php'))) 1060 { 1061 $post_id = WPAlchemy_MetaBox::_get_post_id(); 1062 1063 $post_type = isset($_GET['post_type']) ? $_GET['post_type'] : NULL ; 1064 1065 $post_type = $post_id ? get_post_type($post_id) : $post_type ; 1066 1067 if (isset($post_type)) 1068 { 1069 return $post_type; 1070 } 1071 else 1072 { 1073 // because of the 'post.php' and 'post-new.php' checks above, we can default to 'post' 1074 return 'post'; 1075 } 1076 } 1077 } 1078 1079 return NULL; 1080 } 1081 1082 /** 1083 * Used to get the current post id. 1084 * 1085 * @static 1086 * @since 1.4.8 1087 * @return int post ID 1088 */ 1089 function _get_post_id() 1090 { 1091 global $post; 1092 1093 $p_post_id = isset($_POST['post_ID']) ? $_POST['post_ID'] : null ; 1094 1095 $g_post_id = isset($_GET['post']) ? $_GET['post'] : null ; 1096 1097 $post_id = $g_post_id ? $g_post_id : $p_post_id ; 1098 1099 $post_id = isset($post->ID) ? $post->ID : $post_id ; 1100 1101 if (isset($post_id)) 1102 { 1103 return (integer) $post_id; 1104 } 1105 1106 return null; 1107 } 1108 1109 /** 1110 * @since 1.0 1111 */ 1112 function can_output() 1113 { 1114 $post_id = WPAlchemy_MetaBox::_get_post_id(); 1115 1116 if (!empty($this->exclude_template) OR !empty($this->include_template)) 1117 { 1118 $template_file = get_post_meta($post_id,'_wp_page_template',TRUE); 1119 } 1120 1121 if 1122 ( 1123 !empty($this->exclude_category) OR 1124 !empty($this->exclude_category_id) OR 1125 !empty($this->include_category) OR 1126 !empty($this->include_category_id) 1127 ) 1128 { 1129 $categories = wp_get_post_categories($post_id,'fields=all'); 1130 } 1131 1132 if 1133 ( 1134 !empty($this->exclude_tag) OR 1135 !empty($this->exclude_tag_id) OR 1136 !empty($this->include_tag) OR 1137 !empty($this->include_tag_id) 1138 ) 1139 { 1140 $tags = wp_get_post_tags($post_id); 1141 } 1142 1143 // processing order: "exclude" then "include" 1144 // processing order: "template" then "category" then "post" 1145 1146 $can_output = TRUE; // include all 1147 1148 if 1149 ( 1150 !empty($this->exclude_template) OR 1151 !empty($this->exclude_category_id) OR 1152 !empty($this->exclude_category) OR 1153 !empty($this->exclude_tag_id) OR 1154 !empty($this->exclude_tag) OR 1155 !empty($this->exclude_post_id) OR 1156 !empty($this->include_template) OR 1157 !empty($this->include_category_id) OR 1158 !empty($this->include_category) OR 1159 !empty($this->include_tag_id) OR 1160 !empty($this->include_tag) OR 1161 !empty($this->include_post_id) 1162 ) 1163 { 1164 if (!empty($this->exclude_template)) 1165 { 1166 if (in_array($template_file,$this->exclude_template)) 1167 { 1168 $can_output = FALSE; 1169 } 1170 } 1171 1172 if (!empty($this->exclude_category_id)) 1173 { 1174 foreach ($categories as $cat) 1175 { 1176 if (in_array($cat->term_id,$this->exclude_category_id)) 1177 { 1178 $can_output = FALSE; 1179 break; 1180 } 1181 } 1182 } 1183 1184 if (!empty($this->exclude_category)) 1185 { 1186 foreach ($categories as $cat) 1187 { 1188 if 1189 ( 1190 in_array($cat->slug,$this->exclude_category) OR 1191 in_array($cat->name,$this->exclude_category) 1192 ) 1193 { 1194 $can_output = FALSE; 1195 break; 1196 } 1197 } 1198 } 1199 1200 if (!empty($this->exclude_tag_id)) 1201 { 1202 foreach ($tags as $tag) 1203 { 1204 if (in_array($tag->term_id,$this->exclude_tag_id)) 1205 { 1206 $can_output = FALSE; 1207 break; 1208 } 1209 } 1210 } 1211 1212 if (!empty($this->exclude_tag)) 1213 { 1214 foreach ($tags as $tag) 1215 { 1216 if 1217 ( 1218 in_array($tag->slug,$this->exclude_tag) OR 1219 in_array($tag->name,$this->exclude_tag) 1220 ) 1221 { 1222 $can_output = FALSE; 1223 break; 1224 } 1225 } 1226 } 1227 1228 if (!empty($this->exclude_post_id)) 1229 { 1230 if (in_array($post_id,$this->exclude_post_id)) 1231 { 1232 $can_output = FALSE; 1233 } 1234 } 1235 1236 // excludes are not set use "include only" mode 1237 1238 if 1239 ( 1240 empty($this->exclude_template) AND 1241 empty($this->exclude_category_id) AND 1242 empty($this->exclude_category) AND 1243 empty($this->exclude_tag_id) AND 1244 empty($this->exclude_tag) AND 1245 empty($this->exclude_post_id) 1246 ) 1247 { 1248 $can_output = FALSE; 1249 } 1250 1251 if (!empty($this->include_template)) 1252 { 1253 if (in_array($template_file,$this->include_template)) 1254 { 1255 $can_output = TRUE; 1256 } 1257 } 1258 1259 if (!empty($this->include_category_id)) 1260 { 1261 foreach ($categories as $cat) 1262 { 1263 if (in_array($cat->term_id,$this->include_category_id)) 1264 { 1265 $can_output = TRUE; 1266 break; 1267 } 1268 } 1269 } 1270 1271 if (!empty($this->include_category)) 1272 { 1273 foreach ($categories as $cat) 1274 { 1275 if 1276 ( 1277 in_array($cat->slug,$this->include_category) OR 1278 in_array($cat->name,$this->include_category) 1279 ) 1280 { 1281 $can_output = TRUE; 1282 break; 1283 } 1284 } 1285 } 1286 1287 if (!empty($this->include_tag_id)) 1288 { 1289 foreach ($tags as $tag) 1290 { 1291 if (in_array($tag->term_id,$this->include_tag_id)) 1292 { 1293 $can_output = TRUE; 1294 break; 1295 } 1296 } 1297 } 1298 1299 if (!empty($this->include_tag)) 1300 { 1301 foreach ($tags as $tag) 1302 { 1303 if 1304 ( 1305 in_array($tag->slug,$this->include_tag) OR 1306 in_array($tag->name,$this->include_tag) 1307 ) 1308 { 1309 $can_output = TRUE; 1310 break; 1311 } 1312 } 1313 } 1314 1315 if (!empty($this->include_post_id)) 1316 { 1317 if (in_array($post_id,$this->include_post_id)) 1318 { 1319 $can_output = TRUE; 1320 } 1321 } 1322 } 1323 1324 $post_type = WPAlchemy_MetaBox::_get_current_post_type(); 1325 1326 if (isset($post_type) AND ! in_array($post_type, $this->types)) 1327 { 1328 $can_output = FALSE; 1329 } 1330 1331 // filter: output (can_output) 1332 if ($this->has_filter('output')) 1333 { 1334 $can_output = $this->apply_filters('output', $post_id); 1335 } 1336 1337 return $can_output; 1338 } 1339 1340 /** 1341 * Used to insert global STYLE or SCRIPT tags into the head, called on 1342 * WordPress admin_footer action. 1343 * 1344 * @static 1345 * @since 1.3 1346 * @access private 1347 * @see _global_foot() 1348 */ 1349 function _global_head() 1350 { 1351 // must be creating or editing a post or page 1352 if ( ! WPAlchemy_MetaBox::_is_post() AND ! WPAlchemy_MetaBox::_is_page()) return; 1353 1354 // todo: you're assuming people will want to use this exact functionality 1355 // consider giving a developer access to change this via hooks/callbacks 1356 1357 // include javascript for special functionality 1358 ?><style type="text/css"> .wpa_group.tocopy { display:none; } </style> 1359 <script type="text/javascript"> 1360 /* <![CDATA[ */ 1361 jQuery(function($) 1362 { 1363 $(document).click(function(e) 1364 { 1365 var elem = $(e.target); 1366 1367 if (elem.attr('class') && elem.filter('[class*=dodelete]').length) 1368 { 1369 e.preventDefault(); 1370 1371 var p = elem.parents('.postbox'); /*wp*/ 1372 1373 var the_name = elem.attr('class').match(/dodelete-([a-zA-Z0-9_-]*)/i); 1374 1375 the_name = (the_name && the_name[1]) ? the_name[1] : null ; 1376 1377 /* todo: expose and allow editing of this message */ 1378 if (confirm('This action can not be undone, are you sure?')) 1379 { 1380 if (the_name) 1381 { 1382 $('.wpa_group-'+ the_name, p).not('.tocopy').remove(); 1383 } 1384 else 1385 { 1386 elem.parents('.wpa_group').remove(); 1387 } 1388 1389 the_name = elem.parents('.wpa_group').attr('class').match(/wpa_group-([a-zA-Z0-9_-]*)/i)[1]; 1390 1391 checkLoopLimit(the_name); 1392 1393 $.wpalchemy.trigger('wpa_delete'); 1394 } 1395 } 1396 }); 1397 1398 $('[class*=docopy-]').click(function(e) 1399 { 1400 e.preventDefault(); 1401 1402 var p = $(this).parents('.postbox'); /*wp*/ 1403 1404 var the_name = $(this).attr('class').match(/docopy-([a-zA-Z0-9_-]*)/i)[1]; 1405 1406 var the_group = $('.wpa_group-'+ the_name +':first.tocopy', p); 1407 1408 var the_clone = the_group.clone().removeClass('tocopy last'); 1409 1410 var the_props = ['name', 'id', 'for', 'class']; 1411 1412 the_group.find('*').each(function(i, elem) 1413 { 1414 for (var j = 0; j < the_props.length; j++) 1415 { 1416 var the_prop = $(elem).attr(the_props[j]); 1417 1418 if (the_prop) 1419 { 1420 var the_match = the_prop.match(/\[(\d+)\]/i); 1421 1422 if (the_match) 1423 { 1424 the_prop = the_prop.replace(the_match[0],'['+ (+the_match[1]+1) +']'); 1425 1426 $(elem).attr(the_props[j], the_prop); 1427 } 1428 1429 the_match = null; 1430 1431 // todo: this may prove to be too broad of a search 1432 the_match = the_prop.match(/n(\d+)/i); 1433 1434 if (the_match) 1435 { 1436 the_prop = the_prop.replace(the_match[0], 'n' + (+the_match[1]+1)); 1437 1438 $(elem).attr(the_props[j], the_prop); 1439 } 1440 } 1441 } 1442 }); 1443 1444 if ($(this).hasClass('ontop')) 1445 { 1446 $('.wpa_group-'+ the_name +':first', p).before(the_clone); 1447 } 1448 else 1449 { 1450 the_group.before(the_clone); 1451 } 1452 1453 checkLoopLimit(the_name); 1454 1455 $.wpalchemy.trigger('wpa_copy', [the_clone]); 1456 }); 1457 1458 function checkLoopLimit(name) 1459 { 1460 var elem = $('.docopy-' + name); 1461 1462 var the_class = $('.wpa_loop-' + name).attr('class'); 1463 1464 if (the_class) 1465 { 1466 var the_match = the_class.match(/wpa_loop_limit-([0-9]*)/i); 1467 1468 if (the_match) 1469 { 1470 var the_limit = the_match[1]; 1471 1472 if ($('.wpa_group-' + name).not('.wpa_group.tocopy').length >= the_limit) 1473 { 1474 elem.hide(); 1475 } 1476 else 1477 { 1478 elem.show(); 1479 } 1480 } 1481 } 1482 } 1483 1484 /* do an initial limit check, show or hide buttons */ 1485 $('[class*=docopy-]').each(function() 1486 { 1487 var the_name = $(this).attr('class').match(/docopy-([a-zA-Z0-9_-]*)/i)[1]; 1488 1489 checkLoopLimit(the_name); 1490 }); 1491 }); 1492 /* ]]> */ 1493 </script> 1494 <?php 1495 } 1496 1497 /** 1498 * Used to insert global SCRIPT tags into the footer, called on WordPress 1499 * admin_footer action. 1500 * 1501 * @static 1502 * @since 1.3 1503 * @access private 1504 * @see _global_head() 1505 */ 1506 function _global_foot() 1507 { 1508 // must be creating or editing a post or page 1509 if ( ! WPAlchemy_MetaBox::_is_post() AND ! WPAlchemy_MetaBox::_is_page()) return; 1510 1511 ?> 1512 <script type="text/javascript"> 1513 /* <![CDATA[ */ 1514 (function($){ /* not using jQuery ondomready, code runs right away in footer */ 1515 1516 /* use a global dom element to attach events to */ 1517 $.wpalchemy = $('<div></div>').attr('id','wpalchemy').appendTo('body'); 1518 1519 })(jQuery); 1520 /* ]]> */ 1521 </script> 1522 <?php 1523 } 1524 1525 /** 1526 * Gets the meta data for a meta box 1527 * 1528 * @since 1.0 1529 * @access public 1530 * @param int $post_id optional post ID for which to retrieve the meta data 1531 * @return array 1532 * @see _meta 1533 */ 1534 function the_meta($post_id = NULL) 1535 { 1536 return $this->_meta($post_id); 1537 } 1538 1539 /** 1540 * Gets the meta data for a meta box 1541 * 1542 * Internal method calls will typically bypass the data retrieval and will 1543 * immediately return the current meta data 1544 * 1545 * @since 1.3 1546 * @access private 1547 * @param int $post_id optional post ID for which to retrieve the meta data 1548 * @param bool $internal optional boolean if internally calling 1549 * @return array 1550 * @see the_meta() 1551 */ 1552 function _meta($post_id = NULL, $internal = FALSE) 1553 { 1554 if ( ! is_numeric($post_id)) 1555 { 1556 if ($internal AND $this->current_post_id) 1557 { 1558 $post_id = $this->current_post_id; 1559 } 1560 else 1561 { 1562 global $post; 1563 1564 $post_id = $post->ID; 1565 } 1566 } 1567 1568 // this allows multiple internal calls to _meta() without having to fetch data everytime 1569 if ($internal AND !empty($this->meta) AND $this->current_post_id == $post_id) return $this->meta; 1570 1571 $this->current_post_id = $post_id; 1572 1573 // WPALCHEMY_MODE_ARRAY 1574 1575 $meta = get_post_meta($post_id, $this->id, TRUE); 1576 1577 // WPALCHEMY_MODE_EXTRACT 1578 1579 $fields = get_post_meta($post_id, $this->id . '_fields', TRUE); 1580 1581 if ( ! empty($fields) AND is_array($fields)) 1582 { 1583 $meta = array(); 1584 1585 foreach ($fields as $field) 1586 { 1587 $field_noprefix = preg_replace('/^' . $this->prefix . '/i', '', $field); 1588 $meta[$field_noprefix] = get_post_meta($post_id, $field, TRUE); 1589 } 1590 } 1591 1592 $this->meta = $meta; 1593 1594 return $this->meta; 1595 } 1596 1597 // user can also use the_ID(), php functions are case-insensitive 1598 /** 1599 * @since 1.0 1600 * @access public 1601 */ 1602 function the_id() 1603 { 1604 echo $this->get_the_id(); 1605 } 1606 1607 /** 1608 * @since 1.0 1609 * @access public 1610 */ 1611 function get_the_id() 1612 { 1613 return $this->id; 1614 } 1615 1616 /** 1617 * @since 1.0 1618 * @access public 1619 */ 1620 function the_field($n, $hint = NULL) 1621 { 1622 if ($this->in_loop) $this->subname = $n; 1623 else $this->name = $n; 1624 1625 $this->hint = $hint; 1626 } 1627 1628 /** 1629 * @since 1.0 1630 * @access public 1631 */ 1632 function have_value($n = NULL) 1633 { 1634 if ($this->get_the_value($n)) return TRUE; 1635 1636 return FALSE; 1637 } 1638 1639 /** 1640 * @since 1.0 1641 * @access public 1642 */ 1643 function the_value($n = NULL) 1644 { 1645 echo $this->get_the_value($n); 1646 } 1647 1648 /** 1649 * @since 1.0 1650 * @access public 1651 */ 1652 function get_the_value($n = NULL, $collection = FALSE) 1653 { 1654 $this->_meta(NULL, TRUE); 1655 1656 $value = null; 1657 1658 if ($this->in_loop) 1659 { 1660 if(isset($this->meta[$this->name])) 1661 { 1662 $n = is_null($n) ? $this->subname : $n ; 1663 1664 if(!is_null($n)) 1665 { 1666 if ($collection) 1667 { 1668 if(isset($this->meta[$this->name][$this->current])) 1669 { 1670 $value = $this->meta[$this->name][$this->current]; 1671 } 1672 } 1673 else 1674 { 1675 if(isset($this->meta[$this->name][$this->current][$n])) 1676 { 1677 $value = $this->meta[$this->name][$this->current][$n]; 1678 } 1679 } 1680 } 1681 else 1682 { 1683 if ($collection) 1684 { 1685 if(isset($this->meta[$this->name])) 1686 { 1687 $value = $this->meta[$this->name]; 1688 } 1689 } 1690 else 1691 { 1692 if(isset($this->meta[$this->name][$this->current])) 1693 { 1694 $value = $this->meta[$this->name][$this->current]; 1695 } 1696 } 1697 } 1698 } 1699 } 1700 else 1701 { 1702 $n = is_null($n) ? $this->name : $n ; 1703 1704 if(isset($this->meta[$n])) 1705 { 1706 $value = $this->meta[$n]; 1707 } 1708 } 1709 1710 if (is_string($value) || is_numeric($value)) 1711 { 1712 if ($this->in_template) 1713 { 1714 return htmlentities($value, ENT_QUOTES, 'UTF-8'); 1715 } 1716 else 1717 { 1718 // http://wordpress.org/support/topic/call-function-called-by-embed-shortcode-direct 1719 // http://phpdoc.wordpress.org/trunk/WordPress/Embed/WP_Embed.html#run_shortcode 1720 1721 global $wp_embed; 1722 1723 return do_shortcode($wp_embed->run_shortcode($value)); 1724 } 1725 } 1726 else 1727 { 1728 // value can sometimes be an array 1729 return $value; 1730 } 1731 } 1732 1733 /** 1734 * @since 1.0 1735 * @access public 1736 */ 1737 function the_name($n = NULL) 1738 { 1739 echo $this->get_the_name($n); 1740 } 1741 1742 /** 1743 * @since 1.0 1744 * @access public 1745 */ 1746 function get_the_name($n = NULL) 1747 { 1748 if (!$this->in_template AND $this->mode == WPALCHEMY_MODE_EXTRACT) 1749 { 1750 return $this->prefix . str_replace($this->prefix, '', is_null($n) ? $this->name : $n); 1751 } 1752 1753 if ($this->in_loop) 1754 { 1755 $n = is_null($n) ? $this->subname : $n ; 1756 1757 if (!is_null($n)) $the_field = $this->id . '[' . $this->name . '][' . $this->current . '][' . $n . ']' ; 1758 1759 else $the_field = $this->id . '[' . $this->name . '][' . $this->current . ']' ; 1760 } 1761 else 1762 { 1763 $n = is_null($n) ? $this->name : $n ; 1764 1765 $the_field = $this->id . '[' . $n . ']'; 1766 } 1767 1768 $hints = array 1769 ( 1770 WPALCHEMY_FIELD_HINT_CHECKBOX_MULTI, 1771 WPALCHEMY_FIELD_HINT_SELECT_MULTI, 1772 WPALCHEMY_FIELD_HINT_SELECT_MULTIPLE, 1773 ); 1774 1775 if (in_array($this->hint, $hints)) 1776 { 1777 $the_field .= '[]'; 1778 } 1779 1780 return $the_field; 1781 } 1782 1783 /** 1784 * @since 1.1 1785 * @access public 1786 */ 1787 function the_index() 1788 { 1789 echo $this->get_the_index(); 1790 } 1791 1792 /** 1793 * @since 1.1 1794 * @access public 1795 */ 1796 function get_the_index() 1797 { 1798 return $this->in_loop ? $this->current : 0 ; 1799 } 1800 1801 /** 1802 * @since 1.0 1803 * @access public 1804 */ 1805 function is_first() 1806 { 1807 if ($this->in_loop AND $this->current == 0) return TRUE; 1808 1809 return FALSE; 1810 } 1811 1812 /** 1813 * @since 1.0 1814 * @access public 1815 */ 1816 function is_last() 1817 { 1818 if ($this->in_loop AND ($this->current+1) == $this->length) return TRUE; 1819 1820 return FALSE; 1821 } 1822 1823 /** 1824 * Used to check if a value is a match 1825 * 1826 * @since 1.1 1827 * @access public 1828 * @param string $n the field name to check or the value to check for (if the_field() is used prior) 1829 * @param string $v optional the value to check for 1830 * @return bool 1831 * @see is_value() 1832 */ 1833 function is_value($n, $v = NULL) 1834 { 1835 if (is_null($v)) 1836 { 1837 $the_value = $this->get_the_value(); 1838 1839 $v = $n; 1840 } 1841 else 1842 { 1843 $the_value = $this->get_the_value($n); 1844 } 1845 1846 if($v == $the_value) return TRUE; 1847 1848 return FALSE; 1849 } 1850 1851 /** 1852 * Used to check if a value is selected, useful when working with checkbox, 1853 * radio and select values. 1854 * 1855 * @since 1.3 1856 * @access public 1857 * @param string $n the field name to check or the value to check for (if the_field() is used prior) 1858 * @param string $v optional the value to check for 1859 * @return bool 1860 * @see is_value() 1861 */ 1862 function is_selected($n, $v = NULL) 1863 { 1864 if (is_null($v)) 1865 { 1866 $the_value = $this->get_the_value(NULL); 1867 1868 $v = $n; 1869 } 1870 else 1871 { 1872 $the_value = $this->get_the_value($n); 1873 } 1874 1875 if (is_array($the_value)) 1876 { 1877 if (in_array($v, $the_value)) return TRUE; 1878 } 1879 elseif($v == $the_value) 1880 { 1881 return TRUE; 1882 } 1883 1884 return FALSE; 1885 } 1886 1887 /** 1888 * Prints the current state of a checkbox field and should be used inline 1889 * within the INPUT tag. 1890 * 1891 * @since 1.3 1892 * @access public 1893 * @param string $n the field name to check or the value to check for (if the_field() is used prior) 1894 * @param string $v optional the value to check for 1895 * @see get_the_checkbox_state() 1896 */ 1897 function the_checkbox_state($n, $v = NULL) 1898 { 1899 echo $this->get_the_checkbox_state($n, $v); 1900 } 1901 1902 /** 1903 * Returns the current state of a checkbox field, the returned string is 1904 * suitable to be used inline within the INPUT tag. 1905 * 1906 * @since 1.3 1907 * @access public 1908 * @param string $n the field name to check or the value to check for (if the_field() is used prior) 1909 * @param string $v optional the value to check for 1910 * @return string suitable to be used inline within the INPUT tag 1911 * @see the_checkbox_state() 1912 */ 1913 function get_the_checkbox_state($n, $v = NULL) 1914 { 1915 if ($this->is_selected($n, $v)) return ' checked="checked"'; 1916 } 1917 1918 /** 1919 * Prints the current state of a radio field and should be used inline 1920 * within the INPUT tag. 1921 * 1922 * @since 1.3 1923 * @access public 1924 * @param string $n the field name to check or the value to check for (if the_field() is used prior) 1925 * @param string $v optional the value to check for 1926 * @see get_the_radio_state() 1927 */ 1928 function the_radio_state($n, $v = NULL) 1929 { 1930 echo $this->get_the_checkbox_state($n, $v); 1931 } 1932 1933 /** 1934 * Returns the current state of a radio field, the returned string is 1935 * suitable to be used inline within the INPUT tag. 1936 * 1937 * @since 1.3 1938 * @access public 1939 * @param string $n the field name to check or the value to check for (if the_field() is used prior) 1940 * @param string $v optional the value to check for 1941 * @return string suitable to be used inline within the INPUT tag 1942 * @see the_radio_state() 1943 */ 1944 function get_the_radio_state($n, $v = NULL) 1945 { 1946 return $this->get_the_checkbox_state($n, $v); 1947 } 1948 1949 /** 1950 * Prints the current state of a select field and should be used inline 1951 * within the SELECT tag. 1952 * 1953 * @since 1.3 1954 * @access public 1955 * @param string $n the field name to check or the value to check for (if the_field() is used prior) 1956 * @param string $v optional the value to check for 1957 * @see get_the_select_state() 1958 */ 1959 function the_select_state($n, $v = NULL) 1960 { 1961 echo $this->get_the_select_state($n, $v); 1962 } 1963 1964 /** 1965 * Returns the current state of a select field, the returned string is 1966 * suitable to be used inline within the SELECT tag. 1967 * 1968 * @since 1.3 1969 * @access public 1970 * @param string $n the field name to check or the value to check for (if the_field() is used prior) 1971 * @param string $v optional the value to check for 1972 * @return string suitable to be used inline within the SELECT tag 1973 * @see the_select_state() 1974 */ 1975 function get_the_select_state($n, $v = NULL) 1976 { 1977 if ($this->is_selected($n, $v)) return ' selected="selected"'; 1978 } 1979 1980 /** 1981 * @since 1.1 1982 * @access public 1983 */ 1984 function the_group_open($t = 'div') 1985 { 1986 echo $this->get_the_group_open($t); 1987 } 1988 1989 /** 1990 * @since 1.1 1991 * @access public 1992 */ 1993 function get_the_group_open($t = 'div') 1994 { 1995 $this->group_tag = $t; 1996 1997 $loop_open = NULL; 1998 1999 $loop_open_classes = array('wpa_loop', 'wpa_loop-' . $this->name); 2000 2001 $css_class = array('wpa_group', 'wpa_group-'. $this->name); 2002 2003 if ($this->is_first()) 2004 { 2005 array_push($css_class, 'first'); 2006 2007 $loop_open = '<div class="wpa_loop">'; 2008 2009 if (isset($this->_loop_data->limit)) 2010 { 2011 array_push($loop_open_classes, 'wpa_loop_limit-' . $this->_loop_data->limit); 2012 } 2013 2014 $loop_open = '<div id="wpa_loop-'. $this->name .'" class="' . implode(' ', $loop_open_classes) . '">'; 2015 } 2016 2017 if ($this->is_last()) 2018 { 2019 array_push($css_class, 'last'); 2020 2021 if ($this->in_loop == 'multi') 2022 { 2023 array_push($css_class, 'tocopy'); 2024 } 2025 } 2026 2027 return $loop_open . '<' . $t . ' class="'. implode(' ', $css_class) . '">'; 2028 } 2029 2030 /** 2031 * @since 1.1 2032 * @access public 2033 */ 2034 function the_group_close() 2035 { 2036 echo $this->get_the_group_close(); 2037 } 2038 2039 /** 2040 * @since 1.1 2041 * @access public 2042 */ 2043 function get_the_group_close() 2044 { 2045 $loop_close = NULL; 2046 2047 if ($this->is_last()) 2048 { 2049 $loop_close = '</div>'; 2050 } 2051 2052 return '</' . $this->group_tag . '>' . $loop_close; 2053 } 2054 2055 /** 2056 * @since 1.1 2057 * @access public 2058 */ 2059 function have_fields_and_multi($n, $options = NULL) 2060 { 2061 if (is_array($options)) 2062 { 2063 // use as stdClass object 2064 $options = (object)$options; 2065 2066 $length = @$options->length; 2067 2068 $this->_loop_data->limit = @$options->limit; 2069 } 2070 else 2071 { 2072 // backward compatibility (bc) 2073 $length = $options; 2074 } 2075 2076 $this->_meta(NULL, TRUE); 2077 2078 $this->in_loop = 'multi'; 2079 2080 return $this->_loop($n, $length, 2); 2081 } 2082 2083 /** 2084 * @deprecated 2085 * @since 1.0 2086 * @access public 2087 */ 2088 function have_fields_and_one($n) 2089 { 2090 $this->_meta(NULL, TRUE); 2091 $this->in_loop = 'single'; 2092 return $this->_loop($n,NULL,1); 2093 } 2094 2095 /** 2096 * @since 1.0 2097 * @access public 2098 */ 2099 function have_fields($n,$length=NULL) 2100 { 2101 $this->_meta(NULL, TRUE); 2102 $this->in_loop = 'normal'; 2103 return $this->_loop($n,$length); 2104 } 2105 2106 /** 2107 * @since 1.0 2108 * @access private 2109 */ 2110 function _loop($n,$length=NULL,$and_one=0) 2111 { 2112 if (!$this->in_loop) 2113 { 2114 $this->in_loop = TRUE; 2115 } 2116 2117 $this->name = $n; 2118 2119 $cnt = count(!empty($this->meta[$n])?$this->meta[$n]:NULL); 2120 2121 $length = is_null($length) ? $cnt : $length ; 2122 2123 if ($this->in_loop == 'multi' AND $cnt > $length) $length = $cnt; 2124 2125 $this->length = $length; 2126 2127 if ($this->in_template AND $and_one) 2128 { 2129 if ($length == 0) 2130 { 2131 $this->length = $and_one; 2132 } 2133 else 2134 { 2135 $this->length = $length+1; 2136 } 2137 } 2138 2139 $this->current++; 2140 2141 if ($this->current < $this->length) 2142 { 2143 $this->subname = NULL; 2144 2145 $this->fieldtype = NULL; 2146 2147 return TRUE; 2148 } 2149 else if ($this->current == $this->length) 2150 { 2151 $this->name = NULL; 2152 2153 $this->current = -1; 2154 } 2155 2156 $this->in_loop = FALSE; 2157 2158 $this->_loop_data = new stdClass; 2159 2160 return FALSE; 2161 } 2162 2163 /** 2164 * @since 1.0 2165 * @access private 2166 */ 2167 function _save($post_id) 2168 { 2169 /** 2170 * note: the "save_post" action fires for saving revisions and post/pages, 2171 * when saving a post this function fires twice, once for a revision save, 2172 * and again for the post/page save ... the $post_id is different for the 2173 * revision save, this means that "get_post_meta()" will not work if trying 2174 * to get values for a revision (as it has no post meta data) 2175 * see http://alexking.org/blog/2008/09/06/wordpress-26x-duplicate-custom-field-issue 2176 * 2177 * why let the code run twice? wordpress does not currently save post meta 2178 * data per revisions (I think it should, so users can do a complete revert), 2179 * so in the case that this functionality changes, let it run twice 2180 */ 2181 2182 $real_post_id = isset($_POST['post_ID']) ? $_POST['post_ID'] : NULL ; 2183 2184 // check autosave 2185 if (defined('DOING_AUTOSAVE') AND DOING_AUTOSAVE AND !$this->autosave) return $post_id; 2186 2187 // make sure data came from our meta box, verify nonce 2188 $nonce = isset($_POST[$this->id.'_nonce']) ? $_POST[$this->id.'_nonce'] : NULL ; 2189 if (!wp_verify_nonce($nonce, $this->id)) return $post_id; 2190 2191 // check user permissions 2192 if ($_POST['post_type'] == 'page') 2193 { 2194 if (!current_user_can('edit_page', $post_id)) return $post_id; 2195 } 2196 else 2197 { 2198 if (!current_user_can('edit_post', $post_id)) return $post_id; 2199 } 2200 2201 // authentication passed, save data 2202 2203 $new_data = isset( $_POST[$this->id] ) ? $_POST[$this->id] : NULL ; 2204 2205 WPAlchemy_MetaBox::clean($new_data); 2206 2207 if (empty($new_data)) 2208 { 2209 $new_data = NULL; 2210 } 2211 2212 // filter: save 2213 if ($this->has_filter('save')) 2214 { 2215 $new_data = $this->apply_filters('save', $new_data, $real_post_id); 2216 2217 /** 2218 * halt saving 2219 * @since 1.3.4 2220 */ 2221 if (FALSE === $new_data) return $post_id; 2222 2223 WPAlchemy_MetaBox::clean($new_data); 2224 } 2225 2226 // get current fields, use $real_post_id (checked for in both modes) 2227 $current_fields = get_post_meta($real_post_id, $this->id . '_fields', TRUE); 2228 2229 if ($this->mode == WPALCHEMY_MODE_EXTRACT) 2230 { 2231 $new_fields = array(); 2232 2233 if (is_array($new_data)) 2234 { 2235 foreach ($new_data as $k => $v) 2236 { 2237 $field = $this->prefix . $k; 2238 2239 array_push($new_fields,$field); 2240 2241 $new_value = $new_data[$k]; 2242 2243 if (is_null($new_value)) 2244 { 2245 delete_post_meta($post_id, $field); 2246 } 2247 else 2248 { 2249 update_post_meta($post_id, $field, $new_value); 2250 } 2251 } 2252 } 2253 2254 $diff_fields = array_diff((array)$current_fields,$new_fields); 2255 2256 if (is_array($diff_fields)) 2257 { 2258 foreach ($diff_fields as $field) 2259 { 2260 delete_post_meta($post_id,$field); 2261 } 2262 } 2263 2264 delete_post_meta($post_id, $this->id . '_fields'); 2265 2266 if ( ! empty($new_fields)) 2267 { 2268 add_post_meta($post_id,$this->id . '_fields', $new_fields, TRUE); 2269 } 2270 2271 // keep data tidy, delete values if previously using WPALCHEMY_MODE_ARRAY 2272 delete_post_meta($post_id, $this->id); 2273 } 2274 else 2275 { 2276 if (is_null($new_data)) 2277 { 2278 delete_post_meta($post_id, $this->id); 2279 } 2280 else 2281 { 2282 update_post_meta($post_id, $this->id, $new_data); 2283 } 2284 2285 // keep data tidy, delete values if previously using WPALCHEMY_MODE_EXTRACT 2286 if (is_array($current_fields)) 2287 { 2288 foreach ($current_fields as $field) 2289 { 2290 delete_post_meta($post_id, $field); 2291 } 2292 2293 delete_post_meta($post_id, $this->id . '_fields'); 2294 } 2295 } 2296 2297 // action: save 2298 if ($this->has_action('save')) 2299 { 2300 $this->do_action('save', $new_data, $real_post_id); 2301 } 2302 2303 return $post_id; 2304 } 2305 2306 /** 2307 * Cleans an array, removing blank ('') values 2308 * 2309 * @static 2310 * @since 1.0 2311 * @access public 2312 * @param array the array to clean (passed by reference) 2313 */ 2314 function clean(&$arr) 2315 { 2316 if (is_array($arr)) 2317 { 2318 foreach ($arr as $i => $v) 2319 { 2320 if (is_array($arr[$i])) 2321 { 2322 WPAlchemy_MetaBox::clean($arr[$i]); 2323 2324 if (!count($arr[$i])) 2325 { 2326 unset($arr[$i]); 2327 } 2328 } 2329 else 2330 { 2331 if ('' == trim($arr[$i]) OR is_null($arr[$i])) 2332 { 2333 unset($arr[$i]); 2334 } 2335 } 2336 } 2337 2338 if (!count($arr)) 2339 { 2340 $arr = array(); 2341 } 2342 else 2343 { 2344 $keys = array_keys($arr); 2345 2346 $is_numeric = TRUE; 2347 2348 foreach ($keys as $key) 2349 { 2350 if (!is_numeric($key)) 2351 { 2352 $is_numeric = FALSE; 2353 break; 2354 } 2355 } 2356 2357 if ($is_numeric) 2358 { 2359 $arr = array_values($arr); 2360 } 2361 } 2362 } 2363 } 50 /** 51 * User defined identifier for the meta box, prefix with an underscore to 52 * prevent option(s) form showing up in the custom fields meta box, this 53 * option should be used when instantiating the class. 54 * 55 * @since 1.0 56 * @var string required 57 */ 58 public $id; 59 60 /** 61 * Used to set the title of the meta box, this option should be used when 62 * instantiating the class. 63 * 64 * @since 1.0 65 * @var string required 66 * @see $hide_title 67 */ 68 public $title = 'Custom Meta'; 69 70 /** 71 * Used to set the meta box content, the contents of your meta box should be 72 * defined within this file, this option should be used when instantiating 73 * the class. 74 * 75 * @since 1.0 76 * @var string required 77 */ 78 public $template; 79 80 /** 81 * Used to set the post types that the meta box can appear in, this option 82 * should be used when instantiating the class. 83 * 84 * @since 1.0 85 * @var array 86 */ 87 public $types; 88 89 /** 90 * @since 1.0 91 * @var bool 92 */ 93 public $context = 'normal'; 94 95 /** 96 * @since 1.0 97 * @var bool 98 */ 99 public $priority = 'high'; 100 101 /** 102 * @since 1.0 103 * @var bool 104 */ 105 public $autosave = TRUE; 106 107 /** 108 * Used to set how the class does its data storage, data will be stored as 109 * an associative array in a single meta entry in the wp_postmeta table or 110 * data can be set and individual entries in the wp_postmeta table, the 111 * following constants should be used when setting this option, 112 * WPALCHEMY_MODE_ARRAY (default) and WPALCHEMY_MODE_EXTRACT, this option 113 * should be used when instantiating the class. 114 * 115 * @since 1.2 116 * @var string 117 */ 118 public $mode = WPALCHEMY_MODE_ARRAY; 119 120 /** 121 * When the mode option is set to WPALCHEMY_MODE_EXTRACT, you have to take 122 * care to avoid name collisions with other meta entries. Use this option to 123 * automatically add a prefix to your variables, this option should be used 124 * when instantiating the class. 125 * 126 * @since 1.2 127 * @var array 128 */ 129 public $prefix; 130 131 /** 132 * @since 1.0 133 * @var bool 134 */ 135 public $exclude_template; 136 137 /** 138 * @since 1.0 139 * @var bool 140 */ 141 public $exclude_category_id; 142 143 /** 144 * @since 1.0 145 * @var bool 146 */ 147 public $exclude_category; 148 149 /** 150 * @since 1.0 151 * @var bool 152 */ 153 public $exclude_tag_id; 154 155 /** 156 * @since 1.0 157 * @var bool 158 */ 159 public $exclude_tag; 160 161 /** 162 * @since 1.0 163 * @var bool 164 */ 165 public $exclude_post_id; 166 167 /** 168 * @since 1.0 169 * @var bool 170 */ 171 public $include_template; 172 173 /** 174 * @since 1.0 175 * @var bool 176 */ 177 public $include_category_id; 178 179 /** 180 * @since 1.0 181 * @var bool 182 */ 183 public $include_category; 184 185 /** 186 * @since 1.0 187 * @var bool 188 */ 189 public $include_tag_id; 190 191 /** 192 * @since 1.0 193 * @var bool 194 */ 195 public $include_tag; 196 197 /** 198 * @since 1.0 199 * @var bool 200 */ 201 public $include_post_id; 202 203 /** 204 * Callback used on the WordPress "admin_init" action, the main benefit is 205 * that this callback is executed only when the meta box is present, this 206 * option should be used when instantiating the class. 207 * 208 * @since 1.3.4 209 * @var string|array optional 210 */ 211 public $init_action; 212 213 /** 214 * Callback used to override when the meta box gets displayed, must return 215 * true or false to determine if the meta box should or should not be 216 * displayed, this option should be used when instantiating the class. 217 * 218 * @since 1.3 219 * @var string|array optional 220 * @param array $post_id first variable passed to the callback function 221 * @see can_output() 222 */ 223 public $output_filter; 224 225 /** 226 * Callback used to override or insert meta data before saving, you can halt 227 * saving by passing back FALSE (return FALSE), this option should be used 228 * when instantiating the class. 229 * 230 * @since 1.3 231 * @var string|array optional 232 * @param array $meta meta box data, first variable passed to the callback function 233 * @param string $post_id second variable passed to the callback function 234 * @see $save_action, add_filter() 235 */ 236 public $save_filter; 237 238 /** 239 * Callback used to execute custom code after saving, this option should be 240 * used when instantiating the class. 241 * 242 * @since 1.3 243 * @var string|array optional 244 * @param array $meta meta box data, first variable passed to the callback function 245 * @param string $post_id second variable passed to the callback function 246 * @see $save_filter, add_filter() 247 */ 248 public $save_action; 249 250 /** 251 * Callback used to override or insert STYLE or SCRIPT tags into the head, 252 * this option should be used when instantiating the class. 253 * 254 * @since 1.3 255 * @var string|array optional 256 * @param array $content current head content, first variable passed to the callback function 257 * @see $head_action, add_filter() 258 */ 259 public $head_filter; 260 261 /** 262 * Callback used to insert STYLE or SCRIPT tags into the head, 263 * this option should be used when instantiating the class. 264 * 265 * @since 1.3 266 * @var string|array optional 267 * @see $head_filter, add_action() 268 */ 269 public $head_action; 270 271 /** 272 * Callback used to override or insert SCRIPT tags into the footer, this 273 * option should be used when instantiating the class. 274 * 275 * @since 1.3 276 * @var string|array optional 277 * @param array $content current foot content, first variable passed to the callback function 278 * @see $foot_action, add_filter() 279 */ 280 public $foot_filter; 281 282 /** 283 * Callback used to insert SCRIPT tags into the footer, this option should 284 * be used when instantiating the class. 285 * 286 * @since 1.3 287 * @var string|array optional 288 * @see $foot_filter, add_action() 289 */ 290 public $foot_action; 291 292 /** 293 * Used to hide the default content editor in a page or post, this option 294 * should be used when instantiating the class. 295 * 296 * @since 1.3 297 * @var bool optional 298 */ 299 public $hide_editor = FALSE; 300 301 /** 302 * Used in conjunction with the "hide_editor" option, prevents the media 303 * buttons from also being hidden. 304 * 305 * @since 1.5 306 * @var bool optional 307 */ 308 public $use_media_buttons = FALSE; 309 310 /** 311 * Used to hide the meta box title, this option should be used when 312 * instantiating the class. 313 * 314 * @since 1.3 315 * @var bool optional 316 * @see $title 317 */ 318 public $hide_title = FALSE; 319 320 /** 321 * Used to lock a meta box in place, possible values are: top, bottom, 322 * before_post_title, after_post_title, this option should be used when 323 * instantiating the class. 324 * 325 * @since 1.3.3 326 * @var string optional possible values are: top, bottom, before_post_title, after_post_title 327 */ 328 public $lock; 329 330 /** 331 * Used to lock a meta box at top (below the default content editor), this 332 * option should be used when instantiating the class. 333 * 334 * @deprecated deprecated since version 1.3.3 335 * @since 1.3 336 * @var bool optional 337 * @see $lock 338 */ 339 public $lock_on_top = FALSE; 340 341 /** 342 * Used to lock a meta box at bottom, this option should be used when 343 * instantiating the class. 344 * 345 * @deprecated deprecated since version 1.3.3 346 * @since 1.3 347 * @var bool optional 348 * @see $lock 349 */ 350 public $lock_on_bottom = FALSE; 351 352 /** 353 * Used to set the initial view state of the meta box, possible values are: 354 * opened, closed, always_opened, this option should be used when 355 * instantiating the class. 356 * 357 * @since 1.3.3 358 * @var string optional possible values are: opened, closed, always_opened 359 */ 360 public $view; 361 362 /** 363 * Used to hide the show/hide checkbox option from the screen options area, 364 * this option should be used when instantiating the class. 365 * 366 * @since 1.3.4 367 * @var bool optional 368 */ 369 public $hide_screen_option = FALSE; 370 371 // private 372 373 var $meta; 374 var $name; 375 var $subname; 376 377 /** 378 * Used to provide field type hinting 379 * 380 * @since 1.3 381 * @var string 382 * @see the_field() 383 */ 384 protected $hint; 385 386 var $length = 0; 387 var $current = -1; 388 var $in_loop = FALSE; 389 var $in_template = FALSE; 390 var $group_tag; 391 var $current_post_id; 392 393 /** 394 * Used to store current loop details, cleared after loop ends 395 * 396 * @since 1.4 397 * @var stdClass 398 * @see have_fields_and_multi(), have_fields() 399 */ 400 protected $_loop_data; 401 402 public function __construct($arr) 403 { 404 $this->_loop_data = new \stdClass; 405 406 $this->meta = array(); 407 408 $this->types = array('post', 'page'); 409 410 if (is_array($arr)) 411 { 412 foreach ($arr as $n => $v) 413 { 414 $this->$n = $v; 415 } 416 417 if (empty($this->id)) die('Meta box ID required'); 418 419 if (is_numeric($this->id)) die('Meta box ID must be a string'); 420 421 if (empty($this->template)) die('Meta box template file required'); 422 423 // check for nonarray values 424 425 $exc_inc = array 426 ( 427 'exclude_template', 428 'exclude_category_id', 429 'exclude_category', 430 'exclude_tag_id', 431 'exclude_tag', 432 'exclude_post_id', 433 434 'include_template', 435 'include_category_id', 436 'include_category', 437 'include_tag_id', 438 'include_tag', 439 'include_post_id' 440 ); 441 442 foreach ($exc_inc as $v) 443 { 444 // ideally the exclude and include values should be in array form, convert to array otherwise 445 if (!empty($this->$v) AND !is_array($this->$v)) 446 { 447 $this->$v = array_map('trim',explode(',',$this->$v)); 448 } 449 } 450 451 // convert depreciated variables 452 if ($this->lock_on_top) $this->lock = WPALCHEMY_LOCK_TOP; 453 elseif ($this->lock_on_bottom) $this->lock = WPALCHEMY_LOCK_BOTTOM; 454 455 add_action('admin_init', array($this,'_init')); 456 457 // uses the default wordpress-importer plugin hook 458 add_action('import_post_meta', array($this, '_import'), 10, 3); 459 460 // todo: when first run define a constant to prevent other instances from running again ... 461 add_action( 'admin_head', array( $this, '_global_head' ) ); 462 463 add_action( 'admin_footer', array( $this, '_global_foot' ) ); 464 } 465 else 466 { 467 die('Associative array parameters required'); 468 } 469 } 470 471 /** 472 * Used to correct double serialized data during post/page export/import, 473 * additionally will try to fix corrupted serialized data by recalculating 474 * string length values 475 * 476 * @since 1.3.16 477 */ 478 public function _import($post_id, $key, $value) 479 { 480 if (WPALCHEMY_MODE_ARRAY == $this->mode AND $key == $this->id) 481 { 482 // using $wp_import to get access to the raw postmeta data prior to it getting passed 483 // through "maybe_unserialize()" in "plugins/wordpress-importer/wordpress-importer.php" 484 // the "import_post_meta" action is called after "maybe_unserialize()" 485 486 if ( isset( $wp_import->posts ) && ( is_array( $wp_import->posts ) || is_object( $wp_import->posts ) ) ) 487 { 488 foreach ( $wp_import->posts as $post ) 489 { 490 if ( $post_id == $post['post_id'] ) 491 { 492 foreach( $post['postmeta'] as $meta ) 493 { 494 if ( $key == $meta['key'] ) 495 { 496 // try to fix corrupted serialized data, specifically "\r\n" being converted to "\n" during wordpress XML export (WXR) 497 // "maybe_unserialize()" fixes a wordpress bug which double serializes already serialized data during export/import 498 $value = maybe_unserialize( $this->fix_serialized_string_type( $meta['value'] ) ); 499 500 update_post_meta( $post_id, $key, $value ); 501 } 502 } 503 } 504 } 505 } 506 } 507 } 508 509 /** 510 * @since 1.6 511 */ 512 protected function fix_serialized_string_type( $serialized_data ) { 513 return preg_replace_callback( '!s:(\d+):"(.*?)";!s', array( $this, 'fix_serialized_string_type_callback' ), stripslashes( $serialized_data ) ); 514 } 515 516 /** 517 * @since 1.6 518 */ 519 protected function fix_serialized_string_type_callback( $matches ) { 520 return sprintf( 's:%s:"%s";', strlen( $matches[2] ), $matches[2] ); 521 } 522 523 /** 524 * Used to initialize the meta box, runs on WordPress admin_init action, 525 * properly calls internal WordPress methods 526 * 527 * @since 1.0 528 */ 529 public function _init() 530 { 531 // must be creating or editing a post or page 532 if ( ! self::_is_post() AND ! self::_is_page()) return; 533 534 if ( ! empty($this->output_filter)) 535 { 536 $this->add_filter('output', $this->output_filter); 537 } 538 539 if ($this->can_output()) 540 { 541 foreach ($this->types as $type) 542 { 543 add_meta_box($this->id . '_metabox', $this->title, array($this, '_setup'), $type, $this->context, $this->priority); 544 } 545 546 add_action('save_post', array($this,'_save')); 547 548 $filters = array('save', 'head', 'foot'); 549 550 foreach ($filters as $filter) 551 { 552 $var = $filter . '_filter'; 553 554 if (!empty($this->$var)) 555 { 556 if ('save' == $filter) 557 { 558 $this->add_filter($filter, $this->$var, 10, 2); 559 } 560 else 561 { 562 $this->add_filter($filter, $this->$var); 563 } 564 } 565 } 566 567 $actions = array('save', 'head', 'foot', 'init'); 568 569 foreach ($actions as $action) 570 { 571 $var = $action . '_action'; 572 573 if (!empty($this->$var)) 574 { 575 if ('save' == $action) 576 { 577 $this->add_action($action, $this->$var, 10, 2); 578 } 579 else 580 { 581 $this->add_action($action, $this->$var); 582 } 583 } 584 } 585 586 add_action('admin_head', array($this,'_head'), 11); 587 588 add_action('admin_footer', array($this,'_foot'), 11); 589 590 // action: init 591 if ($this->has_action('init')) 592 { 593 $this->do_action('init'); 594 } 595 } 596 } 597 598 /** 599 * Used to insert STYLE or SCRIPT tags into the head, called on WordPress 600 * admin_head action. 601 * 602 * @since 1.3 603 * @see _foot() 604 */ 605 public function _head() 606 { 607 $content = NULL; 608 609 ob_start(); 610 611 ?> 612 <style type="text/css"> 613 <?php if ($this->hide_editor) { ?> #wp-content-editor-container, #post-status-info, <?php if ($this->use_media_buttons) { ?> #content-html, #content-tmce<?php } else { ?> #wp-content-wrap<?php } ?> { display:none; } <?php } ?> 614 </style> 615 <?php 616 617 $content = ob_get_contents(); 618 619 ob_end_clean(); 620 621 // filter: head 622 if ($this->has_filter('head')) 623 { 624 $content = $this->apply_filters('head', $content); 625 } 626 627 echo $content; 628 629 // action: head 630 if ($this->has_action('head')) 631 { 632 $this->do_action('head'); 633 } 634 } 635 636 /** 637 * Used to insert SCRIPT tags into the footer, called on WordPress 638 * admin_footer action. 639 * 640 * @since 1.3 641 * @see _head() 642 */ 643 public function _foot() 644 { 645 $content = NULL; 646 647 if 648 ( 649 $this->lock OR 650 $this->hide_title OR 651 $this->view OR 652 $this->hide_screen_option 653 ) 654 { 655 ob_start(); 656 657 ?> 658 <script type="text/javascript"> 659 /* <![CDATA[ */ 660 (function($){ /* not using jQuery ondomready, code runs right away in footer */ 661 662 var mb_id = '<?php echo $this->id; ?>'; 663 var mb = $('#' + mb_id + '_metabox'); 664 665 <?php if (WPALCHEMY_LOCK_TOP == $this->lock): ?> 666 <?php if ('side' == $this->context): ?> 667 var id = 'wpalchemy-side-top'; 668 if ( ! $('#'+id).length) 669 { 670 $('<div></div>').attr('id',id).prependTo('#side-info-column'); 671 } 672 <?php else: ?> 673 var id = 'wpalchemy-content-top'; 674 if ( ! $('#'+id).length) 675 { 676 $('<div></div>').attr('id',id).insertAfter('#postdiv, #postdivrich'); 677 } 678 <?php endif; ?> 679 $('#'+id).append(mb); 680 <?php elseif (WPALCHEMY_LOCK_BOTTOM == $this->lock): ?> 681 <?php if ('side' == $this->context): ?> 682 var id = 'wpalchemy-side-bottom'; 683 if ( ! $('#'+id).length) 684 { 685 $('<div></div>').attr('id',id).appendTo('#side-info-column'); 686 } 687 <?php else: ?> 688 if ( ! $('#advanced-sortables').children().length) 689 { 690 $('#advanced-sortables').css('display','none'); 691 } 692 693 var id = 'wpalchemy-content-bottom'; 694 if ( ! $('#'+id).length) 695 { 696 $('<div></div>').attr('id',id).insertAfter('#advanced-sortables'); 697 } 698 <?php endif; ?> 699 $('#'+id).append(mb); 700 <?php elseif (WPALCHEMY_LOCK_BEFORE_POST_TITLE == $this->lock): ?> 701 <?php if ('side' != $this->context): ?> 702 var id = 'wpalchemy-content-bpt'; 703 if ( ! $('#'+id).length) 704 { 705 $('<div></div>').attr('id',id).prependTo('#post-body-content'); 706 } 707 $('#'+id).append(mb); 708 <?php endif; ?> 709 <?php elseif (WPALCHEMY_LOCK_AFTER_POST_TITLE == $this->lock): ?> 710 <?php if ('side' != $this->context): ?> 711 var id = 'wpalchemy-content-apt'; 712 if ( ! $('#'+id).length) 713 { 714 $('<div></div>').attr('id',id).insertAfter('#titlediv'); 715 } 716 $('#'+id).append(mb); 717 <?php endif; ?> 718 <?php endif; ?> 719 720 <?php if ( ! empty($this->lock)): ?> 721 $('.hndle', mb).css('cursor','pointer'); 722 $('.handlediv', mb).remove(); 723 <?php endif; ?> 724 725 <?php if ($this->hide_title): ?> 726 $('.hndle', mb).remove(); 727 $('.handlediv', mb).remove(); 728 mb.removeClass('closed'); /* start opened */ 729 <?php endif; ?> 730 731 <?php if (WPALCHEMY_VIEW_START_OPENED == $this->view): ?> 732 mb.removeClass('closed'); 733 <?php elseif (WPALCHEMY_VIEW_START_CLOSED == $this->view): ?> 734 mb.addClass('closed'); 735 <?php elseif (WPALCHEMY_VIEW_ALWAYS_OPENED == $this->view): ?> 736 /* todo: need to find a way to add this script block below, load-scripts.php?... */ 737 var h3 = mb.children('h3'); 738 setTimeout(function(){ h3.unbind('click'); }, 1000); 739 $('.handlediv', mb).remove(); 740 mb.removeClass('closed'); /* start opened */ 741 $('.hndle', mb).css('cursor','auto'); 742 <?php endif; ?> 743 744 <?php if ($this->hide_screen_option): ?> 745 $('.metabox-prefs label[for='+ mb_id +'_metabox-hide]').remove(); 746 <?php endif; ?> 747 748 mb = null; 749 750 })(jQuery); 751 /* ]]> */ 752 </script> 753 <?php 754 755 $content = ob_get_contents(); 756 757 ob_end_clean(); 758 } 759 760 // filter: foot 761 if ($this->has_filter('foot')) 762 { 763 $content = $this->apply_filters('foot', $content); 764 } 765 766 echo $content; 767 768 // action: foot 769 if ($this->has_action('foot')) 770 { 771 $this->do_action('foot'); 772 } 773 } 774 775 /** 776 * Used to setup the meta box content template 777 * 778 * @since 1.0 779 * @see _init() 780 */ 781 public function _setup() 782 { 783 $this->in_template = TRUE; 784 785 // also make current post data available 786 global $post; 787 788 // shortcuts 789 $mb =& $this; 790 $metabox =& $this; 791 $id = $this->id; 792 $meta = $this->_meta(NULL, TRUE); 793 794 // use include because users may want to use one templete for multiple meta boxes 795 include $this->template; 796 797 // create a nonce for verification 798 echo '<input type="hidden" name="'. $this->id .'_nonce" value="' . wp_create_nonce($this->id) . '" />'; 799 800 $this->in_template = FALSE; 801 } 802 803 /** 804 * Used to properly prefix the filter tag, the tag is unique to the meta 805 * box instance 806 * 807 * @since 1.3 808 * @param string $tag name of the filter 809 * @return string uniquely prefixed tag name 810 */ 811 protected function _get_filter_tag($tag) 812 { 813 $prefix = 'wpalchemy_filter_' . $this->id . '_'; 814 $prefix = preg_replace('/_+/', '_', $prefix); 815 816 $tag = preg_replace('/^'. $prefix .'/i', '', $tag); 817 return $prefix . $tag; 818 } 819 820 /** 821 * Uses WordPress add_filter() function, see WordPress add_filter() 822 * 823 * @since 1.3 824 * @link http://core.trac.wordpress.org/browser/trunk/wp-includes/plugin.php#L65 825 */ 826 public function add_filter($tag, $function_to_add, $priority = 10, $accepted_args = 1) 827 { 828 $tag = $this->_get_filter_tag($tag);; 829 add_filter($tag, $function_to_add, $priority, $accepted_args); 830 } 831 832 /** 833 * Uses WordPress has_filter() function, see WordPress has_filter() 834 * 835 * @since 1.3 836 * @link http://core.trac.wordpress.org/browser/trunk/wp-includes/plugin.php#L86 837 */ 838 public function has_filter($tag, $function_to_check = FALSE) 839 { 840 $tag = $this->_get_filter_tag($tag); 841 return has_filter($tag, $function_to_check); 842 } 843 844 /** 845 * Uses WordPress apply_filters() function, see WordPress apply_filters() 846 * 847 * @since 1.3 848 * @link http://core.trac.wordpress.org/browser/trunk/wp-includes/plugin.php#L134 849 */ 850 public function apply_filters($tag, $value) 851 { 852 $args = func_get_args(); 853 $args[0] = $this->_get_filter_tag($tag); 854 return call_user_func_array('apply_filters', $args); 855 } 856 857 /** 858 * Uses WordPress remove_filter() function, see WordPress remove_filter() 859 * 860 * @since 1.3 861 * @link http://core.trac.wordpress.org/browser/trunk/wp-includes/plugin.php#L250 862 */ 863 public function remove_filter($tag, $function_to_remove, $priority = 10, $accepted_args = 1) 864 { 865 $tag = $this->_get_filter_tag($tag); 866 return remove_filter($tag, $function_to_remove, $priority, $accepted_args); 867 } 868 869 /** 870 * Used to properly prefix the action tag, the tag is unique to the meta 871 * box instance 872 * 873 * @since 1.3 874 * @param string $tag name of the action 875 * @return string uniquely prefixed tag name 876 */ 877 protected function _get_action_tag($tag) 878 { 879 $prefix = 'wpalchemy_action_' . $this->id . '_'; 880 $prefix = preg_replace('/_+/', '_', $prefix); 881 882 $tag = preg_replace('/^'. $prefix .'/i', '', $tag); 883 return $prefix . $tag; 884 } 885 886 /** 887 * Uses WordPress add_action() function, see WordPress add_action() 888 * 889 * @since 1.3 890 * @link http://core.trac.wordpress.org/browser/trunk/wp-includes/plugin.php#L324 891 */ 892 public function add_action($tag, $function_to_add, $priority = 10, $accepted_args = 1) 893 { 894 $tag = $this->_get_action_tag($tag); 895 add_action($tag, $function_to_add, $priority, $accepted_args); 896 } 897 898 /** 899 * Uses WordPress has_action() function, see WordPress has_action() 900 * 901 * @since 1.3 902 * @link http://core.trac.wordpress.org/browser/trunk/wp-includes/plugin.php#L492 903 */ 904 public function has_action($tag, $function_to_check = FALSE) 905 { 906 $tag = $this->_get_action_tag($tag); 907 return has_action($tag, $function_to_check); 908 } 909 910 /** 911 * Uses WordPress remove_action() function, see WordPress remove_action() 912 * 913 * @since 1.3 914 * @link http://core.trac.wordpress.org/browser/trunk/wp-includes/plugin.php#L513 915 */ 916 public function remove_action($tag, $function_to_remove, $priority = 10, $accepted_args = 1) 917 { 918 $tag = $this->_get_action_tag($tag); 919 return remove_action($tag, $function_to_remove, $priority, $accepted_args); 920 } 921 922 /** 923 * Uses WordPress do_action() function, see WordPress do_action() 924 * @since 1.3 925 * @link http://core.trac.wordpress.org/browser/trunk/wp-includes/plugin.php#L352 926 */ 927 public function do_action($tag, $arg = '') 928 { 929 $args = func_get_args(); 930 $args[0] = $this->_get_action_tag($tag); 931 return call_user_func_array('do_action', $args); 932 } 933 934 /** 935 * Used to check if creating a new post or editing one 936 * 937 * @since 1.3.7 938 * @return bool 939 * @see _is_page() 940 */ 941 static public function _is_post() 942 { 943 if ('post' == self::_is_post_or_page()) 944 { 945 return TRUE; 946 } 947 948 return FALSE; 949 } 950 951 /** 952 * Used to check if creating a new page or editing one 953 * 954 * @since 1.3.7 955 * @return bool 956 * @see _is_post() 957 */ 958 static public function _is_page() 959 { 960 if ('page' == self::_is_post_or_page()) 961 { 962 return TRUE; 963 } 964 965 return FALSE; 966 } 967 968 /** 969 * Used to check if creating or editing a post or page 970 * 971 * @since 1.3.8 972 * @return string "post" or "page" 973 * @see _is_post(), _is_page() 974 */ 975 static public function _is_post_or_page() 976 { 977 $post_type = self::_get_current_post_type(); 978 979 if (isset($post_type)) 980 { 981 if ('page' == $post_type) 982 { 983 return 'page'; 984 } 985 else 986 { 987 return 'post'; 988 } 989 } 990 991 return NULL; 992 } 993 994 /** 995 * Used to check for the current post type, works when creating or editing a 996 * new post, page or custom post type. 997 * 998 * @since 1.4.6 999 * @return string [custom_post_type], page or post 1000 */ 1001 static public function _get_current_post_type() 1002 { 1003 $uri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : NULL ; 1004 1005 if ( isset( $uri ) ) 1006 { 1007 $uri_parts = parse_url($uri); 1008 1009 $file = basename($uri_parts['path']); 1010 1011 if ($uri AND in_array($file, array('post.php', 'post-new.php'))) 1012 { 1013 $post_id = self::_get_post_id(); 1014 1015 $post_type = isset($_GET['post_type']) ? $_GET['post_type'] : NULL ; 1016 1017 $post_type = $post_id ? get_post_type($post_id) : $post_type ; 1018 1019 if (isset($post_type)) 1020 { 1021 return $post_type; 1022 } 1023 else 1024 { 1025 // because of the 'post.php' and 'post-new.php' checks above, we can default to 'post' 1026 return 'post'; 1027 } 1028 } 1029 } 1030 1031 return NULL; 1032 } 1033 1034 /** 1035 * Used to get the current post id. 1036 * 1037 * @since 1.4.8 1038 * @return int post ID 1039 */ 1040 static public function _get_post_id() 1041 { 1042 global $post; 1043 1044 $p_post_id = isset($_POST['post_ID']) ? $_POST['post_ID'] : null ; 1045 1046 $g_post_id = isset($_GET['post']) ? $_GET['post'] : null ; 1047 1048 $post_id = $g_post_id ? $g_post_id : $p_post_id ; 1049 1050 $post_id = isset($post->ID) ? $post->ID : $post_id ; 1051 1052 if (isset($post_id)) 1053 { 1054 return (integer) $post_id; 1055 } 1056 1057 return null; 1058 } 1059 1060 /** 1061 * @since 1.0 1062 */ 1063 public function can_output() 1064 { 1065 $post_id = self::_get_post_id(); 1066 1067 if (!empty($this->exclude_template) OR !empty($this->include_template)) 1068 { 1069 $template_file = get_post_meta($post_id,'_wp_page_template',TRUE); 1070 } 1071 1072 if 1073 ( 1074 !empty($this->exclude_category) OR 1075 !empty($this->exclude_category_id) OR 1076 !empty($this->include_category) OR 1077 !empty($this->include_category_id) 1078 ) 1079 { 1080 $categories = wp_get_post_categories($post_id,'fields=all'); 1081 } 1082 1083 if 1084 ( 1085 !empty($this->exclude_tag) OR 1086 !empty($this->exclude_tag_id) OR 1087 !empty($this->include_tag) OR 1088 !empty($this->include_tag_id) 1089 ) 1090 { 1091 $tags = wp_get_post_tags($post_id); 1092 } 1093 1094 // processing order: "exclude" then "include" 1095 // processing order: "template" then "category" then "post" 1096 1097 $can_output = TRUE; // include all 1098 1099 if 1100 ( 1101 !empty($this->exclude_template) OR 1102 !empty($this->exclude_category_id) OR 1103 !empty($this->exclude_category) OR 1104 !empty($this->exclude_tag_id) OR 1105 !empty($this->exclude_tag) OR 1106 !empty($this->exclude_post_id) OR 1107 !empty($this->include_template) OR 1108 !empty($this->include_category_id) OR 1109 !empty($this->include_category) OR 1110 !empty($this->include_tag_id) OR 1111 !empty($this->include_tag) OR 1112 !empty($this->include_post_id) 1113 ) 1114 { 1115 if (!empty($this->exclude_template)) 1116 { 1117 if (in_array($template_file,$this->exclude_template)) 1118 { 1119 $can_output = FALSE; 1120 } 1121 } 1122 1123 if (!empty($this->exclude_category_id)) 1124 { 1125 foreach ($categories as $cat) 1126 { 1127 if (in_array($cat->term_id,$this->exclude_category_id)) 1128 { 1129 $can_output = FALSE; 1130 break; 1131 } 1132 } 1133 } 1134 1135 if (!empty($this->exclude_category)) 1136 { 1137 foreach ($categories as $cat) 1138 { 1139 if 1140 ( 1141 in_array($cat->slug,$this->exclude_category) OR 1142 in_array($cat->name,$this->exclude_category) 1143 ) 1144 { 1145 $can_output = FALSE; 1146 break; 1147 } 1148 } 1149 } 1150 1151 if (!empty($this->exclude_tag_id)) 1152 { 1153 foreach ($tags as $tag) 1154 { 1155 if (in_array($tag->term_id,$this->exclude_tag_id)) 1156 { 1157 $can_output = FALSE; 1158 break; 1159 } 1160 } 1161 } 1162 1163 if (!empty($this->exclude_tag)) 1164 { 1165 foreach ($tags as $tag) 1166 { 1167 if 1168 ( 1169 in_array($tag->slug,$this->exclude_tag) OR 1170 in_array($tag->name,$this->exclude_tag) 1171 ) 1172 { 1173 $can_output = FALSE; 1174 break; 1175 } 1176 } 1177 } 1178 1179 if (!empty($this->exclude_post_id)) 1180 { 1181 if (in_array($post_id,$this->exclude_post_id)) 1182 { 1183 $can_output = FALSE; 1184 } 1185 } 1186 1187 // excludes are not set use "include only" mode 1188 1189 if 1190 ( 1191 empty($this->exclude_template) AND 1192 empty($this->exclude_category_id) AND 1193 empty($this->exclude_category) AND 1194 empty($this->exclude_tag_id) AND 1195 empty($this->exclude_tag) AND 1196 empty($this->exclude_post_id) 1197 ) 1198 { 1199 $can_output = FALSE; 1200 } 1201 1202 if (!empty($this->include_template)) 1203 { 1204 if (in_array($template_file,$this->include_template)) 1205 { 1206 $can_output = TRUE; 1207 } 1208 } 1209 1210 if (!empty($this->include_category_id)) 1211 { 1212 foreach ($categories as $cat) 1213 { 1214 if (in_array($cat->term_id,$this->include_category_id)) 1215 { 1216 $can_output = TRUE; 1217 break; 1218 } 1219 } 1220 } 1221 1222 if (!empty($this->include_category)) 1223 { 1224 foreach ($categories as $cat) 1225 { 1226 if 1227 ( 1228 in_array($cat->slug,$this->include_category) OR 1229 in_array($cat->name,$this->include_category) 1230 ) 1231 { 1232 $can_output = TRUE; 1233 break; 1234 } 1235 } 1236 } 1237 1238 if (!empty($this->include_tag_id)) 1239 { 1240 foreach ($tags as $tag) 1241 { 1242 if (in_array($tag->term_id,$this->include_tag_id)) 1243 { 1244 $can_output = TRUE; 1245 break; 1246 } 1247 } 1248 } 1249 1250 if (!empty($this->include_tag)) 1251 { 1252 foreach ($tags as $tag) 1253 { 1254 if 1255 ( 1256 in_array($tag->slug,$this->include_tag) OR 1257 in_array($tag->name,$this->include_tag) 1258 ) 1259 { 1260 $can_output = TRUE; 1261 break; 1262 } 1263 } 1264 } 1265 1266 if (!empty($this->include_post_id)) 1267 { 1268 if (in_array($post_id,$this->include_post_id)) 1269 { 1270 $can_output = TRUE; 1271 } 1272 } 1273 } 1274 1275 $post_type = self::_get_current_post_type(); 1276 1277 if (isset($post_type) AND ! in_array($post_type, $this->types)) 1278 { 1279 $can_output = FALSE; 1280 } 1281 1282 // filter: output (can_output) 1283 if ($this->has_filter('output')) 1284 { 1285 $can_output = $this->apply_filters('output', $post_id); 1286 } 1287 1288 return $can_output; 1289 } 1290 1291 /** 1292 * Used to insert global STYLE or SCRIPT tags into the head, called on 1293 * WordPress admin_footer action. 1294 * 1295 * @since 1.3 1296 * @see _global_foot() 1297 */ 1298 static public function _global_head() 1299 { 1300 // must be creating or editing a post or page 1301 if ( ! self::_is_post() AND ! self::_is_page()) return; 1302 1303 // todo: you're assuming people will want to use this exact functionality 1304 // consider giving a developer access to change this via hooks/callbacks 1305 1306 // include javascript for special functionality 1307 ?><style type="text/css"> .wpa_group.tocopy { display:none; } </style> 1308 <script type="text/javascript"> 1309 /* <![CDATA[ */ 1310 jQuery(function($) 1311 { 1312 $(document).click(function(e) 1313 { 1314 var elem = $(e.target); 1315 1316 if (elem.attr('class') && elem.filter('[class*=dodelete]').length) 1317 { 1318 e.preventDefault(); 1319 1320 var p = elem.parents('.postbox'); /*wp*/ 1321 1322 var the_name = elem.attr('class').match(/dodelete-([a-zA-Z0-9_-]*)/i); 1323 1324 the_name = (the_name && the_name[1]) ? the_name[1] : null ; 1325 1326 /* todo: expose and allow editing of this message */ 1327 if (confirm('This action can not be undone, are you sure?')) 1328 { 1329 if (the_name) 1330 { 1331 $('.wpa_group-'+ the_name, p).not('.tocopy').remove(); 1332 } 1333 else 1334 { 1335 elem.parents('.wpa_group').remove(); 1336 } 1337 1338 var the_group = elem.parents('.wpa_group'); 1339 1340 if(the_group && the_group.attr('class')) 1341 { 1342 the_name = the_group.attr('class').match(/wpa_group-([a-zA-Z0-9_-]*)/i); 1343 1344 the_name = (the_name && the_name[1]) ? the_name[1] : null ; 1345 1346 checkLoopLimit(the_name); 1347 } 1348 1349 $.wpalchemy.trigger('wpa_delete'); 1350 } 1351 } 1352 }); 1353 1354 $('[class*=docopy-]').click(function(e) 1355 { 1356 e.preventDefault(); 1357 1358 var p = $(this).parents('.postbox'); /*wp*/ 1359 1360 var the_name = $(this).attr('class').match(/docopy-([a-zA-Z0-9_-]*)/i)[1]; 1361 1362 var the_group = $('.wpa_group-'+ the_name +'.tocopy', p).first(); 1363 1364 var the_clone = the_group.clone().removeClass('tocopy last'); 1365 1366 var the_props = ['name', 'id', 'for', 'class']; 1367 1368 the_group.find('*').each(function(i, elem) 1369 { 1370 for (var j = 0; j < the_props.length; j++) 1371 { 1372 var the_prop = $(elem).attr(the_props[j]); 1373 1374 if (the_prop) 1375 { 1376 var the_match = the_prop.match(/\[(\d+)\]/i); 1377 1378 if (the_match) 1379 { 1380 the_prop = the_prop.replace(the_match[0],'['+ (+the_match[1]+1) +']'); 1381 1382 $(elem).attr(the_props[j], the_prop); 1383 } 1384 1385 the_match = null; 1386 1387 // todo: this may prove to be too broad of a search 1388 the_match = the_prop.match(/n(\d+)/i); 1389 1390 if (the_match) 1391 { 1392 the_prop = the_prop.replace(the_match[0], 'n' + (+the_match[1]+1)); 1393 1394 $(elem).attr(the_props[j], the_prop); 1395 } 1396 } 1397 } 1398 }); 1399 1400 if ($(this).hasClass('ontop')) 1401 { 1402 $('.wpa_group-'+ the_name, p).first().before(the_clone); 1403 } 1404 else 1405 { 1406 the_group.before(the_clone); 1407 } 1408 1409 checkLoopLimit(the_name); 1410 1411 $.wpalchemy.trigger('wpa_copy', [the_clone]); 1412 }); 1413 1414 function checkLoopLimit(name) 1415 { 1416 var elem = $('.docopy-' + name); 1417 1418 var the_class = $('.wpa_loop-' + name).attr('class'); 1419 1420 if (the_class) 1421 { 1422 var the_match = the_class.match(/wpa_loop_limit-([0-9]*)/i); 1423 1424 if (the_match) 1425 { 1426 var the_limit = the_match[1]; 1427 1428 if ($('.wpa_group-' + name).not('.wpa_group.tocopy').length >= the_limit) 1429 { 1430 elem.hide(); 1431 } 1432 else 1433 { 1434 elem.show(); 1435 } 1436 } 1437 } 1438 } 1439 1440 /* do an initial limit check, show or hide buttons */ 1441 $('[class*=docopy-]').each(function() 1442 { 1443 var the_name = $(this).attr('class').match(/docopy-([a-zA-Z0-9_-]*)/i)[1]; 1444 1445 checkLoopLimit(the_name); 1446 }); 1447 }); 1448 /* ]]> */ 1449 </script> 1450 <?php 1451 } 1452 1453 /** 1454 * Used to insert global SCRIPT tags into the footer, called on WordPress 1455 * admin_footer action. 1456 * 1457 * @since 1.3 1458 * @see _global_head() 1459 */ 1460 static public function _global_foot() 1461 { 1462 // must be creating or editing a post or page 1463 if ( ! self::_is_post() AND ! self::_is_page()) return; 1464 1465 ?> 1466 <script type="text/javascript"> 1467 /* <![CDATA[ */ 1468 (function($){ /* not using jQuery ondomready, code runs right away in footer */ 1469 1470 /* use a global dom element to attach events to */ 1471 $.wpalchemy = $('<div></div>').attr('id','wpalchemy').appendTo('body'); 1472 1473 })(jQuery); 1474 /* ]]> */ 1475 </script> 1476 <?php 1477 } 1478 1479 /** 1480 * Gets the meta data for a meta box 1481 * 1482 * @since 1.0 1483 * @param int $post_id optional post ID for which to retrieve the meta data 1484 * @return array 1485 * @see _meta 1486 */ 1487 public function the_meta($post_id = NULL) 1488 { 1489 return $this->_meta($post_id); 1490 } 1491 1492 /** 1493 * Gets the meta data for a meta box 1494 * 1495 * Internal method calls will typically bypass the data retrieval and will 1496 * immediately return the current meta data 1497 * 1498 * @since 1.3 1499 * @param int $post_id optional post ID for which to retrieve the meta data 1500 * @param bool $internal optional boolean if internally calling 1501 * @return array 1502 * @see the_meta() 1503 */ 1504 protected function _meta($post_id = NULL, $internal = FALSE) 1505 { 1506 if ( ! is_numeric($post_id)) 1507 { 1508 if ($internal AND $this->current_post_id) 1509 { 1510 $post_id = $this->current_post_id; 1511 } 1512 else 1513 { 1514 global $post; 1515 1516 $post_id = $post->ID; 1517 } 1518 } 1519 1520 // this allows multiple internal calls to _meta() without having to fetch data everytime 1521 if ($internal AND !empty($this->meta) AND $this->current_post_id == $post_id) return $this->meta; 1522 1523 $this->current_post_id = $post_id; 1524 1525 // WPALCHEMY_MODE_ARRAY 1526 1527 $meta = get_post_meta($post_id, $this->id, TRUE); 1528 1529 // WPALCHEMY_MODE_EXTRACT 1530 1531 $fields = get_post_meta($post_id, $this->id . '_fields', TRUE); 1532 1533 if ( ! empty($fields) AND is_array($fields)) 1534 { 1535 $meta = array(); 1536 1537 foreach ($fields as $field) 1538 { 1539 $field_noprefix = preg_replace('/^' . $this->prefix . '/i', '', $field); 1540 $meta[$field_noprefix] = get_post_meta($post_id, $field, TRUE); 1541 } 1542 } 1543 1544 $this->meta = $meta; 1545 1546 return $this->meta; 1547 } 1548 1549 // user can also use the_ID(), php functions are case-insensitive 1550 /** 1551 * @since 1.0 1552 */ 1553 public function the_id() 1554 { 1555 echo $this->get_the_id(); 1556 } 1557 1558 /** 1559 * @since 1.0 1560 */ 1561 public function get_the_id() 1562 { 1563 return $this->id; 1564 } 1565 1566 /** 1567 * @since 1.0 1568 */ 1569 public function the_field($n, $hint = NULL) 1570 { 1571 if ($this->in_loop) $this->subname = $n; 1572 else $this->name = $n; 1573 1574 $this->hint = $hint; 1575 } 1576 1577 /** 1578 * @since 1.0 1579 */ 1580 public function have_value($n = NULL) 1581 { 1582 if ($this->get_the_value($n)) return TRUE; 1583 1584 return FALSE; 1585 } 1586 1587 /** 1588 * @since 1.0 1589 */ 1590 public function the_value($n = NULL) 1591 { 1592 echo $this->get_the_value($n); 1593 } 1594 1595 /** 1596 * @since 1.0 1597 */ 1598 public function get_the_value($n = NULL, $collection = FALSE) 1599 { 1600 $this->_meta(NULL, TRUE); 1601 1602 $value = null; 1603 1604 if ($this->in_loop) 1605 { 1606 if(isset($this->meta[$this->name])) 1607 { 1608 $n = is_null($n) ? $this->subname : $n ; 1609 1610 if(!is_null($n)) 1611 { 1612 if ($collection) 1613 { 1614 if(isset($this->meta[$this->name][$this->current])) 1615 { 1616 $value = $this->meta[$this->name][$this->current]; 1617 } 1618 } 1619 else 1620 { 1621 if(isset($this->meta[$this->name][$this->current][$n])) 1622 { 1623 $value = $this->meta[$this->name][$this->current][$n]; 1624 } 1625 } 1626 } 1627 else 1628 { 1629 if ($collection) 1630 { 1631 if(isset($this->meta[$this->name])) 1632 { 1633 $value = $this->meta[$this->name]; 1634 } 1635 } 1636 else 1637 { 1638 if(isset($this->meta[$this->name][$this->current])) 1639 { 1640 $value = $this->meta[$this->name][$this->current]; 1641 } 1642 } 1643 } 1644 } 1645 } 1646 else 1647 { 1648 $n = is_null($n) ? $this->name : $n ; 1649 1650 if(isset($this->meta[$n])) 1651 { 1652 $value = $this->meta[$n]; 1653 } 1654 } 1655 1656 if (is_string($value) || is_numeric($value)) 1657 { 1658 if ($this->in_template) 1659 { 1660 return htmlentities($value, ENT_QUOTES, 'UTF-8'); 1661 } 1662 else 1663 { 1664 // http://wordpress.org/support/topic/call-function-called-by-embed-shortcode-direct 1665 // http://phpdoc.wordpress.org/trunk/WordPress/Embed/WP_Embed.html#run_shortcode 1666 1667 global $wp_embed; 1668 1669 return do_shortcode($wp_embed->run_shortcode($value)); 1670 } 1671 } 1672 else 1673 { 1674 // value can sometimes be an array 1675 return $value; 1676 } 1677 } 1678 1679 /** 1680 * @since 1.0 1681 */ 1682 public function the_name($n = NULL) 1683 { 1684 echo $this->get_the_name($n); 1685 } 1686 1687 /** 1688 * @since 1.0 1689 */ 1690 public function get_the_name($n = NULL) 1691 { 1692 if (!$this->in_template AND $this->mode == WPALCHEMY_MODE_EXTRACT) 1693 { 1694 return $this->prefix . str_replace($this->prefix, '', is_null($n) ? $this->name : $n); 1695 } 1696 1697 if ($this->in_loop) 1698 { 1699 $n = is_null($n) ? $this->subname : $n ; 1700 1701 if (!is_null($n)) $the_field = $this->id . '[' . $this->name . '][' . $this->current . '][' . $n . ']' ; 1702 1703 else $the_field = $this->id . '[' . $this->name . '][' . $this->current . ']' ; 1704 } 1705 else 1706 { 1707 $n = is_null($n) ? $this->name : $n ; 1708 1709 $the_field = $this->id . '[' . $n . ']'; 1710 } 1711 1712 $hints = array 1713 ( 1714 WPALCHEMY_FIELD_HINT_CHECKBOX_MULTI, 1715 WPALCHEMY_FIELD_HINT_SELECT_MULTI, 1716 WPALCHEMY_FIELD_HINT_SELECT_MULTIPLE, 1717 ); 1718 1719 if (in_array($this->hint, $hints)) 1720 { 1721 $the_field .= '[]'; 1722 } 1723 1724 return $the_field; 1725 } 1726 1727 /** 1728 * @since 1.1 1729 */ 1730 public function the_index() 1731 { 1732 echo $this->get_the_index(); 1733 } 1734 1735 /** 1736 * @since 1.1 1737 */ 1738 public function get_the_index() 1739 { 1740 return $this->in_loop ? $this->current : 0 ; 1741 } 1742 1743 /** 1744 * @since 1.0 1745 */ 1746 public function is_first() 1747 { 1748 if ($this->in_loop AND $this->current == 0) return TRUE; 1749 1750 return FALSE; 1751 } 1752 1753 /** 1754 * @since 1.0 1755 */ 1756 public function is_last() 1757 { 1758 if ($this->in_loop AND ($this->current+1) == $this->length) return TRUE; 1759 1760 return FALSE; 1761 } 1762 1763 /** 1764 * Used to check if a value is a match 1765 * 1766 * @since 1.1 1767 * @param string $n the field name to check or the value to check for (if the_field() is used prior) 1768 * @param string $v optional the value to check for 1769 * @return bool 1770 * @see is_value() 1771 */ 1772 public function is_value($n, $v = NULL) 1773 { 1774 if (is_null($v)) 1775 { 1776 $the_value = $this->get_the_value(); 1777 1778 $v = $n; 1779 } 1780 else 1781 { 1782 $the_value = $this->get_the_value($n); 1783 } 1784 1785 if($v == $the_value) return TRUE; 1786 1787 return FALSE; 1788 } 1789 1790 /** 1791 * Used to check if a value is selected, useful when working with checkbox, 1792 * radio and select values. 1793 * 1794 * @since 1.3 1795 * @param string $n the field name to check or the value to check for (if the_field() is used prior) 1796 * @param string $v optional the value to check for 1797 * @return bool 1798 * @see is_value() 1799 */ 1800 public function is_selected($n, $v = NULL, $is_default = FALSE) 1801 { 1802 if (is_null($v)) 1803 { 1804 $the_value = $this->get_the_value(NULL); 1805 1806 $v = $n; 1807 } 1808 else 1809 { 1810 $the_value = $this->get_the_value($n); 1811 } 1812 1813 if (is_array($the_value)) 1814 { 1815 if (in_array($v, $the_value)) return TRUE; 1816 } 1817 elseif($v == $the_value) 1818 { 1819 return TRUE; 1820 } 1821 1822 if( empty( $the_value ) && $is_default ) 1823 { 1824 return TRUE; 1825 } 1826 1827 return FALSE; 1828 } 1829 1830 /** 1831 * Prints the current state of a checkbox field and should be used inline 1832 * within the INPUT tag. 1833 * 1834 * @since 1.3 1835 * @param string $n the field name to check or the value to check for (if the_field() is used prior) 1836 * @param string $v optional the value to check for 1837 * @see get_the_checkbox_state() 1838 */ 1839 public function the_checkbox_state($n, $v = NULL, $is_default = FALSE) 1840 { 1841 echo $this->get_the_checkbox_state($n, $v, $is_default); 1842 } 1843 1844 /** 1845 * Returns the current state of a checkbox field, the returned string is 1846 * suitable to be used inline within the INPUT tag. 1847 * 1848 * @since 1.3 1849 * @param string $n the field name to check or the value to check for (if the_field() is used prior) 1850 * @param string $v optional the value to check for 1851 * @return string suitable to be used inline within the INPUT tag 1852 * @see the_checkbox_state() 1853 */ 1854 public function get_the_checkbox_state($n, $v = NULL, $is_default = FALSE) 1855 { 1856 if ($this->is_selected($n, $v, $is_default)) return ' checked="checked"'; 1857 } 1858 1859 /** 1860 * Prints the current state of a radio field and should be used inline 1861 * within the INPUT tag. 1862 * 1863 * @since 1.3 1864 * @param string $n the field name to check or the value to check for (if the_field() is used prior) 1865 * @param string $v optional the value to check for 1866 * @see get_the_radio_state() 1867 */ 1868 public function the_radio_state($n, $v = NULL, $is_default = FALSE) 1869 { 1870 echo $this->get_the_checkbox_state($n, $v, $is_default); 1871 } 1872 1873 /** 1874 * Returns the current state of a radio field, the returned string is 1875 * suitable to be used inline within the INPUT tag. 1876 * 1877 * @since 1.3 1878 * @param string $n the field name to check or the value to check for (if the_field() is used prior) 1879 * @param string $v optional the value to check for 1880 * @return string suitable to be used inline within the INPUT tag 1881 * @see the_radio_state() 1882 */ 1883 public function get_the_radio_state($n, $v = NULL, $is_default = FALSE) 1884 { 1885 return $this->get_the_checkbox_state($n, $v, $is_default); 1886 } 1887 1888 /** 1889 * Prints the current state of a select field and should be used inline 1890 * within the SELECT tag. 1891 * 1892 * @since 1.3 1893 * @param string $n the field name to check or the value to check for (if the_field() is used prior) 1894 * @param string $v optional the value to check for 1895 * @see get_the_select_state() 1896 */ 1897 public function the_select_state($n, $v = NULL, $is_default = FALSE) 1898 { 1899 echo $this->get_the_select_state($n, $v, $is_default); 1900 } 1901 1902 /** 1903 * Returns the current state of a select field, the returned string is 1904 * suitable to be used inline within the SELECT tag. 1905 * 1906 * @since 1.3 1907 * @param string $n the field name to check or the value to check for (if the_field() is used prior) 1908 * @param string $v optional the value to check for 1909 * @return string suitable to be used inline within the SELECT tag 1910 * @see the_select_state() 1911 */ 1912 public function get_the_select_state($n, $v = NULL, $is_default = FALSE) 1913 { 1914 if ($this->is_selected($n, $v, $is_default)) return ' selected="selected"'; 1915 } 1916 1917 /** 1918 * @since 1.1 1919 */ 1920 public function the_group_open($t = 'div') 1921 { 1922 echo $this->get_the_group_open($t); 1923 } 1924 1925 /** 1926 * @since 1.1 1927 */ 1928 public function get_the_group_open($t = 'div') 1929 { 1930 $this->group_tag = $t; 1931 1932 $loop_open = NULL; 1933 1934 $loop_open_classes = array('wpa_loop', 'wpa_loop-' . $this->name); 1935 1936 $css_class = array('wpa_group', 'wpa_group-'. $this->name); 1937 1938 if ($this->is_first()) 1939 { 1940 array_push($css_class, 'first'); 1941 1942 $loop_open = '<div class="wpa_loop">'; 1943 1944 if (isset($this->_loop_data->limit)) 1945 { 1946 array_push($loop_open_classes, 'wpa_loop_limit-' . $this->_loop_data->limit); 1947 } 1948 1949 $loop_open = '<div id="wpa_loop-'. $this->name .'" class="' . implode(' ', $loop_open_classes) . '">'; 1950 } 1951 1952 if ($this->is_last()) 1953 { 1954 array_push($css_class, 'last'); 1955 1956 if ($this->in_loop == 'multi') 1957 { 1958 array_push($css_class, 'tocopy'); 1959 } 1960 } 1961 1962 return $loop_open . '<' . $t . ' class="'. implode(' ', $css_class) . '">'; 1963 } 1964 1965 /** 1966 * @since 1.1 1967 */ 1968 public function the_group_close() 1969 { 1970 echo $this->get_the_group_close(); 1971 } 1972 1973 /** 1974 * @since 1.1 1975 */ 1976 public function get_the_group_close() 1977 { 1978 $loop_close = NULL; 1979 1980 if ($this->is_last()) 1981 { 1982 $loop_close = '</div>'; 1983 } 1984 1985 return '</' . $this->group_tag . '>' . $loop_close; 1986 } 1987 1988 /** 1989 * @since 1.1 1990 */ 1991 public function have_fields_and_multi($n, $options = NULL) 1992 { 1993 if (is_array($options)) 1994 { 1995 // use as stdClass object 1996 $options = (object)$options; 1997 1998 $length = @$options->length; 1999 2000 $this->_loop_data->limit = @$options->limit; 2001 } 2002 else 2003 { 2004 // backward compatibility (bc) 2005 $length = $options; 2006 } 2007 2008 $this->_meta(NULL, TRUE); 2009 2010 $this->in_loop = 'multi'; 2011 2012 return $this->_loop($n, $length, 2); 2013 } 2014 2015 /** 2016 * @deprecated 2017 * @since 1.0 2018 */ 2019 public function have_fields_and_one($n) 2020 { 2021 $this->_meta(NULL, TRUE); 2022 $this->in_loop = 'single'; 2023 return $this->_loop($n,NULL,1); 2024 } 2025 2026 /** 2027 * @since 1.0 2028 */ 2029 public function have_fields($n,$length=NULL) 2030 { 2031 $this->_meta(NULL, TRUE); 2032 $this->in_loop = 'normal'; 2033 return $this->_loop($n,$length); 2034 } 2035 2036 /** 2037 * @since 1.0 2038 */ 2039 protected function _loop($n,$length=NULL,$and_one=0) 2040 { 2041 if (!$this->in_loop) 2042 { 2043 $this->in_loop = TRUE; 2044 } 2045 2046 $this->name = $n; 2047 2048 $cnt = count(!empty($this->meta[$n])?$this->meta[$n]:NULL); 2049 2050 $length = is_null($length) ? $cnt : $length ; 2051 2052 if ($this->in_loop == 'multi' AND $cnt > $length) $length = $cnt; 2053 2054 $this->length = $length; 2055 2056 if ($this->in_template AND $and_one) 2057 { 2058 if ($length == 0) 2059 { 2060 $this->length = $and_one; 2061 } 2062 else 2063 { 2064 $this->length = $length+1; 2065 } 2066 } 2067 2068 $this->current++; 2069 2070 if ($this->current < $this->length) 2071 { 2072 $this->subname = NULL; 2073 2074 $this->fieldtype = NULL; 2075 2076 return TRUE; 2077 } 2078 else if ($this->current == $this->length) 2079 { 2080 $this->name = NULL; 2081 2082 $this->current = -1; 2083 } 2084 2085 $this->in_loop = FALSE; 2086 2087 $this->_loop_data = new \stdClass; 2088 2089 return FALSE; 2090 } 2091 2092 /** 2093 * @since 1.0 2094 */ 2095 public function _save($post_id) 2096 { 2097 /** 2098 * note: the "save_post" action fires for saving revisions and post/pages, 2099 * when saving a post this function fires twice, once for a revision save, 2100 * and again for the post/page save ... the $post_id is different for the 2101 * revision save, this means that "get_post_meta()" will not work if trying 2102 * to get values for a revision (as it has no post meta data) 2103 * see http://alexking.org/blog/2008/09/06/wordpress-26x-duplicate-custom-field-issue 2104 * 2105 * why let the code run twice? wordpress does not currently save post meta 2106 * data per revisions (I think it should, so users can do a complete revert), 2107 * so in the case that this functionality changes, let it run twice 2108 */ 2109 2110 $real_post_id = isset($_POST['post_ID']) ? $_POST['post_ID'] : NULL ; 2111 2112 // check autosave 2113 if (defined('DOING_AUTOSAVE') AND DOING_AUTOSAVE AND !$this->autosave) return $post_id; 2114 2115 // make sure data came from our meta box, verify nonce 2116 $nonce = isset($_POST[$this->id.'_nonce']) ? $_POST[$this->id.'_nonce'] : NULL ; 2117 if (!wp_verify_nonce($nonce, $this->id)) return $post_id; 2118 2119 // check user permissions 2120 if ($_POST['post_type'] == 'page') 2121 { 2122 if (!current_user_can('edit_page', $post_id)) return $post_id; 2123 } 2124 else 2125 { 2126 if (!current_user_can('edit_post', $post_id)) return $post_id; 2127 } 2128 2129 // authentication passed, save data 2130 2131 $new_data = isset( $_POST[$this->id] ) ? $_POST[$this->id] : NULL ; 2132 2133 self::clean($new_data); 2134 2135 if (empty($new_data)) 2136 { 2137 $new_data = NULL; 2138 } 2139 2140 // filter: save 2141 if ($this->has_filter('save')) 2142 { 2143 $new_data = $this->apply_filters('save', $new_data, $real_post_id); 2144 2145 /** 2146 * halt saving 2147 * @since 1.3.4 2148 */ 2149 if (FALSE === $new_data) return $post_id; 2150 2151 self::clean($new_data); 2152 } 2153 2154 // get current fields, use $real_post_id (checked for in both modes) 2155 $current_fields = get_post_meta($real_post_id, $this->id . '_fields', TRUE); 2156 2157 if ($this->mode == WPALCHEMY_MODE_EXTRACT) 2158 { 2159 $new_fields = array(); 2160 2161 if (is_array($new_data)) 2162 { 2163 foreach ($new_data as $k => $v) 2164 { 2165 $field = $this->prefix . $k; 2166 2167 array_push($new_fields,$field); 2168 2169 $new_value = $new_data[$k]; 2170 2171 if (is_null($new_value)) 2172 { 2173 delete_post_meta($post_id, $field); 2174 } 2175 else 2176 { 2177 update_post_meta($post_id, $field, $new_value); 2178 } 2179 } 2180 } 2181 2182 $diff_fields = array_diff((array)$current_fields,$new_fields); 2183 2184 if (is_array($diff_fields)) 2185 { 2186 foreach ($diff_fields as $field) 2187 { 2188 delete_post_meta($post_id,$field); 2189 } 2190 } 2191 2192 delete_post_meta($post_id, $this->id . '_fields'); 2193 2194 if ( ! empty($new_fields)) 2195 { 2196 add_post_meta($post_id,$this->id . '_fields', $new_fields, TRUE); 2197 } 2198 2199 // keep data tidy, delete values if previously using WPALCHEMY_MODE_ARRAY 2200 delete_post_meta($post_id, $this->id); 2201 } 2202 else 2203 { 2204 if (is_null($new_data)) 2205 { 2206 delete_post_meta($post_id, $this->id); 2207 } 2208 else 2209 { 2210 update_post_meta($post_id, $this->id, $new_data); 2211 } 2212 2213 // keep data tidy, delete values if previously using WPALCHEMY_MODE_EXTRACT 2214 if (is_array($current_fields)) 2215 { 2216 foreach ($current_fields as $field) 2217 { 2218 delete_post_meta($post_id, $field); 2219 } 2220 2221 delete_post_meta($post_id, $this->id . '_fields'); 2222 } 2223 } 2224 2225 // action: save 2226 if ($this->has_action('save')) 2227 { 2228 $this->do_action('save', $new_data, $real_post_id); 2229 } 2230 2231 return $post_id; 2232 } 2233 2234 /** 2235 * Cleans an array, removing blank ('') values 2236 * 2237 * @since 1.0 2238 * @param array the array to clean (passed by reference) 2239 */ 2240 static public function clean(&$arr) 2241 { 2242 if (is_array($arr)) 2243 { 2244 foreach ($arr as $i => $v) 2245 { 2246 if (is_array($arr[$i])) 2247 { 2248 self::clean($arr[$i]); 2249 2250 if (!count($arr[$i])) 2251 { 2252 unset($arr[$i]); 2253 } 2254 } 2255 else 2256 { 2257 if ('' == trim($arr[$i]) OR is_null($arr[$i])) 2258 { 2259 unset($arr[$i]); 2260 } 2261 } 2262 } 2263 2264 if (!count($arr)) 2265 { 2266 $arr = array(); 2267 } 2268 else 2269 { 2270 $keys = array_keys($arr); 2271 2272 $is_numeric = TRUE; 2273 2274 foreach ($keys as $key) 2275 { 2276 if (!is_numeric($key)) 2277 { 2278 $is_numeric = FALSE; 2279 break; 2280 } 2281 } 2282 2283 if ($is_numeric) 2284 { 2285 $arr = array_values($arr); 2286 } 2287 } 2288 } 2289 } 2364 2290 } 2365 2366 /* eof */
Note: See TracChangeset
for help on using the changeset viewer.