WordPress

php — Usuń błąd wielu niestandardowych typów postów z hierarchią i bez niej

  • 18 grudnia, 2023
  • 7 min read
php — Usuń błąd wielu niestandardowych typów postów z hierarchią i bez niej


Mam dwa niestandardowe typy postów o nazwie toplijst i produkt. Próbuję osiągnąć następującą strukturę łącza bezpośredniego:

Toplijst:

website.com/toplijst/parent-toplijst/

website.com/toplijst/parent-toplijst/child-toplijst/

Powinno stać się:

website.com/parent-toplijst/ website.com/parent-toplijst/child-toplijst/

Produkt

website.com/product/product-post

Powinno stać się

strona internetowa.com/product-post

Typ postu produktowego nie jest typem postu hierarchicznego.

Mam zarejestrowany typ postu w następujący sposób:

require_once dirname(__FILE__) . '/../classes/class-slugless-rewrites.php';

// Create toplijst post type
function create_toplijst_post_type()
{
    $labels = array(
        'name'               => _x('Toplijsten', 'post type general name', 'text-domain'),
        'singular_name'      => _x('Toplijst', 'post type singular name', 'text-domain'),
        'menu_name'          => _x('Toplijsten', 'admin menu', 'text-domain'),
        'name_admin_bar'     => _x('Toplijst', 'add new on admin bar', 'text-domain'),
        'add_new'            => _x('Add New', 'Toplijst', 'text-domain'),
        'add_new_item'       => __('Add New Toplijst', 'text-domain'),
        'new_item'           => __('New Toplijst', 'text-domain'),
        'edit_item'          => __('Edit Toplijst', 'text-domain'),
        'view_item'          => __('View Toplijst', 'text-domain'),
        'all_items'          => __('All Toplijsten', 'text-domain'),
        'search_items'       => __('Search Toplijsten', 'text-domain'),
        'parent_item_colon'  => __('Parent Toplijsten:', 'text-domain'),
        'not_found'          => __('No Toplijsten found.', 'text-domain'),
        'not_found_in_trash' => __('No Toplijsten found in Trash.', 'text-domain')
    );

    $args = array(
        'labels'             => $labels,
        'public'             => true,
        'publicly_queryable' => true,
        'show_ui'            => true,
        'show_in_menu'       => true,
        'query_var'          => true,
        'show_in_rest'       => true,
        'rewrite'            => false,
        'has_archive'        => 'toplijsten',
        'capability_type'    => 'post',
        'hierarchical'       => true,
        'menu_position'      => null,
        'menu_icon'          => 'dashicons-list-view',
        'supports'           => array('title', 'author', 'revisions', 'thumbnail', 'custom-fields', 'page-attributes')
    );

    register_post_type('toplijst', $args);
}

add_action('init', 'create_toplijst_post_type');

// Create producten post type
function create_producten_post_type()
{
    $labels = array(
        'name'               => _x('Producten', 'post type general name', 'text-domain'),
        'singular_name'      => _x('Product', 'post type singular name', 'text-domain'),
        'menu_name'          => _x('Producten', 'admin menu', 'text-domain'),
        'name_admin_bar'     => _x('Product', 'add new on admin bar', 'text-domain'),
        'add_new'            => _x('Add New', 'Product', 'text-domain'),
        'add_new_item'       => __('Add New Product', 'text-domain'),
        'new_item'           => __('New Product', 'text-domain'),
        'edit_item'          => __('Edit Product', 'text-domain'),
        'view_item'          => __('View Product', 'text-domain'),
        'all_items'          => __('All Producten', 'text-domain'),
        'search_items'       => __('Search Producten', 'text-domain'),
        'parent_item_colon'  => __('Parent Producten:', 'text-domain'),
        'not_found'          => __('No Producten found.', 'text-domain'),
        'not_found_in_trash' => __('No Producten found in Trash.', 'text-domain')
    );

    $args = array(
        'labels'             => $labels,
        'public'             => true,
        'publicly_queryable' => true,
        'show_ui'            => true,
        'show_in_menu'       => true,
        'query_var'          => true,
        'rewrite'            => false,
        'capability_type'    => 'post',
        'hierarchical'       => false,
        'menu_position'      => null,
        'menu_icon'          => 'dashicons-star-filled', // Choose an appropriate dashicon
        'supports'           => array('title', 'author', 'revisions', 'thumbnail', 'custom-fields', 'page-attributes')
    );

    register_post_type('product', $args);
}
add_action('init', 'create_producten_post_type');

$slugless_rewrite_args = array(
    'toplijst' => array(
        'hierarchical' => true,
        'has_archive' => true,
        'archive_feeds' => false,
        'archive_slug' => 'toplijsten'
    ),
    'product' => array(
        'hierarchical' => false,
        'has_archive' => false,
        'archive_feeds' => false
    )
);

$slugless_rewrites = Slugless_Rewrites::get_instance($slugless_rewrite_args);

Jak widać, skonfigurowałem klasę Slugless_Rewrites do obsługi łączy bezpośrednich. Kod klasy znajduje się tutaj:

class Slugless_Rewrites
{
    private $post_types = [];
    private static $instance = null;

    public static function get_instance($post_types)
    {
        if (self::$instance === null) {
            self::$instance = new self($post_types);
        }
        return self::$instance;
    }

    private function __construct($post_types)
    {
        foreach ($post_types as $post_type => $args) {
            $args = wp_parse_args($args, array(
                'hierarchical'  => false,
                'has_archive'   => false,
                'archive_feeds' => false,
                'archive_slug'  => $post_type
            ));

            $this->post_types[$post_type] = $args;

            add_action('init', function () use ($post_type, $args) {
                $this->add_rewrites($post_type, $args);
            }, 20);

            add_filter('rewrite_rules_array', function ($rules) use ($post_type) {
                return $this->inject_rules($rules, $post_type);
            });
        }

        add_filter('request', array($this, 'check_rewrite_conflicts'));
        add_filter('query_vars', array($this, 'custom_query_vars'));
        add_filter('post_type_link', array($this, 'modify_permalinks'), 10, 3);
        add_filter('wp_unique_post_slug', array($this, 'prevent_slug_duplicates'), 10, 6);
    }

    public function __clone()
    {
    }

    public function __wakeup()
    {
    }

    private function add_rewrites($post_type, $args)
    {
        add_rewrite_tag("%{$post_type}_type%", '([^&]+)');

        if ($args['hierarchical']) {
            add_rewrite_rule(
                '^' . $post_type . '/(.+)/([^/]+)(?:/([0-9]+))?/?$',
                'index.php?post_type=" . $post_type . "&pagename=$matches[1]/$matches[2]&page=$matches[3]',
                'top'
            );
        } else {
            add_rewrite_rule(
                '^' . $post_type . '/([^/]+)/?$',
                'index.php?post_type=" . $post_type . "&name=$matches[1]',
                'top'
            );
        }
    }

    private function inject_rules($rules, $post_type)
    {
        $new_rules = [
            '^' . $post_type . '/(.+)/([^/]+)(?:/([0-9]+))?/?$' => 'index.php?post_type=" . $post_type . "&pagename=$matches[1]/$matches[2]&page=$matches[3]'
        ];

        return $new_rules + $rules;
    }

    public function check_rewrite_conflicts($query_vars)
    {
        if (isset($query_vars['name'])) {
            $post_type = $this->determine_post_type($query_vars['name']);
            if ($post_type) {
                do_action('qm/debug', 'Initial query vars: ' . $post_type);
                $query_vars['post_type'] = $post_type;
            } else {
                foreach ($this->post_types as $type => $args) {
                    if ($args['hierarchical']) {
                        $path = $query_vars['pagename'] ?? $query_vars['name'];
                        $page = get_page_by_path($path, OBJECT, $type);
                        if ($page) {
                            $query_vars['post_type'] = $type;
                            $query_vars['pagename'] = $path;
                            unset($query_vars['name']);
                            do_action('qm/debug', 'Final query vars: ' . print_r($query_vars, true));

                            return $query_vars;
                        }
                    }
                }

                $page = get_page_by_path($query_vars['name']);
                if ($page) {
                    $query_vars['post_type'] = 'page';
                    $query_vars['pagename'] = $query_vars['name'];
                } else {
                    $query_vars['post_type'] = 'toplijst';
                    $query_vars['pagename'] = $query_vars['name'];
                }
            }
        }

        do_action('qm/debug', 'Final query vars: ' . print_r($query_vars, true));

        return $query_vars;
    }

    private function determine_post_type($slug)
    {
        $post_types_to_check = array_merge(['page'], array_keys($this->post_types));

        foreach ($post_types_to_check as $post_type) {
            $posts = get_posts([
                'name'           => $slug,
                'post_type'      => $post_type,
                'post_status'    => 'publish',
                'numberposts'    => 1
            ]);

            if (!empty($posts)) {
                return $post_type;
            }
        }

        return null;
    }

    public function custom_query_vars($query_vars)
    {
        foreach (array_keys($this->post_types) as $post_type) {
            $query_vars[] = $post_type;
        }
        return $query_vars;
    }

    public function modify_permalinks($post_link, $post, $leavename)
    {
        foreach ($this->post_types as $post_type => $args) {
            if ($post->post_type == $post_type) {
                $slug = $post->post_name;
                $parent_id = $post->post_parent;
                while ($parent_id) {
                    $parent_post = get_post($parent_id);
                    $slug = $parent_post->post_name . " . $slug;
                    $parent_id = $parent_post->post_parent;
                }

                $slug = str_replace("{$post_type}/", '', $slug);
                return home_url($slug);
            }
        }
        return $post_link;
    }

    public function prevent_slug_duplicates($slug, $post_ID, $post_status, $post_type, $post_parent, $original_slug)
    {
        foreach ($this->post_types as $type => $args) {
            if ($post_type != $type && !in_array($post_type, ['post', 'page'])) {
                continue;
            }
            if (get_page_by_path($slug, OBJECT, $type)) {
                return $slug . '-duplicate';
            }
        }
        return $slug;
    }
}

Klasa pomyślnie tworzy następującą strukturę:

Warto przeczytać!  motywy — Jak usunąć pole komentarza_notes_before w formularzu komentarza WordPress

Toplijst:

website.com/parent-toplijst/

Jednak dziecko-toplijst nie działa na:

website.com/parent-toplijst/child-toplijst/

To działa na:

website.com/child-toplijst/

Produkt

Działa zgodnie z oczekiwaniami.

Moje pytanie brzmi: jak mogę uzyskać hierarchiczny niestandardowy typ postu toplijst, aby działał z niestandardową strukturą, którą próbuję skonfigurować.

Zastanawiam się również, czy jest to najlepsza metoda przepisywania niestandardowych łączy bezpośrednich typu post.

Pomoc w tym problemie byłaby bardzo mile widziana!


Źródło