/**
  * Render the product/global tab content.  Templates are loaded in the
  * following order:
  *
  * theme / woocommerce / single-product / tabs / content-{tab-name-slug}.php
  * theme / woocommerce / single-product / tabs / content.php
  * woocommerce-tab-manager / templates / single-product / tabs / content.php
  *
  * $tab structure:
  * Array(
  *   'title'    => (string) Tab title,
  *   'priority' => (string) Tab priority,
  *   'callback' => (mixed) callback function,
  *   'id'       => (int) tab post identifier,
  * )
  *
  * @access public
  * @since 1.0.5
  * @global WC_Tab_Manager wc_tab_manager()
  * @global WC_Product $product
  *
  * @param string $key tab key, this is the sanitized tab title with possibly a numerical suffix to avoid key clashes
  * @param array $tab tab data
  */
 function woocommerce_tab_manager_tab_content($key, $tab)
 {
     global $product;
     $tab = wc_tab_manager()->get_product_tab($product->id, $tab['id'], true);
     if ($tab) {
         // first look for a template specific for this tab
         $template_name = "single-product/tabs/content-{$tab['name']}.php";
         $located = locate_template(array(trailingslashit(WC()->template_path()) . $template_name, $template_name));
         // if not found, fallback to the general template
         if (!$located) {
             $template_name = 'single-product/tabs/content.php';
         }
         wc_get_template($template_name, array('tab' => $tab), '', wc_tab_manager()->get_plugin_path() . '/templates/');
     }
 }
/**
 * Add necessary admin scripts
 * @access public
 */
function wc_tab_manager_admin_enqueue_scripts()
{
    // Get admin screen id
    $screen = get_current_screen();
    // on the admin product page
    if ('product' == $screen->id || isset($_REQUEST['page']) && 'tab_manager' == $_REQUEST['page']) {
        wp_enqueue_script('wc_tab_manager_admin', wc_tab_manager()->get_plugin_url() . '/assets/js/admin/wc-tab-manager.min.js', array('jquery'));
        $wc_tab_manager_admin_params = array('remove_product_tab' => __('Remove this product tab?', WC_Tab_Manager::TEXT_DOMAIN), 'remove_label' => __('Remove', WC_Tab_Manager::TEXT_DOMAIN), 'click_to_toggle' => __('Click to toggle', WC_Tab_Manager::TEXT_DOMAIN), 'title_label' => __('Title', WC_Tab_Manager::TEXT_DOMAIN), 'title_description' => __('The tab title, this appears in the tab', WC_Tab_Manager::TEXT_DOMAIN), 'content_label' => __('Content', WC_Tab_Manager::TEXT_DOMAIN), 'ajax_url' => admin_url('admin-ajax.php'), 'get_editor_nonce' => wp_create_nonce('get-editor'));
        wp_localize_script('wc_tab_manager_admin', 'wc_tab_manager_admin_params', $wc_tab_manager_admin_params);
    }
    // we're going to make sortable boxes in our custom default tab layout page, the same as on the product edit page
    if (isset($_REQUEST['page']) && 'tab_manager' == $_REQUEST['page']) {
        wp_enqueue_script('woocommerce_admin');
        wp_enqueue_script('jquery-ui-sortable');
        wp_enqueue_script('media-upload');
        wp_enqueue_script('thickbox');
        $params = array('ajax_url' => admin_url('admin-ajax.php'));
        wp_enqueue_script('woocommerce_admin_meta_boxes', WC()->plugin_url() . '/assets/js/admin/meta-boxes.min.js', array('jquery', 'jquery-ui-datepicker', 'jquery-ui-sortable', 'accounting', 'round'), WC()->version);
        // keep the woocommerce_admin_meta_boxes script happy
        wp_localize_script('woocommerce_admin_meta_boxes', 'woocommerce_admin_meta_boxes', $params);
    }
}
/**
 * Helper function to render the sortable tabs admin UI used both on the product
 * edit pages, as well as the custom Default Tab Layout admin page
 *
 * @access public
 * @param array $tabs tab data
 */
function wc_tab_manager_sortable_product_tabs($tabs)
{
    global $typenow;
    $style = '';
    ?>
	<style type="text/css">
		#woocommerce-product-data ul.product_data_tabs li.product_tabs_tab a { <?php 
    echo $style;
    ?>
 }
		.wc-metaboxes-wrapper .wc-metabox table.woocommerce_product_tab_data td label { display: inline; line-height: inherit; }
		.woocommerce_product_tabs .options_group label { float: left; padding: 0; width: 150px; }
		.woocommerce_product_tabs .options_group p { font-size: 12px; line-height: 24px; }
		.wc-metaboxes-wrapper .woocommerce_product_tabs .wc-metabox table td input { font-size: inherit; }
		.woocommerce_product_tabs .description { margin: 0 0 0 7px; padding: 0; }
		.woocommerce_product_tabs .options_group .form-field label { font-weight:bold; }
		.wc-metaboxes-wrapper .toolbar { text-align:right; }
		.wc-metaboxes-wrapper .toolbar label { line-height:22px; }
		.wc-metaboxes-wrapper .toolbar input { margin-top:0; }
		.wc-metaboxes-wrapper .toolbar input { margin-top:0; }

		#woocommerce_product_tabs .quicktags-toolbar input {
			background-color: #EEEEEE;
			background-image: -moz-linear-gradient(center bottom , #E3E3E3, #FFFFFF);
			border: 1px solid #C3C3C3;
			border-radius: 3px 3px 3px 3px;
			color: #464646;
			display: inline-block;
			font: 12px/18px Arial,Helvetica,sans-serif normal;
			margin: 2px 1px 4px;
			width:auto;
			min-width: 26px;
			padding: 2px 4px;
			float: none;
		}

		#woocommerce_product_tabs .wp-editor-area {
			-moz-box-sizing: border-box;
			border: 0 none;
			font-family: Consolas,Monaco,monospace;
			line-height: 150%;
			outline: medium none;
			padding: 10px;
			resize: vertical;
			font-size:inherit;
			color:#333333;
		}

		#wc_tab_manager_block {
			background-color: white;
			height: 100%;
			left: 0;
			opacity: 0.6;
			position: absolute;
			top: 0;
			width: 100%;
			display:none;
		}
	</style>
	<div id="woocommerce_product_tabs" class="panel wc-metaboxes-wrapper">
		<p class="toolbar">
			<?php 
    if ('product' == $typenow) {
        global $post;
        $override_tab_layout = get_post_meta($post->ID, '_override_tab_layout', true);
        ?>
				<label for="_override_tab_layout"><?php 
        _e('Override default tab layout:', WC_Tab_Manager::TEXT_DOMAIN);
        ?>
</label> <input type="checkbox" name="_override_tab_layout" id="_override_tab_layout" <?php 
        checked($override_tab_layout, "yes");
        ?>
 />
			<?php 
    }
    ?>
			<a href="#" class="close_all"><?php 
    _e('Close all', WC_Tab_Manager::TEXT_DOMAIN);
    ?>
</a> / <a href="#" class="expand_all"><?php 
    _e('Expand all', WC_Tab_Manager::TEXT_DOMAIN);
    ?>
</a>
		</p>

		<div style="position:relative;">
		<div class="woocommerce_product_tabs wc-metaboxes">

			<?php 
    // the core woocommerce tabs
    $core_tabs = wc_tab_manager()->get_core_tabs();
    // get any global tabs
    $global_tabs = array();
    $posts = get_posts(array('numberposts' => -1, 'post_type' => 'wc_product_tab', 'post_parent' => 0, 'post_status' => 'publish', 'suppress_filters' => false));
    foreach ($posts as $_post) {
        $tab = array('id' => $_post->ID, 'position' => 0, 'type' => 'global', 'title' => $_post->post_title);
        list($tab['content']) = explode("\n", wordwrap(str_replace("\n", "", strip_shortcodes(strip_tags($_post->post_content))), 155));
        // content excerpt
        if (strlen($_post->post_content) > 155) {
            $tab['content'] .= '...';
        }
        if ($tab['content']) {
            $tab['content'] .= ' - ';
        }
        $tab['content'] .= ' <a href="' . get_edit_post_link($_post->ID) . '">' . __('Edit Global Tab Content', WC_Tab_Manager::TEXT_DOMAIN) . '</a>';
        $global_tabs['global_tab_' . $_post->ID] = $tab;
    }
    // get any 3rd party tabs
    $third_party_tabs = array();
    foreach (wc_tab_manager()->get_third_party_tabs() as $id => $tab) {
        if (!isset($tab['ignore']) || false == $tab['ignore']) {
            $third_party_tabs[$id] = array('id' => $tab['id'], 'position' => 0, 'type' => 'third_party', 'title' => $tab['title'], 'description' => $tab['description']);
        }
    }
    // if no tabs are set (for this product) try defaulting to the default tab layout, if it exists
    if (!is_array($tabs)) {
        $tabs = get_option('wc_tab_manager_default_layout', false);
    }
    // if no default tab layout either, default to the core + 3rd party tabs
    if (!is_array($tabs)) {
        $tabs = $core_tabs + $third_party_tabs;
    } else {
        // otherwise, get the content and title for any product/global tabs, and verify that any global/3rd party tabs still exist
        foreach ($tabs as $id => $tab) {
            if ('global' == $tab['type']) {
                // global tab: get an excerpt of the content to display if any, or if the tab has been removed or trashed, remove it from view
                if (isset($global_tabs[$id])) {
                    $tabs[$id]['title'] = $global_tabs[$id]['title'];
                    $tabs[$id]['content'] = $global_tabs[$id]['content'];
                } else {
                    // global tab is gone
                    unset($tabs[$id]);
                }
            } elseif ('third_party' == $tab['type']) {
                // 3rd party tab, does the plugin still exist?
                if (isset($third_party_tabs[$id])) {
                    $tabs[$id]['title'] = $third_party_tabs[$id]['title'];
                    $tabs[$id]['description'] = $third_party_tabs[$id]['description'];
                } else {
                    unset($tabs[$id]);
                }
            } elseif ('product' == $tab['type']) {
                // get any custom product tab content from the underlying post
                $tab_post = get_post($tab['id']);
                if ($tab_post && 'publish' == $tab_post->post_status) {
                    $tabs[$id]['content'] = $tab_post->post_content;
                    $tabs[$id]['title'] = $tab_post->post_title;
                } else {
                    // product tab is gone
                    unset($tabs[$id]);
                }
            }
        }
    }
    // markup for all core, global and 3rd party tabs will be rendered, and if not currently added to the product, they will be hidden until added
    $combined_tabs = array_merge($core_tabs, $global_tabs, $third_party_tabs, $tabs);
    $i = 0;
    foreach ($combined_tabs as $id => $tab) {
        $position = $tab['position'];
        $active = isset($tabs[$id]);
        // for the core tabs, even if the title is changed, keep the displayed name the same in the bar so there's less confusion
        $name = 'core' == $tab['type'] ? $core_tabs[$id]['title'] : $tab['title'];
        // handle the Reviews tab specially by cutting off the ' (%d)' which looks like garbage in the sortable tab list
        if ('core' == $tab['type'] && 'reviews' == $tab['id']) {
            $name = substr($name, 0, -4);
        }
        ?>
					<div class="woocommerce_product_tab wc-metabox <?php 
        echo sanitize_html_class('product_tab_' . $tab['type']);
        ?>
 <?php 
        echo sanitize_html_class($id);
        ?>
" rel="<?php 
        echo esc_attr($position);
        ?>
" <?php 
        if (!$active) {
            echo ' style="display:none;"';
        }
        ?>
>
						<h3>
							<button type="button" class="remove_row button"><?php 
        _e('Remove', WC_Tab_Manager::TEXT_DOMAIN);
        ?>
</button>
							<div class="handlediv" title="<?php 
        _e('Click to toggle', WC_Tab_Manager::TEXT_DOMAIN);
        ?>
"></div>
							<strong class="product_tab_name"><?php 
        echo esc_html($name);
        ?>
</strong>
						</h3>
						<table class="woocommerce_product_tab_data wc-metabox-content">
							<tr>
								<td>
									<?php 
        if (isset($core_tabs[$id]['description'])) {
            ?>
										<p><em><?php 
            echo esc_html($core_tabs[$id]['description']);
            ?>
</em></p>
									<?php 
        }
        ?>
									<?php 
        if ('third_party' == $tab['type']) {
            ?>
										<p><em><?php 
            echo esc_html($tab['description'] ? $tab['description'] : __('The title/content for this tab will be provided by a third party plugin', WC_Tab_Manager::TEXT_DOMAIN));
            ?>
</em></p>
									<?php 
        }
        ?>
									<div class="options_group">
										<?php 
        if ('third_party' != $tab['type']) {
            ?>
											<p class="form-field product_tab_title_field">
												<label for="product_tab_title_<?php 
            echo $i;
            ?>
"><?php 
            _e('Title', WC_Tab_Manager::TEXT_DOMAIN);
            ?>
</label>
												<?php 
            if ('global' == $tab['type']) {
                ?>
													<span><?php 
                echo esc_html($tab['title']);
                ?>
</span>
													<input type="hidden" name="product_tab_title[<?php 
                echo $i;
                ?>
]" value="<?php 
                echo esc_attr($tab['title']);
                ?>
" />
												<?php 
            } else {
                ?>
													<input type="text" value="<?php 
                echo esc_attr($tab['title']);
                ?>
" id="product_tab_title_<?php 
                echo $i;
                ?>
" name="product_tab_title[<?php 
                echo $i;
                ?>
]" class="short product_tab_title"> <span class="description"><?php 
                esc_html_e("The tab title, this appears in the tab", WC_Tab_Manager::TEXT_DOMAIN);
                ?>
</span>
												<?php 
            }
            ?>
											</p>
										<?php 
        }
        ?>
										<?php 
        if (isset($core_tabs[$id]['heading']) && $core_tabs[$id]['heading']) {
            ?>
											<p class="form-field product_tab_heading_field">
												<label for="product_tab_heading_<?php 
            echo $i;
            ?>
"><?php 
            _e('Heading', WC_Tab_Manager::TEXT_DOMAIN);
            ?>
</label>
												<input type="text" value="<?php 
            echo esc_attr($tab['heading']);
            ?>
" id="product_tab_heading_<?php 
            echo $i;
            ?>
" name="product_tab_heading[<?php 
            echo $i;
            ?>
]" class="short"> <span class="description"><?php 
            esc_html_e("The tab heading, this appears just before the tab content", WC_Tab_Manager::TEXT_DOMAIN);
            ?>
</span>
											</p>
										<?php 
        }
        ?>
										<?php 
        if ('global' == $tab['type']) {
            ?>
											<p class="form-field product_tab_heading_field">
												<label for="product_tab_content_<?php 
            echo $i;
            ?>
"><?php 
            _e('Content', WC_Tab_Manager::TEXT_DOMAIN);
            ?>
</label>
												<span><?php 
            echo wp_kses_post($tab['content']);
            ?>
</span>
											</p>
										<?php 
        }
        ?>
									</div>
									<?php 
        if ('product' == $tab['type'] && isset($tab['content'])) {
            ?>
										<?php 
            /* Because the editor is within a movable block, we must disable the rich visual MCE editor, and use only the quicktags editor */
            wp_editor($tab['content'], 'producttabcontent' . $i, array('textarea_name' => 'product_tab_content[' . $i . ']', 'tinymce' => false, 'textarea_rows' => 10));
            ?>
									<?php 
        }
        ?>
									<input type="hidden" name="product_tab_active[<?php 
        echo $i;
        ?>
]" class="product_tab_active" value="<?php 
        echo esc_attr($active);
        ?>
" />
									<input type="hidden" name="product_tab_position[<?php 
        echo $i;
        ?>
]" class="product_tab_position" value="<?php 
        echo esc_attr($position);
        ?>
" />
									<input type="hidden" name="product_tab_type[<?php 
        echo $i;
        ?>
]" class="product_tab_type" value="<?php 
        echo esc_attr($tab['type']);
        ?>
" />
									<input type="hidden" name="product_tab_id[<?php 
        echo $i;
        ?>
]" class="product_tab_id" value="<?php 
        echo esc_attr($tab['id']);
        ?>
" />
								</td>
							</tr>
						</table>
					</div>
					<?php 
        $i++;
    }
    ?>
		</div>

		<?php 
    $select_tabs = $core_tabs + $global_tabs + $third_party_tabs;
    ?>
		<p class="toolbar">
			<button type="button" class="button button-primary add_product_tab"><?php 
    _e('Add', WC_Tab_Manager::TEXT_DOMAIN);
    ?>
</button>
			<select name="product_tab" class="product_tab">
				<?php 
    if ('product' == $typenow) {
        ?>
<option value=""><?php 
        _e('Custom Tab', WC_Tab_Manager::TEXT_DOMAIN);
        ?>
</option><?php 
    }
    ?>
				<?php 
    foreach ($select_tabs as $id => $tab) {
        echo '<option value="' . esc_attr($id) . '">' . esc_html__($tab['title'], WC_Tab_Manager::TEXT_DOMAIN) . '</option>';
    }
    ?>
			</select>
		</p>

		<div class="clear"></div>
		<div id="wc_tab_manager_block"></div>
		</div>
	</div>
	<?php 
}
function init_woocommerce_tab_manager()
{
    /**
     * The WooCommerce Tab Manager allows product tabs to be ordered, created,
     * updated, and removed.
     *
     * For the purposes of this plugin the tabs available for management can be
     * broken down into the following categories:
     *
     * - core tabs: The default Description, Additional Information and Reviews tabs
     * - global tabs: These are tabs which can be added to any product
     * - 3rd party tabs: Tabs added by 3rd party plugins, ie WooCommerce Product Enquiry Form
     * - product level tabs: Tabs added to a particular product
     *
     * Note: the terminology surrounding "product tabs" is somewhat confusing in
     * this plugin as I use the term to refer both to any tab which can be added to
     * a product, as well as the "product level tabs".  Hopefully the code context
     * makes it clear enough though.
     *
     * Global and Product Level tabs themselves are represented by a new post_type
     * named wc_product_tab.
     *
     * Tabs can be configured globally from within the Tab Manager submenu, and
     * overridden at the individual product level.  At the global level the tab layout
     * is stored as a wordpress option.  At the product level, the tab layout is
     * stored in the exact same structure, as a post meta.
     *
     * Database:
     * - Option named 'wc_tab_manager_db_version' with the current plugin version
     * - Option named 'wc_tab_manager_default_layout' with the global default layout
     * - Postmeta named '_override_tab_layout' attached to products, indicating
     *   whether the global default layout is to be used
     * - Postmeta named '_product_tabs' attached to products, with the product-level
     *   tab layout (same structure as the global default layout)
     *
     * @since 1.0
     */
    class WC_Tab_Manager extends SV_WC_Plugin
    {
        /** Plugin version */
        const VERSION = '1.3.0';
        /** @var WC_Tab_Manager single instance of this plugin */
        protected static $instance;
        /** The plugins id, used for various slugs and such */
        const PLUGIN_ID = 'tab_manager';
        /** plugin text domain */
        const TEXT_DOMAIN = 'woocommerce-tab-manager';
        /**
         * Local cache array of product tabs, keyed off product id
         * @var array
         */
        private $product_tabs = array();
        /**
         * Array of third party tabs
         * @var array
         */
        private $third_party_tabs;
        /**
         * @var boolean Temporary member used to defer plugin installation, until the plugin framework supports this
         */
        private $wp_loaded_action = false;
        /**
         * Setup main plugin class
         *
         * @since 1.0
         * @see SV_WC_Plugin::__construct()
         */
        public function __construct()
        {
            parent::__construct(self::PLUGIN_ID, self::VERSION, self::TEXT_DOMAIN);
            $this->includes();
            add_action('init', array($this, 'init'));
            add_action('init', array($this, 'include_template_functions'), 25);
            add_filter('woocommerce_product_tabs', array($this, 'setup_tabs'), 98);
            // allow the use of shortcodes within the tab content
            add_filter('woocommerce_tab_manager_tab_panel_content', 'do_shortcode');
        }
        /**
         * Load plugin text domain.
         *
         * @since 1.1
         * @see SV_WC_Plugin::load_translation()
         */
        public function load_translation()
        {
            load_plugin_textdomain('woocommerce-tab-manager', false, dirname(plugin_basename($this->get_file())) . '/i18n/languages');
        }
        /**
         * Init WooCommerce Tab Manager
         */
        public function init()
        {
            // Init user roles
            $this->init_user_roles();
            // Init WooCommerce Product Tab taxonomy
            $this->init_taxonomy();
        }
        /**
         * Function used to init WooCommerce Tab Manager Template Functions, making them pluggable by plugins and themes
         */
        public function include_template_functions()
        {
            require_once $this->get_plugin_path() . '/woocommerce-tab-manager-template.php';
        }
        /**
         * Files required by both the admin and frontend
         */
        private function includes()
        {
            if (is_admin()) {
                $this->admin_includes();
            }
            if (defined('DOING_AJAX') && DOING_AJAX) {
                $this->ajax_includes();
            }
        }
        /**
         * Include required admin files
         */
        private function admin_includes()
        {
            require_once $this->get_plugin_path() . '/admin/woocommerce-tab-manager-admin-init.php';
            // Admin section
        }
        /**
         * Include required ajax files.
         */
        private function ajax_includes()
        {
            require_once $this->get_plugin_path() . '/woocommerce-tab-manager-ajax.php';
            // Ajax functions for admin and the front-end
        }
        /**
         * Init WooCommerce Tab Manager user role
         */
        private function init_user_roles()
        {
            global $wp_roles;
            if (class_exists('WP_Roles') && !isset($wp_roles)) {
                $wp_roles = new WP_Roles();
            }
            // it's fine if this gets executed more than once
            if (is_object($wp_roles)) {
                $wp_roles->add_cap('shop_manager', 'manage_woocommerce_tab_manager');
                $wp_roles->add_cap('administrator', 'manage_woocommerce_tab_manager');
            }
        }
        /**
         * Init custom post type
         */
        private function init_taxonomy()
        {
            // bail if the post type was already registered
            if (post_type_exists('wc_product_tab')) {
                return;
            }
            if (current_user_can('manage_woocommerce')) {
                $show_in_menu = 'woocommerce';
            } else {
                $show_in_menu = true;
            }
            register_post_type("wc_product_tab", array('labels' => array('name' => __('Tabs', self::TEXT_DOMAIN), 'singular_name' => __('Tab', self::TEXT_DOMAIN), 'menu_name' => _x('Tab Manager', 'Admin menu name', self::TEXT_DOMAIN), 'add_new' => __('Add Tab', self::TEXT_DOMAIN), 'add_new_item' => __('Add New Tab', self::TEXT_DOMAIN), 'edit' => __('Edit', self::TEXT_DOMAIN), 'edit_item' => __('Edit Tab', self::TEXT_DOMAIN), 'new_item' => __('New Tab', self::TEXT_DOMAIN), 'view' => __('View Tabs', self::TEXT_DOMAIN), 'view_item' => __('View Tab', self::TEXT_DOMAIN), 'search_items' => __('Search Tabs', self::TEXT_DOMAIN), 'not_found' => __('No Tabs found', self::TEXT_DOMAIN), 'not_found_in_trash' => __('No Tabs found in trash', self::TEXT_DOMAIN)), 'description' => __('This is where you can add new tabs that you can add to products.', self::TEXT_DOMAIN), 'public' => true, 'show_ui' => true, 'capability_type' => 'post', 'capabilities' => array('publish_posts' => 'manage_woocommerce_tab_manager', 'edit_posts' => 'manage_woocommerce_tab_manager', 'edit_others_posts' => 'manage_woocommerce_tab_manager', 'delete_posts' => 'manage_woocommerce_tab_manager', 'delete_others_posts' => 'manage_woocommerce_tab_manager', 'read_private_posts' => 'manage_woocommerce_tab_manager', 'edit_post' => 'manage_woocommerce_tab_manager', 'delete_post' => 'manage_woocommerce_tab_manager', 'read_post' => 'manage_woocommerce_tab_manager'), 'publicly_queryable' => true, 'exclude_from_search' => true, 'show_in_menu' => $show_in_menu, 'hierarchical' => false, 'rewrite' => false, 'query_var' => false, 'supports' => array('title', 'editor'), 'show_in_nav_menus' => false));
        }
        /**
         * Return the plugin action links.  This will only be called if the plugin
         * is active.
         *
         * @since 1.0.9
         * @param array $actions associative array of action names to anchor tags
         * @return array associative array of plugin action links
         */
        public function add_plugin_action_links($actions)
        {
            $custom_actions = array('configure' => sprintf('<a href="%s">%s</a>', admin_url('edit.php?post_type=wc_product_tab'), __('Configure', self::TEXT_DOMAIN)), 'docs' => sprintf('<a href="%s">%s</a>', 'http://docs.woothemes.com/document/tab-manager/', __('Docs', self::TEXT_DOMAIN)), 'support' => sprintf('<a href="%s">%s</a>', 'http://support.woothemes.com/', __('Support', self::TEXT_DOMAIN)), 'review' => sprintf('<a href="%s">%s</a>', $this->get_review_url(), __('Write a Review', self::TEXT_DOMAIN)));
            // add the links to the front of the actions list
            return array_merge($custom_actions, $actions);
        }
        /** Frontend methods ******************************************************/
        /**
         * Organizes the product tabs as configured within the Tab Manager
         *
         * $tabs structure:
         * Array(
         *   id => Array(
         *     'title'    => (string) Tab title,
         *     'priority' => (string) Tab priority,
         *     'callback' => (mixed) callback function,
         *   )
         * )
         *
         * @since 1.0.5
         * @param array $tabs array representing the product tabs
         * @return array representing the product tabs
         */
        public function setup_tabs($tabs)
        {
            global $product;
            // first off, make sure that we're dealing with an array rather than null
            if (is_null($tabs)) {
                $tabs = array();
            }
            $new_tabs = $tabs;
            $product_tabs = isset($product->id) ? $this->get_product_tabs($product->id) : null;
            // if product tabs have been configured for this product or globally (otherwise, allow default behavior)
            if (is_array($product_tabs)) {
                // start fresh
                $new_tabs = array();
                // unhook and load any third party tabs that have been added by this point
                $third_party_tabs = $this->get_third_party_tabs($tabs);
                foreach ($product_tabs as $key => $tab) {
                    $priority = ($tab['position'] + 1) * 10;
                    $tab_id = $tab['id'];
                    if ('core' == $tab['type']) {
                        // the core tabs can be suppressed for a variety of reasons: description tab due to no content, attributes tab due to no attributes, etc
                        if (!isset($tabs[$tab_id])) {
                            continue;
                        }
                        // set the review (comment) count for the reviews tab, if they used the '%d' substitution
                        if ('reviews' == $tab['id'] && false !== strpos($tab['title'], '%d')) {
                            $tab['title'] = str_replace('%d', get_comments_number($product->id), $tab['title']);
                        }
                        // add the core tab to the new tab set
                        $new_tabs[$tab_id] = array('title' => $tab['title'], 'priority' => $priority, 'callback' => $tabs[$tab_id]['callback']);
                        // handle core tab headings (displays just before the tab content)
                        if ('additional_information' == $tab_id) {
                            add_filter('woocommerce_product_additional_information_heading', array($this, 'core_tab_heading'));
                        } elseif ('description' == $tab_id) {
                            add_filter('woocommerce_product_description_heading', array($this, 'core_tab_heading'));
                        }
                    } elseif ('third_party' == $tab['type']) {
                        // third-party provided tab: ensure it's still available
                        if (!isset($third_party_tabs[$key]) || isset($third_party_tabs[$key]['ignore']) && true == $third_party_tabs[$key]['ignore']) {
                            continue;
                        }
                        // add the 3rd party tab in with the new priority
                        $new_tabs[$tab_id] = $third_party_tabs[$key];
                        $new_tabs[$tab_id]['priority'] = $priority;
                    } else {
                        // product/global tabs
                        // skip any global/product tabs that have been deleted
                        $tab_post = get_post($tab_id);
                        if (!$tab_post || 'publish' != $tab_post->post_status || !$tab_post->post_title) {
                            continue;
                        }
                        $new_tabs[$tab['name']] = array('title' => $tab_post->post_title, 'priority' => $priority, 'callback' => 'woocommerce_tab_manager_tab_content', 'id' => $tab['id']);
                    }
                }
                // finally add in any non-managed 3rd party tabs with their own priority
                foreach ($third_party_tabs as $key => $tab) {
                    if (isset($tab['ignore']) && true == $tab['ignore']) {
                        $new_tabs[$key] = $tab;
                    }
                }
            }
            return apply_filters('wc_tab_manager_product_tabs', $new_tabs);
        }
        /**
         * Filter to modify the Description and Additional Information core tab headings.
         * The heading is not what shows up in the "tab" itself, this is the
         * heading for the tab content area.
         *
         * @param string $heading the tab heading
         * @return string the tab heading
         */
        public function core_tab_heading($heading)
        {
            global $product;
            $tabs = $this->get_product_tabs($product->id);
            $current_filter = current_filter();
            if ('woocommerce_product_additional_information_heading' == $current_filter) {
                return $tabs['core_tab_additional_information']['heading'];
            } elseif ('woocommerce_product_description_heading' == $current_filter) {
                return $tabs['core_tab_description']['heading'];
            }
            return $heading;
        }
        /** Helper methods ******************************************************/
        /**
         * Main Tab Manager Instance, ensures only one instance is/can be loaded
         *
         * @since 1.2.0
         * @see wc_tab_manager()
         * @return WC_Tab_Manager
         */
        public static function instance()
        {
            if (is_null(self::$instance)) {
                self::$instance = new self();
            }
            return self::$instance;
        }
        /**
         * Get any third party tabs which have been added via the
         * woocommerce_product_tabs action.  Any third party tabs so found are collected
         * so they can be re-added by the manager in the appropriate order.  In the
         * admin a human readable title is automatically generated (allowing for
         * automatic integration of 3rd party plugin tabs) and three filters are
         * fired to allow for improved integration with customized titles/descriptions:
         *
         * - woocommerce_tab_manager_integration_tab_allowed: allows plugin to mark tab as not available for management, its priority will not be modified and it will not appear within the Tab Manager Admin UI
         * - woocommerce_tab_manager_integration_tab_title: allows plugin to provide a more descriptive tab title to display within the Tab Manager Admin UI
         * - woocommerce_tab_manager_integration_tab_description: allows plugin to provide a description to display within the Tab Manager Admin UI
         *
         * $tabs structure:
         * Array(
         *   key => Array(
         *     'title'       => (string) Tab title,
         *     'priority'    => (string) Tab priority,
         *     'callback'    => (mixed) callback function,
         *     'description' => (string) An optional tab description added by this method to the return array,
         *     'ignore'      => (boolean) Optional marker indicating this tab is not managed by the Tab Manager plugin and added by this method to the return array,
         *     'id'          => (string) the original tab key,
         *   )
         * )
         * Where key is: third_party_tab_{id}
         *
         * @since 1.0.5
         * @param array $tabs optional array representing the product tabs
         * @return array representing the product tabs
         */
        public function get_third_party_tabs($tabs = null)
        {
            global $wp_filter;
            if (is_null($this->third_party_tabs)) {
                // gather the tabs if not provided
                if (is_null($tabs)) {
                    // In WC 2.1+ the woocommerce_default_product_tabs filter (which
                    //  requires a global $post/$product) is hooked into from the admin
                    //  so unhook to avoid a fatal error (has no effect in pre WC 2.1)
                    if (is_admin()) {
                        remove_filter('woocommerce_product_tabs', 'woocommerce_default_product_tabs');
                        remove_filter('woocommerce_product_tabs', 'woocommerce_sort_product_tabs', 99);
                    }
                    $tabs = apply_filters('woocommerce_product_tabs', array());
                }
                $this->third_party_tabs = array();
                // remove the core tabs (if any) leaving only 3rd party tabs (if any)
                unset($tabs['additional_information'], $tabs['reviews'], $tabs['description']);
                foreach ($tabs as $key => $tab) {
                    // is this tab available for management by the Tab Manager plugin?
                    if (apply_filters('woocommerce_tab_manager_integration_tab_allowed', true, $tab)) {
                        if (is_admin()) {
                            if (!isset($tab['title']) || !$tab['title']) {
                                // on the off chance that the 3rd party tab doesn't have a title, provide it a default one based on the callback so it can be identified within the admin
                                // get a title for the tab.  Default to humanizing the function name, or class name
                                if (is_array($tab['callback'])) {
                                    $tab_title = is_object($tab['callback'][0]) ? get_class($tab['callback'][0]) : $tab['callback'][0];
                                } else {
                                    $tab_title = (string) $tab['callback'];
                                }
                                $tab_title = ucwords(str_replace('_', ' ', $tab_title));
                                $tab_title = str_ireplace(array('woocommerce', 'wordpress'), array('WooCommerce', 'WordPress'), $tab_title);
                                // fix some common words
                                $tab['title'] = $tab_title;
                            }
                            // improved 3rd party integration by allowing plugins to provide a more descriptive title/description for their tabs
                            $tab['title'] = apply_filters('woocommerce_tab_manager_integration_tab_title', $tab['title'], $tab);
                            $tab['description'] = apply_filters('woocommerce_tab_manager_integration_tab_description', '', $tab);
                        }
                        $tab['id'] = $key;
                    } else {
                        // this tab is not managed by the Tab Manager, so mark it as such
                        $tab['ignore'] = true;
                    }
                    // save the tab
                    $this->third_party_tabs['third_party_tab_' . $key] = $tab;
                }
            }
            return $this->third_party_tabs;
        }
        /**
         * Get the default core tabs datastructure
         *
         * @return array the core tabs
         */
        public function get_core_tabs()
        {
            // the core woocommerce tabs
            $core_tabs = array('core_tab_description' => array('id' => 'description', 'position' => 0, 'type' => 'core', 'title' => __('Description', 'woocommerce'), 'description' => __('Displays the product content set in the main content editor.', 'woocommerce'), 'heading' => __('Product Description', 'woocommerce')), 'core_tab_additional_information' => array('id' => 'additional_information', 'position' => 1, 'type' => 'core', 'title' => __('Additional Information', 'woocommerce'), 'description' => __('Displays the product attributes and properties configured in the Product Data panel.', 'woocommerce'), 'heading' => __('Additional Information', 'woocommerce')), 'core_tab_reviews' => array('id' => 'reviews', 'position' => 2, 'type' => 'core', 'title' => __('Reviews (%d)', 'woocommerce'), 'description' => __('Displays the product review form and any reviews.  Use %d in the Title to substitute the number of reviews for the product.', 'woocommerce')));
            return $core_tabs;
        }
        /**
         * Gets the product tabs (if any) for the identified product.  If not
         * configured at the product level, the default layout (if any) will be
         * returned.
         *
         * returned tabs structure:
         * Array(
         *   key => Array(
         *     'position' => (int) 0-indexed ordered position from the Tab Manager Admin UI,
         *     'type'     => (string) one of 'core', 'global', 'third_party' or 'product',
         *     'id'       => (string) Tab identifier, ie 'description', 'reviews', 'additional_information' for the core tabs, post id for product/global, and woocommerce_product_tabs key for third party tabs,
         *     'title'    => (string) The tab title to display on the frontend (not used for 3rd party tabs, though it could be),
         *     'heading'  => (string) Tab heading (core description/additional_information tabs only),
         *     'name'     => (string) Product/Global tabs only, this is the sanitized title, and is used to key the tab in the final woocommerce tab data structure,
         *   )
         * )
         * Where key is: {type}_tab_{id}
         *
         * @param int $product_id product identifier
         *
         * @return array product tabs data
         */
        public function get_product_tabs($product_id)
        {
            if (!isset($this->product_tabs[$product_id])) {
                $override_tab_layout = get_post_meta($product_id, '_override_tab_layout', true);
                if ('yes' == $override_tab_layout) {
                    // product defines its own tab layout?
                    $this->product_tabs[$product_id] = get_post_meta($product_id, '_product_tabs', true);
                } else {
                    // otherwise, get the default layout if any
                    $this->product_tabs[$product_id] = get_option('wc_tab_manager_default_layout', false);
                }
            }
            return $this->product_tabs[$product_id];
        }
        /**
         * Gets the product tab or null if the tab cannot be found
         *
         * @param int $product_id product identifier
         * @param int $tab_id tab identifier
         * @param boolean $get_the_content whether to get the tab content and title
         *
         * @return array tab array, or null
         */
        public function get_product_tab($product_id, $tab_id, $get_the_content = false)
        {
            $tab = null;
            // load the tabs
            $this->get_product_tabs($product_id);
            if (is_array($this->product_tabs[$product_id])) {
                foreach ($this->product_tabs[$product_id] as $id => $tab) {
                    if ($tab['id'] == $tab_id) {
                        // get the tab content, if needed
                        if ($get_the_content && !isset($tab['content'])) {
                            $tab_post = get_post($tab_id);
                            $content = apply_filters('the_content', $tab_post->post_content);
                            $content = str_replace(']]>', ']]&gt;', $content);
                            $this->product_tabs[$product_id][$id]['content'] = $content;
                            $this->product_tabs[$product_id][$id]['title'] = $tab_post->post_title;
                        }
                        $tab = $this->product_tabs[$product_id][$id];
                        break;
                    }
                }
            }
            return apply_filters('wc_tab_manager_get_product_tab', $tab, $product_id, $tab_id, $get_the_content);
        }
        /**
         * Returns the plugin name, localized
         *
         * @since 1.1
         * @see SV_WC_Plugin::get_plugin_name()
         * @return string the plugin name
         */
        public function get_plugin_name()
        {
            return __('WooCommerce Tab Manager', self::TEXT_DOMAIN);
        }
        /**
         * Returns __FILE__
         *
         * @since 1.1
         * @see
         * @return string the full path and filename of the plugin file
         */
        protected function get_file()
        {
            return __FILE__;
        }
        /**
         * Gets the plugin configuration URL
         *
         * @since 1.1
         * @see SV_WC_Plugin::get_settings_url()()
         * @see SV_WC_Plugin::get_settings_link()
         * @param string $plugin_id optional plugin identifier.  Note that this can be a
         *        sub-identifier for plugins with multiple parallel settings pages
         *        (ie a gateway that supports both credit cards and echecks)
         * @return string plugin settings URL
         */
        public function get_settings_url($plugin_id = null)
        {
            return admin_url('edit.php?post_type=wc_product_tab');
        }
        /**
         * Gets the plugin documentation URL
         *
         * @since  1.3.0
         * @see    SV_WC_Plugin::get_documentation_url()
         * @return string
         */
        public function get_documentation_url()
        {
            return 'http://docs.woothemes.com/document/tab-manager/';
        }
        /**
         * Gets the plugin support URL
         *
         * @since  1.3.0
         * @see    SV_WC_Plugin::get_support_url()
         * @return string
         */
        public function get_support_url()
        {
            return 'http://support.woothemes.com/';
        }
        /**
         * Returns true if on the admin tab configuration page
         *
         * @since 1.0.1
         * @return boolean true if on the admin plugin settings page
         */
        public function is_plugin_settings()
        {
            return isset($_GET['post_type']) && 'wc_product_tab' == $_GET['post_type'];
        }
        /** Lifecycle methods ******************************************************/
        /**
         * Run every time.  Used since the activation hook is not executed when updating a plugin
         *
         * @see SV_WC_Plugin::install()
         */
        protected function install()
        {
            global $wpdb;
            // check for a pre 1.1 version
            $legacy_version = get_option('wc_tab_manager_db_version');
            if (false !== $legacy_version) {
                // upgrade path from previous version, trash old version option
                delete_option('wc_tab_manager_db_version');
                // upgrade path
                $this->upgrade($legacy_version);
                // and we're done
                return;
            }
            // any Custom Product Lite Tabs?
            $results = $wpdb->get_results("SELECT post_id, meta_value FROM {$wpdb->postmeta} WHERE meta_key='frs_woo_product_tabs'");
            // prepare the core tabs
            $core_tabs = $this->get_core_tabs();
            foreach ($core_tabs as $id => $tab) {
                unset($core_tabs[$id]['description']);
            }
            // foreach product with a custom lite tab
            foreach ($results as $result) {
                $old_tabs = maybe_unserialize($result->meta_value);
                $new_tabs = array('core_tab_description' => $core_tabs['core_tab_description'], 'core_tab_additional_information' => $core_tabs['core_tab_additional_information']);
                // keep track of tab names to avoid clashes
                $found_names = array('description' => 1, 'additional_information' => 1, 'reviews' => 1);
                foreach ($old_tabs as $tab) {
                    if ($tab['title'] && $tab['content']) {
                        // create the product tab
                        $new_tab = array('position' => count($new_tabs), 'type' => 'product');
                        $new_tab_data = array('post_title' => $tab['title'], 'post_content' => $tab['content'], 'post_status' => 'publish', 'ping_status' => 'closed', 'post_author' => get_current_user_id(), 'post_type' => 'wc_product_tab', 'post_parent' => $result->post_id, 'post_password' => uniqid('tab_'));
                        // create the post and get the id
                        $id = wp_insert_post($new_tab_data);
                        $new_tab['id'] = $id;
                        // determine the unique tab name
                        $tab_name = sanitize_title($tab['title']);
                        if (!isset($found_names[$tab_name])) {
                            $found_names[$tab_name] = 1;
                        } else {
                            $found_names[$tab_name]++;
                        }
                        if ($found_names[$tab_name] > 1) {
                            $tab_name .= '-' . ($found_names[$tab_name] - 1);
                        }
                        $new_tab['name'] = $tab_name;
                        // tab is complete
                        $new_tabs['product_tab_' . $id] = $new_tab;
                    }
                }
                // add the core reviews tab on at the end
                $new_tabs['core_tab_reviews'] = $core_tabs['core_tab_reviews'];
                $new_tabs['core_tab_reviews']['position'] = count($new_tabs) - 1;
                if (count($new_tabs) > 3) {
                    // if we actually had any product tabs
                    add_post_meta($result->post_id, '_product_tabs', $new_tabs, true);
                    add_post_meta($result->post_id, '_override_tab_layout', 'yes', true);
                }
            }
        }
        /**
         * Run when plugin version number changes
         *
         * @see SV_WC_Plugin::upgrade()
         */
        protected function upgrade($installed_version)
        {
            global $wpdb;
            if (version_compare($installed_version, "1.0.4.1", '<=')) {
                // in this version and before:
                // * custom product lite tabs were imported but their status was set
                //   to 'future' meaning they appeared in the Tab Manager menu, but
                //   not at the product level
                // * product tab layout had 'tab_name' rather than 'name' for imported
                //   custom product lite tabs
                // * imported custom product lite tabs attached to products did not
                //   have the '_override_tab_layout' meta set
                $tabs = get_posts(array('numberposts' => '', 'post_type' => 'wc_product_tab', 'nopaging' => true, 'post_status' => 'future'));
                if (is_array($tabs)) {
                    foreach ($tabs as $tab) {
                        // make the tab post status 'publish'
                        $update_tab = array('ID' => $tab->ID, 'post_status' => 'publish');
                        wp_update_post($update_tab);
                        add_post_meta($tab->ID, '_migrated_future', 'yes');
                        // mark the tab as migrated, in case we need to reference them one day
                        // fix the product tab layout 'tab_name' field, which should be 'name'
                        $fixed = false;
                        $product_tabs = get_post_meta($tab->post_parent, '_product_tabs', true);
                        foreach ($product_tabs as $index => $product_tab) {
                            if (isset($product_tab['tab_name']) && $product_tab['tab_name'] && !isset($product_tab['name'])) {
                                $product_tabs[$index]['name'] = $product_tab['tab_name'];
                                unset($product_tabs[$index]['tab_name']);
                                $fixed = true;
                            }
                        }
                        if ($fixed) {
                            update_post_meta($tab->post_parent, '_product_tabs', $product_tabs);
                        }
                        // It seems that setting the tab layout override in existing stores would be too dangerous, so for now the following is not used
                        // enable the product '_override_tab_layout' so the product tab is actually used
                        // update_post_meta( $tab->post_parent, '_override_tab_layout', 'yes' );
                    }
                }
                unset($tabs);
            }
            // In version 1.0.5 the core tab previously referred to as 'attributes' now
            //  needs to be referrred to as 'additional_information' for consistency with
            //  WC 2.0+, so fix the global and any product tab layouts
            if (version_compare($installed_version, "1.0.5", '<=')) {
                // fix global tab layout
                $tab_layout = get_option('wc_tab_manager_default_layout', false);
                if ($tab_layout && isset($tab_layout['core_tab_attributes'])) {
                    $tab_layout['core_tab_additional_information'] = $tab_layout['core_tab_attributes'];
                    $tab_layout['core_tab_additional_information']['id'] = 'additional_information';
                    unset($tab_layout['core_tab_attributes']);
                    update_option('wc_tab_manager_default_layout', $tab_layout);
                }
                // fix any product-level tab layouts
                $results = $wpdb->get_results("SELECT post_id, meta_value FROM {$wpdb->postmeta} WHERE meta_key='_product_tabs'");
                if (is_array($results)) {
                    foreach ($results as $row) {
                        $tab_layout = maybe_unserialize($row->meta_value);
                        if ($tab_layout && isset($tab_layout['core_tab_attributes'])) {
                            $tab_layout['core_tab_additional_information'] = $tab_layout['core_tab_attributes'];
                            $tab_layout['core_tab_additional_information']['id'] = 'additional_information';
                            unset($tab_layout['core_tab_attributes']);
                            update_post_meta($row->post_id, '_product_tabs', $tab_layout);
                        }
                    }
                }
                unset($results);
            }
        }
    }
    // class WC_Tab_Manager
    /**
     * Returns the One True Instance of Tab Manager
     *
     * @since 1.2.0
     * @return WC_Tab_Manager
     */
    function wc_tab_manager()
    {
        return WC_Tab_Manager::instance();
    }
    /**
     * The WC_Tab_Manager global object
     *
     * @deprecated 1.2.0
     * @name $wc_tab_manager
     * @global WC_Tab_Manager $GLOBALS['wc_tab_manager']
     */
    $GLOBALS['wc_tab_manager'] = wc_tab_manager();
}
 * @copyright   Copyright (c) 2012-2015, SkyVerge, Inc.
 * @license     http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
 */
/**
 * WooCommerce Tab Manager Write Panels
 *
 * Sets up the write panels added by the Tab Manager
 */
if (!defined('ABSPATH')) {
    exit;
}
// Exit if accessed directly
/** Product data Tab panel */
include_once wc_tab_manager()->get_plugin_path() . '/admin/post-types/writepanels/writepanel-product_data-tabs.php';
/** Product Tab Actions writepanel */
include_once wc_tab_manager()->get_plugin_path() . '/admin/post-types/writepanels/writepanel-product-tab_actions.php';
/**
 * Save meta boxes
 */
add_action('save_post', 'wc_tab_manager_meta_boxes_save', 1, 2);
/**
 * Runs when a post is saved and does an action which the write panel save scripts can hook into.
 *
 * @access public
 * @param int $post_id post identifier
 * @param object $post post object
 */
function wc_tab_manager_meta_boxes_save($post_id, $post)
{
    if (empty($post_id) || empty($post) || empty($_POST)) {
        return;