TeaThemeOptions/TeaThemeOptions

View on GitHub
src/Core/PostType/PosttypeHook.php

Summary

Maintainability
D
2 days
Test Coverage
<?php

namespace crewstyle\OlympusZeus\Core\Posttype;

use crewstyle\OlympusZeus\OlympusZeus;
use crewstyle\OlympusZeus\Core\Field\Field;
use crewstyle\OlympusZeus\Core\Posttype\PosttypeEngine;

/**
 * Works with Posttype Engine.
 *
 * @package Olympus Zeus
 * @subpackage Core\Posttype\PosttypeHook
 * @author Achraf Chouk <achrafchouk@gmail.com>
 * @since 4.0.0
 *
 */

class PosttypeHook
{
    /**
     * @var array
     */
    protected $posttypes = array();

    /**
     * Constructor.
     *
     * @since 3.0.0
     */
    public function __construct(){}

    /**
     * Build args.
     *
     * @param array $ctn Contains all post type contents
     * @return array $args Contains all args
     *
     * @since 3.3.0
     */
    public static function defineArgs($ctn)
    {
        return array(
            'can_export' => !isset($ctn['can_export']) || !$ctn['can_export'] ? false : true,
            'capability_type' => isset($ctn['capability_type']) ? $ctn['capability_type'] : 'post',
            'description' => isset($ctn['description']) ? $ctn['description'] : '',
            'exclude_from_search' => isset($ctn['exclude_from_search']) && $ctn['exclude_from_search'] ? true : false,
            'has_archive' => isset($ctn['has_archive']) && $ctn['has_archive'] ? true : false,
            'hierarchical' => isset($ctn['hierarchical']) && $ctn['hierarchical'] ? true : false,
            'menu_icon' => isset($ctn['menu_icon']) ? $ctn['menu_icon'] : '',
            'menu_position' => isset($ctn['menu_position']) ? $ctn['menu_position'] : 100,
            'public' => isset($ctn['public']) && $ctn['public'] ? true : false,
            'publicly_queryable' => isset($ctn['publicly_queryable']) && $ctn['publicly_queryable'] ? true : false,

            'permalink_epmask' => EP_PERMALINK,
            'query_var' => true,
            'rewrite' => false,
            'show_in_menu' => true,
            'show_ui' => true,

            'supports' => isset($ctn['supports']) && is_array($ctn['supports']) ? $ctn['supports'] : array(),
            'taxonomies' => isset($ctn['taxonomies']) && is_array($ctn['taxonomies']) ? $ctn['taxonomies'] : array(),

            'show_in_rest' => true,
            'rest_base' => $ctn['slug'],
            'rest_controller_class' => 'WP_REST_Posts_Controller',
        );
    }

    /**
     * Build lables.
     *
     * @param array $ctn Contains all post type contents
     * @return array $labels Contains all labels
     *
     * @since 3.0.0
     */
    public static function defineLabels($ctn)
    {
        return array(
            'name' => $ctn['name'],
            'singular_name' => isset($ctn['singular_name']) && !empty($ctn['singular_name']) 
                ? $ctn['singular_name'] 
                : $ctn['name'],
            'menu_name' => isset($ctn['menu_name']) && !empty($ctn['menu_name']) 
                ? $ctn['menu_name'] 
                : $ctn['name'],

            'add_new' => isset($ctn['add_new']) && !empty($ctn['add_new']) 
                ? $ctn['add_new'] 
                : OlympusZeus::translate('Add new'),
            'add_new_item' => isset($ctn['add_new_item']) && !empty($ctn['add_new_item']) 
                ? $ctn['add_new_item'] 
                : OlympusZeus::translate('Add new item'),
            'all_items' => isset($ctn['all_items']) && !empty($ctn['all_items']) 
                ? $ctn['all_items'] 
                : $ctn['name'],
            'edit' => isset($ctn['edit']) && !empty($ctn['edit']) 
                ? $ctn['edit'] 
                : OlympusZeus::translate('Edit'),
            'edit_item' => isset($ctn['edit_item']) && !empty($ctn['edit_item']) 
                ? $ctn['edit_item'] 
                : OlympusZeus::translate('Edit item'),
            'new_item' => isset($ctn['new_item']) && !empty($ctn['new_item']) 
                ? $ctn['new_item'] 
                : OlympusZeus::translate('New item'),

            'not_found' => isset($ctn['not_found']) && !empty($ctn['not_found']) 
                ? $ctn['not_found'] 
                : OlympusZeus::translate('No item found'),
            'not_found_in_trash' => isset($ctn['not_found_in_trash']) && !empty($ctn['not_found_in_trash']) 
                ? $ctn['not_found_in_trash'] 
                : OlympusZeus::translate('No item found in Trash'),
            'parent_item_colon' => isset($ctn['parent_item_colon']) && !empty($ctn['parent_item_colon']) 
                ? $ctn['parent_item_colon'] 
                : OlympusZeus::translate('Parent item'),
            'search_items' => isset($ctn['search_items']) && !empty($ctn['search_items']) 
                ? $ctn['search_items'] 
                : OlympusZeus::translate('Search items'),

            'view' => isset($ctn['view']) && !empty($ctn['view']) 
                ? $ctn['view'] 
                : OlympusZeus::translate('View'),
            'view_item' => isset($ctn['view_item']) && !empty($ctn['view_item']) 
                ? $ctn['view_item'] 
                : OlympusZeus::translate('View item'),
        );
    }

    /**
     * Hook to change columns on post type list page.
     *
     * @param array $columns Contains list of columns
     * @return array $columns Contains list of columns
     *
     * @since 4.0.0
     */
    public function hookColumns($columns)
    {
        //Get current post type
        $current = isset($_GET['post_type']) ? $_GET['post_type'] : '';

        //check post type
        if (empty($current)) {
            return $columns;
        }

        /**
         * Filter the column headers for a list table on a specific screen.
         *
         * The dynamic portion of the hook name, `$current`, refers to the
         * post type of the current edit screen ID.
         *
         * @var string $current
         * @param array $columns
         * @return array $columns
         *
         * @since 4.0.0
         */
        return apply_filters('olz_manage_edit-'.$current.'_posttype_columns', $columns);
    }

    /**
     * Hook to add featured image to column.
     *
     * @param string $column Contains current column ID
     * @param integer $post_id Contains current post ID
     *
     * @since 4.0.0
     */
    public function hookCustomColumn($column, $post_id)
    {
        //Get current post type
        $current = isset($_GET['post_type']) ? $_GET['post_type'] : '';

        //check post type
        if (empty($current)) {
            return;
        }

        /**
         * Fires for each custom column of a specific post type in the Posts list table.
         *
         * @param string $column
         * @param int $post_id
         *
         * @since 3.3.0
         */
        do_action('olz_manage_'.$current.'_posttype_custom_column', $column, $post_id);
    }

    /**
     * Hook building custom fields for CPTS.
     *
     * @uses add_meta_box()
     *
     * @since 4.0.0
     */
    public function hookFieldsDisplay()
    {
        //Defintions
        $slug = isset($_GET['post_type']) ? $_GET['post_type'] : '';
        $contents = array();
        $ids = array();

        //Define current post type's contents
        if (empty($slug)) {
            $post = isset($_GET['post']) ? $_GET['post'] : 0;
            $slug = !empty($post) ? get_post_type($post) : '';

            if (empty($slug)) {
                return;
            }
        }

        /**
         * Build post type contents.
         *
         * @var string $slug
         * @param array $contents
         * @return array $contents
         *
         * @since 4.0.0
         */
        $contents = apply_filters('olz_posttype_'.$slug.'_contents', $contents);

        //Check contents
        if (empty($contents)) {
            return;
        }

        //Get contents
        foreach ($contents as $ctn) {
            //Check fields
            if (empty($ctn)) {
                continue;
            }

            //Get type and id
            $type = isset($ctn['type']) ? $ctn['type'] : '';
            $id = isset($ctn['id']) ? $ctn['id'] : '';

            //Check if we are authorized to use this field in CPTs
            if (empty($type)) {
                continue;
            }

            //Title
            $title = isset($ctn['title']) ? $ctn['title'] : OlympusZeus::translate('Metabox');

            //Get field instance
            $field = Field::getField($type, $id, array(), $ids);

            //Check error
            if (is_array($field) && $field['error']) {
                continue;
            }

            //Update ids
            if (!empty($id)) {
                $ids[] = $id;
            }

            //Add meta box
            add_meta_box(
                $slug.'-meta-box-'.$id,
                $title,
                array(&$field, 'hookFieldBuild'),
                $slug,
                'normal',
                'low',
                array(
                    'type' => $type,
                    'field' => $field,
                    'contents' => $ctn
                )
            );
        }
    }

    /**
     * Hook building custom options in Permalink settings page.
     *
     * @uses register_setting()
     * @uses add_settings_field()
     *
     * @since 4.0.0
     */
    public function hookFieldsPermalink()
    {
        if (empty($this->posttypes)) {
            return false;
        }

        //Add section
        add_settings_section(
            'olz-permalinks',                               //ID
            OlympusZeus::translate('Custom Permalinks'),    //Title
            array(&$this,'hookPermalinkTitle'),             //Callback
            'permalink'                                     //Page
        );

        //Flush all rewrite rules
        if (isset($_POST['olz-flushpermalink'])) {
            flush_rewrite_rules();
        }

        //Iterate on each cpt
        foreach ($this->posttypes as $pt) {
            //Special case: do not change post/page component
            if (in_array($pt['slug'], array('post', 'page'))) {
                continue;
            }

            //Option
            $opt = str_replace('%SLUG%', $pt['slug'], PosttypeEngine::getPermalink());

            //Check POST
            if (isset($_POST[$opt])) {
                $value = $_POST[$opt];
                OlympusZeus::setOption($opt, $value);
            }
            else {
                $value = OlympusZeus::getOption($opt, '/%'.$pt['slug'].'%-%post_id%');
            }

            //Define metabox title
            $title = $pt['labels']['name'].' <code>%'.$pt['slug'].'%</code>';

            //Add fields
            add_settings_field(
                $opt,                               //Identifier
                $title,                             //Title
                array(&$this,'hookPermalinkSet'),   //Callback function
                'permalink',                        //Page
                'olz-permalinks',                   //Section
                array(
                    'name' => $opt,
                    'value' => $value,
                )
            );
        }

        return true;
    }

    /**
     * Hook building custom fields for Post types.
     *
     * @uses update_post_meta()
     *
     * @since 4.0.0
     */
    public function hookFieldsSave()
    {
        global $post;

        if (!isset($post)) {
            return false;
        }

        if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
            return $post->ID;
        }

        //Get contents
        $slug = $post->post_type;
        $contents = array();

        /**
         * Build post type contents.
         *
         * @var string $slug
         * @param array $contents
         * @return array $contents
         *
         * @since 4.0.0
         */
        $contents = apply_filters('olz_posttype_'.$slug.'_contents', $contents);

        //Check contents
        if (empty($contents)) {
            return false;
        }

        //Update all metas
        foreach ($contents as $ctn) {
            $value = isset($_REQUEST[$ctn['id']]) ? $_REQUEST[$ctn['id']] : '';
            update_post_meta($post->ID, $post->post_type.'-'.$ctn['id'], $value);
        }

        return true;
    }

    /**
     * Hook building custom permalinks for post types.
     * From: http://shibashake.com/wordpress-theme/custom-post-type-permalinks-part-2
     *
     * @param string $permalink Contains permalink structure
     * @param integer $post_id Contains post ID
     * @param boolean $leavename Defeine wether to use postname or not
     * @return string $permalink Permalink final structure
     *
     * @since 4.0.0
     */
    public function hookPermalinkMake($permalink, $post_id, $leavename)
    {
        if (!$post_id) {
            return '';
        }

        //Get post's datas
        $post = get_post($post_id);

        //Define permalink structure
        $rewritecode = array(
            '%year%',
            '%monthnum%',
            '%day%',
            '%hour%',
            '%minute%',
            '%second%',
            $leavename ? '' : '%postname%',
            '%post_id%',
            '%category%',
            '%author%',
            $leavename ? '' : '%pagename%',
        );

        if ('' === $permalink || in_array($post->post_status, array('draft', 'pending', 'auto-draft'))) {
            return $permalink;
        }

        //Need time
        $unixtime = strtotime($post->post_date);
        $date = explode(' ', date('Y m d H i s', $unixtime));

        //Need category
        $category = '';

        //Get categories
        if (strpos($permalink, '%category%') !== false) {
            $cats = get_the_category($post->ID);

            if ($cats) {
                usort($cats, '_usort_terms_by_ID');
                $category = $cats[0]->slug;

                if ($parent = $cats[0]->parent) {
                    $category = get_category_parents($parent, false, '/', true) . $category;
                }
            }

            //Show default category in permalinks, without having to assign it explicitly
            if (empty($category)) {
                $default_category = get_category(OlympusZeus::getOption('default_category'));
                $category = is_wp_error($default_category) ? '' : $default_category->slug;
            }
        }

        //Need author
        $author = '';

        //Get authors
        if (strpos($permalink, '%author%') !== false) {
            $authordata = get_userdata($post->post_author);
            $author = $authordata->__get('user_nicename');
        }

        //Define permalink values
        $rewritereplace = array(
            $date[0],
            $date[1],
            $date[2],
            $date[3],
            $date[4],
            $date[5],
            $post->post_name,
            $post->ID,
            $category,
            $author,
            $post->post_name,
        );

        //Change structure
        $permalink = str_replace($rewritecode, $rewritereplace, $permalink);

        //Return permalink
        return $permalink;
    }

    /**
     * Hook to display input value on Permalink settings page.
     *
     * @param array $vars Contains all usefull data
     *
     * @since 4.0.0
     */
    public function hookPermalinkSet($vars)
    {
        if (empty($vars)) {
            return;
        }

        $vars['t_description'] = OlympusZeus::translate('The following structure uses the same rules 
            than post\'s permalink structure that you can built with <code>%year%</code>, <code>%monthnum%</code>, 
            <code>%day%</code>, <code>%hour%</code>, <code>%minute%</code>, <code>%second%</code>, 
            <code>%post_id%</code>, <code>%category%</code>, <code>%author%</code> and <code>%pagename%</code>. 
            If you need to display the <code>%postname%</code>, simply use the custom post type\'s slug instead.');
        $vars['t_home'] = OLZ_HOME;

        //Render template
        OlympusZeus::getRender('layouts/permalinks.html.twig', $vars);
    }

    /**
     * Hook to display hidden input on Permalink settings title page.
     *
     * @since 4.0.0
     */
    public function hookPermalinkTitle()
    {
        //Display settings
        $this->hookPermalinkSet(array(
            'name' => 'olz-flushpermalink',
            'value' => '1',
        ));
    }

    /**
     * Register post type
     *
     * @param array $posttype Contains all posttype details
     * @return array $posttype
     * @uses register_post_type()
     *
     * @since 4.0.0
     */
    public function registerPostType($posttype = array())
    {
        //Check post types
        if (empty($posttype)) {
            return array();
        }

        //Check slug
        if (!isset($posttype['slug']) || empty($posttype['slug'])) {
            return array();
        }

        //Store slug
        $slug = $posttype['slug'];

        //Special case: define a post/page as title
        //to edit default post/page component
        if (in_array($slug, array('post', 'page'))) {
            return array();
        }

        //Check if post type already exists
        if (post_type_exists($slug)) {
            return array();
        }

        //Build labels
        $labels = $this->defineLabels($posttype['labels']);

        //Build args
        $args = $this->defineArgs($posttype);
        $args['labels'] = $labels;

        //Action to register
        register_post_type($slug, $args);

        //Update post type
        $posttype = array_merge($posttype, $args);

        //Option
        $opt = str_replace('%SLUG%', $slug, PosttypeEngine::getPermalink());

        //Get value
        $structure = OlympusZeus::getOption($opt, '/%'.$slug.'%-%post_id%');

        //Change structure
        add_rewrite_tag('%'.$slug.'%', '([^/]+)', $slug.'=');
        add_permastruct($slug, $structure, false);

        return array($posttype, $slug);
    }

    /**
     * Build post types.
     *
     * @param array $pts Contains all post types.
     * @uses add_action()
     *
     * @since 4.0.0
     */
    public function setPostTypes($pts)
    {
        //Define post types
        $this->posttypes = $pts;

        //Add WP Hooks
        add_action('init', function (){
            //Check post types
            if (empty($this->posttypes)) {
                return;
            }

            //Get all registered post types
            $posttypes = array();

            //Register post type
            foreach ($this->posttypes as $pt) {
                $p = $this->registerPostType($pt);

                if (empty($p) || empty($p[0])) {
                    unset($this->posttypes[$pt['slug']]);
                    continue;
                }

                //Manage columns
                if (OLZ_ISADMIN) {
                    add_filter('manage_edit-'.$p[1].'_columns', array(&$this, 'hookColumns'), 10);
                    add_action('manage_'.$p[1].'_posts_custom_column', array(&$this, 'hookCustomColumn'), 11, 2);
                }

                $this->posttypes[$pt['slug']] = $p[0];
            }

            //Update DB
            OlympusZeus::setConfigs(PosttypeEngine::getIndex(), $this->posttypes);

            //Permalink structures
            add_action('post_type_link', array(&$this, 'hookPermalinkMake'), 10, 3);

            if (OLZ_ISADMIN) {
                //Display post type's custom fields
                add_action('admin_init', array(&$this, 'hookFieldsDisplay'));

                //Display settings in permalinks page
                add_action('admin_init', array(&$this, 'hookFieldsPermalink'));

                //Save post type's custom fields
                add_action('save_post', array(&$this, 'hookFieldsSave'));
            }
        }, 10, 1);
    }
}