wordpress:如何添加层次结构到文章

ioekq8ef  于 2023-01-20  发布在  WordPress
关注(0)|答案(9)|浏览(137)

我在wordpress平台上创建了一个网站,我想在那里发布我自己的书籍文本。所以我想要的是有某种层次结构,我会添加一个职位,然后添加儿童到它(章节)。我发现这一点:

register_post_type( 'post', array(
        'labels' => array(
            'name_admin_bar' => _x( 'Post', 'add new on admin bar' ),
        ),
        'public'  => true,
        '_builtin' => true, /* internal use only. don't use this when registering your own post type. */
        '_edit_link' => 'post.php?post=%d', /* internal use only. don't use this when registering your own post type. */
        'capability_type' => 'post',
        'map_meta_cap' => true,
        'hierarchical' => false,
        'rewrite' => false,
        'query_var' => false,
        'supports' => array( 'title', 'editor', 'author', 'thumbnail', 'excerpt', 'trackbacks', 'custom-fields', 'comments', 'revisions', 'post-formats' ),
    ) );

并试图制作'hierarchical"=>true,但没有效果,有人能帮忙吗?

eqoofvh9

eqoofvh91#

这是我的解决方法。这完全达到了你想要的,能够为内置的post类型post设置post的父对象。你可以通过在registred_post_type action hook中添加一个action来实现这一点。只要把它添加到你的主题的functions.php中就行了。

add_action('registered_post_type', 'igy2411_make_posts_hierarchical', 10, 2 );

// Runs after each post type is registered
function igy2411_make_posts_hierarchical($post_type, $pto){

    // Return, if not post type posts
    if ($post_type != 'post') return;
    
    // access $wp_post_types global variable
    global $wp_post_types;
    
    // Set post type "post" to be hierarchical
    $wp_post_types['post']->hierarchical = 1;

    // Add page attributes to post backend
    // This adds the box to set up parent and menu order on edit posts.
    add_post_type_support( 'post', 'page-attributes' );

}

有很多原因可以解释为什么将帖子层次化是有帮助的。我的用例是客户希望将他们的(已经存在的)帖子结构化为问题,其中子帖子是一个问题(父帖子)的文章。
通过使用将查询限制为仅显示没有父项的帖子,可以轻松实现这一点。

'post_parent' => 0,

在查询$args中。

shyt4zoc

shyt4zoc2#

工作方案4.9.*
上述解决方案使友好URL变得疯狂。
我的解决方案添加层次结构到任何现有的职位类型:

add_filter( 'register_post_type_args', 'add_hierarchy_support', 10, 2 );
function add_hierarchy_support( $args, $post_type ){

    if ($post_type === 'post') { // <-- enter desired post type here

        $args['hierarchical'] = true;
        $args['supports'] = array_merge($args['supports'], array ('page-attributes') );
    }

    return $args;
}

重新保存wp设置到/wp-admin/options-permalink. php

daupos2t

daupos2t3#

更新

由于一些评论引发了新的用例和问题,我重写了这段代码,并在我自己的网站上使用它[在5.8.2中测试]。我已经提供了它的要点。你可以把它包含在你的functions.php中,或者把它做成一个插件。
https://gist.github.com/amurrell/00d29a86fc1a773274bf049ef545b29f
🎉 这个新的更新是利用SQL(快速!)来解析slug和post id,以确定永久链接和路由。它产生完全匹配的post id,即使您使用相同的post_name为不同的post后代。它真的是快速和可靠!
在本文中,最有趣的函数是get_post_from_uri($uri)

  • 我构建了一个自定义查询,它将为我们确定固定链接,并找到完全匹配的帖子ID。
  • 为什么要查询呢?没有wordpress的功能可以帮助你确定一个帖子的完整血统,而不会让你陷入循环。
  • 但是关系存在于数据中!!
  • 因此,最好的方法,以确保我们得到良好的友好的永久链接网址是利用数据库和查询语言的力量。

👇 让我们看看查询是如何工作的,这可能不是一个完美的1 - 1代码,因为我把它动态化了,但是概念是存在的:

示例:

我有以下职位:

      • 气候**[547]
  • 创新联盟[1395]
      • 气候**[1808]
  • 采购[518]
  • 城市销售周期[1345]
      • 气候**[1811]

在SQL中查看:

mysql> select id, post_name, post_parent from wp_posts where post_type = 'post' and id in (1811, 1808, 1345, 1395, 547, 518);
+------+-------------------------+-------------+
| id   | post_name               | post_parent |
+------+-------------------------+-------------+
|  518 | procurement             |           0 |
|  547 | climate                 |           0 |
| 1345 | city-sales-cycle        |         518 |
| 1395 | alliance-for-innovation |           0 |
| 1808 | climate                 |        1395 |
| 1811 | climate                 |        1345 |
+------+-------------------------+-------------+

示例URL:alliance-for-innovation/climate

完整查询...

mysql> select * from
    -> (select TRIM(BOTH '/' FROM concat(
    ->   IFNULL(p3_slug,''),
    ->   '/',
    ->   IFNULL(p2_slug,''),
    ->   '/',
    ->   p1_slug
    -> )
    -> ) as slug,
    -> id
    -> from (
    -> select d2.*, p3.post_name as p3_slug, p3.post_parent as p3_parent from (
    -> select d1.*, p2.post_name as p2_slug, p2.post_parent as p2_parent from (
    -> select id, post_name as p1_slug, post_parent as p1_parent from wp_posts where post_type = 'post' and post_name = 'climate'
    -> ) as d1
    -> left join wp_posts p2 on p2.id = d1.p1_parent
    -> ) as d2
    -> left join wp_posts p3 on p3.id = d2.p2_parent) as d3
    ->
    -> ) as all_slugs
    -> where slug = 'alliance-for-innovation/climate';
+---------------------------------+------+
| slug                            | id   |
+---------------------------------+------+
| alliance-for-innovation/climate | 1808 |
+---------------------------------+------+
1 row in set (0.01 sec)

我现在有两个职位ID * 和 * 的slug,或永久链接,我应该使用!
值得注意的是,我转到了p3层,这比URL所需的多一层(两部分),这是为了防止类似alliance-for-innovation/climate/something的内容匹配。

它是如何工作的?分解查询

有一个内部查询查找URL的最后一部分,即basename,在本例中为climate

mysql> select id, post_name as p1_slug, post_parent as p1_parent from wp_posts where post_type = 'post' and post_name = 'climate';
+------+---------+-----------+
| id   | p1_slug | p1_parent |
+------+---------+-----------+
|  547 | climate |         0 |
| 1808 | climate |      1395 |
| 1811 | climate |      1345 |
+------+---------+-----------+

在编程上,我们不断地在直接与url中/的数目相关的查询周围添加抽象,这样我们就可以找到关于post_parent的slug的更多信息。

mysql> select d1.*, p2.post_name as p2_slug, p2.post_parent as p2_parent from (
    -> select id, post_name as p1_slug, post_parent as p1_parent from wp_posts where post_type = 'post' and post_name = 'climate'
    -> ) as d1
    -> left join wp_posts p2 on p2.id = d1.p1_parent;
+------+---------+-----------+-------------------------+-----------+
| id   | p1_slug | p1_parent | p2_slug                 | p2_parent |
+------+---------+-----------+-------------------------+-----------+
|  547 | climate |         0 | NULL                    |      NULL |
| 1808 | climate |      1395 | alliance-for-innovation |         0 |
| 1811 | climate |      1345 | city-sales-cycle        |       518 |
+------+---------+-----------+-------------------------+-----------+

在我们进行了足够多次的抽象之后,我们可以 * 选择concats作为slug *,例如:p1_嵌段+'/'+ p2_嵌段

mysql> select TRIM(BOTH '/' FROM concat(
    ->   IFNULL(p3_slug,''),
    ->   '/',
    ->   IFNULL(p2_slug,''),
    ->   '/',
    ->   p1_slug
    -> )
    -> ) as slug,
    -> id
    -> from (
    -> select d2.*, p3.post_name as p3_slug, p3.post_parent as p3_parent from (
    -> select d1.*, p2.post_name as p2_slug, p2.post_parent as p2_parent from (
    -> select id, post_name as p1_slug, post_parent as p1_parent from wp_posts where post_type = 'post' and post_name = 'climate'
    -> ) as d1
    -> left join wp_posts p2 on p2.id = d1.p1_parent
    -> ) as d2
    -> left join wp_posts p3 on p3.id = d2.p2_parent) as d3
    ->
    -> ;
+--------------------------------------+------+
| slug                                 | id   |
+--------------------------------------+------+
| climate                              |  547 |
| alliance-for-innovation/climate      | 1808 |
| procurement/city-sales-cycle/climate | 1811 |
+--------------------------------------+------+

最后一步是为原始url添加一个wherealliance-for-innovation/climate。这就是我们在第一个完整查询示例中看到的内容!

让我们看看其他人的表现:

# climate

+---------+-----+
| slug    | id  |
+---------+-----+
| climate | 547 |
+---------+-----+
# procurement/city-sales-cycle/climate

+--------------------------------------+------+
| slug                                 | id   |
+--------------------------------------+------+
| procurement/city-sales-cycle/climate | 1811 |
+--------------------------------------+------+

我喜欢此更新的另一点是我记得:

转义climate,即我们在查询中使用的URL的基本名称,因为从技术上讲,这是用户输入的(通过url)

$wpdb->_real_escape($basename));

那么这个查询构建函数是如何动态的呢?

我们使用PHP数组、循环等来 * 构建一个将成为查询的字符串 *,这样我们就不必使用PHP来处理数据本身的逻辑。
这是一个显示动态抽象的片段-例如,要抓取多少个p1_slug、p2_slug、p3_slug。

// We will do 1 more depth level than we need to confirm the slug would not lazy match
  // This for loop builds inside out.
  for ($c = 1; $c < $depth + 2; $c++) {
    $d = $c;
    $p = $c + 1;

    $pre = "select d${d}.*, p${p}.post_name as p${p}_slug, p${p}.post_parent as p${p}_parent from (";
    $suf = ") as d${d} left join $wpdb->posts p${p} on p${p}.id = d${d}.p${c}_parent";

    $sql = $pre . $sql . $suf;

    $concats[] = sprintf("IFNULL(p${p}_slug,'')");
  }

上一个答案:

我来这里是为了实现:
1.向post_type帖子添加页面属性以添加父帖子
1.能够为post_type帖子添加页面模板
1.能够在post_type帖子上获得分层固定链接结构
我能够使用the accepted answer完成1和2,但不能完成3。

    • 注意**:要让2完全生效,你需要在页面模板的模板评论中指定post_type,如下所示:
<?php
/*
Template Name: Your Post Template Name
Template Post Type: post
*/

对于3,我发现了一个插件,破坏了我的post_type页面,它是很多相当糟糕的,未经维护的代码。
所以我借用this answer编写了一个解决方案来完成这一切:
(用4.9.8测试)

<?php

add_action('registered_post_type', 'make_posts_hierarchical', 10, 2 );

// Runs after each post type is registered
function make_posts_hierarchical($post_type, $pto){

    // Return, if not post type posts
    if ($post_type != 'post') return;

    // access $wp_post_types global variable
    global $wp_post_types;

    // Set post type "post" to be hierarchical
    $wp_post_types['post']->hierarchical = 1;

    // Add page attributes to post backend
    // This adds the box to set up parent and menu order on edit posts.
    add_post_type_support( 'post', 'page-attributes' );

}

/**
 * Get parent post slug
 * 
 * Helpful function to get the post name of a posts parent
 */
function get_parent_post_slug($post) {
  if (!is_object($post) || !$post->post_parent) {
    return false;
  }

  return get_post($post->post_parent)->post_name;
}

/**
 * 
 * Edit View of Permalink
 * 
 * This affects editing permalinks, and $permalink is an array [template, replacement]
 * where replacement is the post_name and template has %postname% in it.
 * 
 **/
add_filter('get_sample_permalink', function($permalink, $post_id, $title, $name, $post) {
  if ($post->post_type != 'post' || !$post->post_parent) {
    return $permalink;
  }

  // Deconstruct the permalink parts
  $template_permalink = current($permalink);
  $replacement_permalink = next($permalink);

  // Find string
  $postname_string = '/%postname%/';

  // Get parent post
  $parent_slug = get_parent_post_slug($post);

  $altered_template_with_parent_slug = '/' . $parent_slug . $postname_string;
  $new_template = str_replace($postname_string, $altered_template_with_parent_slug, $template_permalink);

  $new_permalink = [$new_template, $replacement_permalink];

  return $new_permalink;
}, 99, 5);

/**
 * Alter the link to the post
 * 
 * This affects get_permalink, the_permalink etc. 
 * This will be the target of the edit permalink link too.
 * 
 * Note: only fires on "post" post types.
 */
add_filter('post_link', function($post_link, $post, $leavename){

  if ($post->post_type != 'post' || !$post->post_parent) {
    return $post_link;
  }
  
  $parent_slug = get_parent_post_slug($post);
  $new_post_link = str_replace($post->post_name, $parent_slug . '/' . $post->post_name, $post_link);

  return $new_post_link;
}, 99, 3);

/**
 * Before getting posts
 * 
 * Has to do with routing... adjusts the main query settings
 * 
 */
add_action('pre_get_posts', function($query){
  global $wpdb, $wp_query;

  $original_query = $query;
  $uri = $_SERVER['REQUEST_URI'];

  // Do not do this post check all the time
  if ( $query->is_main_query() && !is_admin()) {

    // get the post_name
    $basename = basename($uri);
    // find out if we have a post that matches this post_name
    $test_query = sprintf("select * from $wpdb->posts where post_type = '%s' and post_name = '%s';", 'post', $basename);
    $result = $wpdb->get_results($test_query);

    // if no match, return default query, or if there's no parent post, this is not necessary
    if (!($post = current($result)) || !$post->post_parent) {
      return $original_query;
    }

    // get the parent slug
    $parent_slug = get_parent_post_slug($post);
    // concat the parent slug with the post_name to get most of the url
    $hierarchal_slug = $parent_slug . '/' . $post->post_name;

    // if the concat of parent-slug/post-name is not in the uri, this is not the right post.
    if (!stristr($uri, $hierarchal_slug)) {
      return $original_query;
    }

    // pretty high confidence that we need to override the query.
    $query->query_vars['post_type'] = ['post'];
    $query->is_home     = false; 
    $query->is_page     = true;  
    $query->is_single   = true; 
    $query->queried_object_id = $post->ID;  
    $query->set('page_id', $post->ID);

    return $query;
  }

}, 1);

您可以将其保存到custom-posts-hierarchy.php文件中,并将其包含在主题的functions.php文件中,或者您可以在顶部添加:

/*
Plugin Name: Custom Posts Hierarchy
Plugin URI:
Description: Add page attributes to posts and support hiearchichal
Author: Angela Murrell
Version:
Author URI: 
*/

然后把它放到你的插件文件夹里。祝你好运!

2hh7jdfx

2hh7jdfx4#

WordPress中的 * 帖子 * 应该是典型的按时间顺序排列的博客帖子。* 页面 * 是为静态内容制作的,它们可以按层次结构组织。
对于任何页面,您都可以选择父页面。这样,您就可以创建具有多个子页面的嵌套层次结构。听起来正是您所需要的。
查看WordPress文档了解详情。
如果你有一个很深很复杂的树结构,一个插件可以帮助你管理它,比如Wordpress Page Tree,它提供了一个比默认的WordPress页面列表更好的界面。

yduiuuwa

yduiuuwa5#

使用像CPT UI这样的插件,你可以创建一个自定义的帖子类型,并将其设置为具有层次树。
然后检查一下帖子类型page-attribute是否设置为这个自定义的帖子类型和voile,你的帖子现在有了层次结构。
https://wordpress.org/plugins/custom-post-type-ui/

fxnxkyjh

fxnxkyjh6#

最好的解决方案是创建自定义分类[1]:http://codex.wordpress.org/Function_Reference/register_taxonomy并创建主鼻涕虫-书籍或其他东西。

vybvopom

vybvopom7#

存在为post创建层次结构的插件:

    • 一个
amrnrhlw

amrnrhlw8#

这样不是更好吗

register_post_type( 'MYPOSTTYPE',
    array(
        'labels' => array(
            'name' => __( 'MYPOSTTYPE' ),
            'singular_name' => __( 'MYPOSTTYPE' )
        ),
        'supports' => array('title', 'editor', 'page-attributes'),
        'public' => true,
        'has_archive' => true,
        'hierarchical' => true,
        'rewrite' => array('slug' => 'MYPOSTTYPE'),
    )
);

我补充说:
“分层”=〉真,
而且很有效。

tf7tbtn2

tf7tbtn29#

我也在考虑给帖子增加层次结构,我通读了这个主题。我的结论是(在我看来)最好避免在帖子中添加层次结构,帖子和页面层次结构是WordPress的这样一个核心概念,以及SEO和与插件兼容性的各种问题(和WordPress核心)可以在触摸这个的时候出现,而不是实现一个复杂的技术解决方案,如果希望它能与未来的WordPress和插件更新保持兼容,那么使用类别和子类别来划分帖子层次结构似乎更好,如果这不能提供足够的灵活性,使用页面而不是帖子,因为页面也支持开箱即用的层次结构(如前面提到的)。
可能有些情况下,看起来像文章类别或页面都不能解决你的层次结构问题,但我仍然认为,你应该考虑是否要通过实现某种形式的自定义文章层次结构解决方案来为自己复杂化的事情,以及所有未来的问题,可能来自它。
虽然为一个问题提出一个技术解决方案是很诱人的,但有时最好的答案是根本不做什么,而是完全使用不同的方法。

相关问题