2026.2 Update
If it is enforced Fragmented thoughts Using the post id as the url, you can use the following code
//force talk use post id in url
add_filter('post_type_link', function ($permalink, $post) {
if ($post->post_type !== 'talk') {
return $permalink;
}
return home_url('/talk/' . $post->ID . '/');
}, 10, 2);
add_action('init', function () {
add_rewrite_rule(
'^talk/([0-9]+)/?$',
'index.php?post_type=talk&p=$matches[1]',
'top'
);
});
Text
Someone wrote about how to develop it many years ago wordpress The fragmentary thought ( link Although the code is 10 years old, it still works, and I have added the in-line comment display and reply function. Make him more like Weibo and Moments, the specific effect: https://jaketao.com/notes
The specific code sharing is as follows:
Step 1: Make a broken thought (the original broken thought production plan, slightly improved)
1.1 Create a new post type
Create a post-type.php file and put it in the root directory of your theme (if it doesn't show up in the background, under the references in functions), the content is:
<?php
add_action('init', 'my_custom_init');
function my_custom_init()
{
$labels = array(
'name' => '碎语',
'singular_name' => 'Talk',
'add_new' => '发表新碎语',
'add_new_item' => '发表新碎语',
'edit_item' => '编辑碎语',
'new_item' => '新碎语',
'view_item' => '查看碎语',
'search_items' => '搜索碎语',
'not_found' => '暂无碎语',
'not_found_in_trash' => '没有已遗弃的碎语',
'parent_item_colon' => '',
'menu_name' => '碎语'
);
$args = array(
'labels' => $labels,
'public' => true,
'publicly_queryable' => true,
'show_ui' => true,
'show_in_menu' => true,
'query_var' => true,
'rewrite' => true,
'capability_type' => 'post',
'has_archive' => true,
'hierarchical' => false,
'menu_position' => null,
'supports' => array('title','editor','author','comment')
);
register_post_type('talk',$args);
}
?>
1.2 Write a front-end page
Copy a page.php, name it page-talk.php and put it in the directory, and change the header to
<?php /* Template Name: 碎碎念 */ ?>
然后在按照你的模板修改,以下是例子,记得增加对应的css在style.css
<?php if (have_posts()) : while (have_posts()) : the_post(); ?>
<?php $limit = get_option('posts_per_page');$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;query_posts('post_type=talk&post_status=publish&showposts=' . $limit=20 . '&paged=' . $paged);if (have_posts()) : while (have_posts()) : the_post(); ?>
<div class="talklist">
<span class="talkcontent">
<?php the_content(); ?>
</span>
<span>
<p class="talktime">
<?php _e('Published by','themejunkie'); ?> <?php the_author_posts_link(); ?>
<?php the_time('Y年n月j日G:i'); ?>
</p>
</span>
</div>
<?php endwhile;endif; ?>
<?php if (function_exists('wp_pagenavi')) wp_pagenavi();else { ?><div class="talkpagenavi"><?php previous_posts_link('【« 上一页】') ?> <?php next_posts_link('【下一页 »】') ?></div><?php } ?>
<?php wp_reset_query(); ?>
1.3 Create a page in the background
Add a page to your WordPress backend – Pages – using the template you just wrote (called Broken Thoughts), so that the first step is basically complete.
If the page style does not match what you want, you can modify the page-talk page yourself
Step 2: Add page comments and likes
If you need to implement pages like Moments and Weibo to read comments, you need to make the following modifications:
2.1 Modification functions.php
You can add it directly, or create a new functions-talk.php (remember the quote)
// ==================================================
// AJAX:拉取评论
// ==================================================
add_action('wp_ajax_load_post_comments', 'load_post_comments_ajax');
add_action('wp_ajax_nopriv_load_post_comments', 'load_post_comments_ajax');
function load_post_comments_ajax() {
$post_id = intval($_POST['post_id'] ?? 0);
if (!$post_id) {
wp_send_json_error('post_id missing');
}
$comments = get_comments([
'post_id' => $post_id,
'status' => 'approve',
'orderby' => 'comment_date',
'order' => 'ASC',
]);
$data = [];
foreach ($comments as $c) {
$data[] = [
'id' => $c->comment_ID,
'parent' => $c->comment_parent,
'author' => $c->comment_author,
'content' => wpautop($c->comment_content),
'date' => $c->comment_date,
'post_id' => $c->comment_post_ID,
'user_id' => $c->user_id ?? 0,
'avatar' => get_avatar_url($c->user_id ?? 0, ['size' => 60]),
'user_url' => $c->comment_author_url ?: '',
'parent_author' => $c->comment_parent
? get_comment($c->comment_parent)->comment_author
: '',
'parent_user_id' => $c->comment_parent
? get_comment($c->comment_parent)->user_id
: 0,
'parent_url' => $c->comment_parent
? get_comment_link($c->comment_parent)
: '',
'children' => [],
];
}
// 构建嵌套评论树
$nest_comments = function (array $comments) {
$tree = [];
$map = [];
foreach ($comments as &$c) {
$map[$c['id']] = &$c;
$c['children'] = [];
}
foreach ($comments as &$c) {
if ($c['parent'] && isset($map[$c['parent']])) {
$map[$c['parent']]['children'][] = &$c;
} else {
$tree[] = &$c;
}
}
return $tree;
};
wp_send_json_success($nest_comments($data));
}
// ==================================================
// AJAX:加载评论表单
// ==================================================
add_action('wp_ajax_load_comment_form', 'load_comment_form_ajax');
add_action('wp_ajax_nopriv_load_comment_form', 'load_comment_form_ajax');
function load_comment_form_ajax() {
$post_id = intval($_POST['post_id'] ?? 0);
if (!$post_id) {
wp_send_json_error();
}
ob_start();
comment_form([
'title_reply' => '发表回复',
'comment_notes_before' => '',
'comment_notes_after' => '',
'logged_in_as' => '',
'label_submit' => '提交',
'id_form' => 'commentform',
'class_form' => 'comment-form',
'comment_field' => '
<div class="comment-form-comment">
<textarea
id="comment"
name="comment"
class="required"
rows="4"
placeholder="写下你的评论…"
required
></textarea>
<div class="comment-form-smile j-smilies" data-target="#comment">
<i class="wpcom-icon wi smile-icon">
<svg aria-hidden="true">
<use xlink:href="#wi-emotion"></use>
</svg>
</i>
</div>
</div>
',
], $post_id);
$form_html = ob_get_clean();
// 移除最外层 #respond(如存在)
$form_html = preg_replace(
'/<div id="respond" class="comment-respond">|<\/div>$/',
'',
$form_html
);
wp_send_json_success($form_html);
}
// ==================================================
// AJAX:提交评论
// ==================================================
add_action('wp_ajax_submit_comment', 'submit_comment_ajax');
add_action('wp_ajax_nopriv_submit_comment', 'submit_comment_ajax');
function submit_comment_ajax() {
if (!is_user_logged_in()) {
wp_send_json_error('need_login');
}
$user = wp_get_current_user();
$commentdata = [
'comment_post_ID' => intval($_POST['post_id']),
'comment_content' => trim($_POST['content']),
'comment_parent' => intval($_POST['parent']),
'user_id' => $user->ID,
'comment_author' => $user->display_name,
'comment_author_email' => $user->user_email,
'comment_author_url' => $user->user_url,
];
$comment_id = wp_new_comment($commentdata);
if (!$comment_id) {
wp_send_json_error('insert_failed');
}
wp_send_json_success([
'comment_id' => $comment_id,
]);
}
// ==================================================
// 前端脚本注册(仅碎碎念列表页)
// ==================================================
add_action('wp_enqueue_scripts', 'enqueue_post_comments_js');
function enqueue_post_comments_js() {
if (!is_page(9890)) {
return;
}
wp_enqueue_script(
'post-comments',
get_stylesheet_directory_uri() . '/js/post-comments.js',
['jquery'],
null,
true
);
wp_localize_script(
'post-comments',
'ajaxurl',
admin_url('admin-ajax.php')
);
}
// ==================================================
// 自定义提交按钮外观(仅碎碎念页)
// ==================================================
add_filter('comment_form_submit_field', function ($submit_field) {
if (!is_page(9890)) {
return $submit_field;
}
preg_match_all('/<input type="hidden".*?>/i', $submit_field, $matches);
$hidden = implode("\n", $matches[0]);
if (is_user_logged_in()) {
$user = wp_get_current_user();
$avatar = get_avatar($user->ID, 60);
$name = esc_html($user->display_name);
} else {
$avatar = '';
$name = '';
}
return '
<div class="form-submit">
<div class="pull-left form-submit-text">
' . $avatar . '
<span>' . $name . '</span>
</div>
<button
name="submit"
type="submit"
id="submit"
class="wpcom-btn btn-primary btn-xs submit"
>
提交
</button>
' . $hidden . '
</div>';
}, 20);
Here I directly use AJAX to recreate a comment area and force you to log in to post back, if you want to use the original ecology directly, you can modify it yourself. In addition, I directly used WPCOM's CSS, and if you need to modify it yourself, you can change the class and CSS files
2.2 Add post-comments.js files
My path is js/post-commnents.js, and I need to modify it myself
jQuery(function ($) {
/* ==================================================
* 展开 / 加载评论
* ================================================== */
$('.toggle-comments').on('click', function () {
const postId = $(this).data('post-id');
const box = $('#comment-box-' + postId);
const list = box.find('.comments-list');
// 已加载过:仅切换显示
if (box.data('loaded')) {
box.toggle();
return;
}
$.post(ajaxurl, {
action: 'load_post_comments',
post_id: postId
}, function (res) {
if (!res.success) return;
// 最新评论在前
const sortedComments = res.data.sort(
(a, b) => new Date(b.date) - new Date(a.date)
);
list.html(renderCommentsNested(sortedComments));
box.show().data('loaded', true);
// 更新评论数量
box.find('.comments-title')
.text(`评论列表(${res.data.length}条)`);
// 仅加载一次评论表单
loadCommentForm(postId, box);
});
});
/* ==================================================
* AJAX 加载评论表单
* ================================================== */
function loadCommentForm(postId, box) {
const respond = box.find('#respond');
if (respond.data('loaded')) return;
$.post(ajaxurl, {
action: 'load_comment_form',
post_id: postId
}, function (res) {
if (!res.success) return;
respond.html(res.data);
const form = respond.find('#commentform');
if (!form.length) return;
// comment_post_ID
if (!form.find('input[name="comment_post_ID"]').length) {
form.append(
`<input type="hidden" name="comment_post_ID" value="${postId}">`
);
} else {
form.find('input[name="comment_post_ID"]').val(postId);
}
// comment_parent
if (!form.find('input[name="comment_parent"]').length) {
form.append(
`<input type="hidden" name="comment_parent" value="0">`
);
} else {
form.find('input[name="comment_parent"]').val(0);
}
respond.data('loaded', true);
});
}
/* ==================================================
* 渲染嵌套评论(不滚动)
* ================================================== */
function renderCommentsNested(comments, parentId = 0, depth = 1) {
let html = '';
comments
.filter(c => c.parent == parentId)
.forEach((c, index) => {
const isEven = index % 2 === 0;
const classes = [
'comment',
depth > 1 ? '' : (isEven ? 'even' : 'odd'),
c.children && c.children.length ? 'parent' : '',
'depth-' + depth
].join(' ').trim();
html += `
<li class="${classes}" id="comment-${c.id}">
<div id="div-comment-${c.id}" class="comment-inner">
<div class="comment-author vcard">
<img
alt="${c.author}的头像"
src="${c.avatar}"
class="avatar avatar-60 photo"
height="60"
width="60"
>
</div>
<div class="comment-body">
<div class="nickname">
${
c.user_url
? `<a href="https://jaketao.com/${c.user_url}" class="url j-user-card" data-user="${c.user_id}" target="_blank" rel="ugc">${c.author}</a>`
: c.author
}
<span class="comment-time">${c.date}</span>
</div>
<div class="comment-text">
${
c.parent_author
? `<span class="comment-text-reply">
<a class="j-user-card" data-user="${c.parent_user_id}" href="https://jaketao.com/${c.parent_url}" target="_blank">
@${c.parent_author}
</a>:
</span>`
: ''
}
${c.content}
</div>
</div>
<div class="reply">
<a
rel="nofollow"
class="comment-reply-link"
href="https://jaketao.com/javascript:;"
data-commentid="${c.id}"
data-postid="${c.post_id}"
data-belowelement="div-comment-${c.id}"
data-respondelement="respond"
data-replyto="回复给 ${c.author}"
aria-label="回复给 ${c.author}"
>
<i class="wpcom-icon wi">
<svg aria-hidden="true">
<use xlink:href="#wi-comment-fill"></use>
</svg>
</i>
<span>回复</span>
</a>
</div>
</div>
${
c.children && c.children.length
? `<ul class="comment-children">
${renderCommentsNested(c.children, c.id, depth + 1)}
</ul>`
: ''
}
</li>`;
});
return html;
}
/* ==================================================
* 提交评论(AJAX)
* ================================================== */
$(document).on('submit', '#commentform', function (e) {
e.preventDefault();
const form = $(this);
const postId = form.find('input[name="comment_post_ID"]').val();
const parent = form.find('input[name="comment_parent"]').val() || 0;
const content = form.find('#comment').val().trim();
if (!content) return;
const subscribe = form.find('#cren_subscribe_to_comment').is(':checked') ? 'on' : '';
$.post(ajaxurl, {
action: 'submit_comment',
post_id: postId,
parent: parent,
content: content,
author: form.find('#author').val(),
email: form.find('#email').val(),
cren_subscribe_to_comment: subscribe
}, function (res) {
if (!res.success) {
if (res === 'need_login') {
alert('请先登录后评论');
location.href = '/wp-login.php';
}
return;
}
// 重置表单
form[0].reset();
form.find('input[name="comment_parent"]').val(0);
// 重新加载评论
$.post(ajaxurl, {
action: 'load_post_comments',
post_id: postId
}, function (res2) {
if (!res2.success) return;
const sortedComments = res2.data.sort(
(a, b) => new Date(b.date) - new Date(a.date)
);
const box = $('#comment-box-' + postId);
box.find('.comments-list')
.html(renderCommentsNested(sortedComments));
box.find('.comments-title')
.text(`评论列表(${res2.data.length}条)`);
});
// 取消回复,回到顶部
$('#cancel-comment-reply-link').trigger('click');
});
});
/* ==================================================
* 点击“回复”
* ================================================== */
$(document).on('click', '.comment-reply-link', function (e) {
e.preventDefault();
const parentId = $(this).data('commentid');
const box = $(this).closest('.entry-comments');
const respond = box.find('#respond');
const target = $('#div-comment-' + parentId);
// 移动表单到目标评论下
respond.appendTo(target);
respond.find('input[name="comment_parent"]').val(parentId);
respond.find('#comment').focus();
$('#cancel-comment-reply-link').show();
});
/* ==================================================
* 取消回复(回到顶部)
* ================================================== */
$(document).on('click', '#cancel-comment-reply-link', function (e) {
e.preventDefault();
const respond = $('#respond');
const box = respond.closest('.entry-comments');
respond.find('input[name="comment_parent"]').val(0);
box.prepend(respond);
$(this).hide();
});
});
2.3 Automatically add titles to fragments (optional)
Because the fragment only has the content body of the article, the title will be unnamed, which is not very elegant, so the code here directly takes the content body as the title.
add_action('save_post_talk', 'talk_generate_title_after_save', 20, 3);
function talk_generate_title_after_save($post_id, $post, $update) {
// 1. 排除自动保存 / 修订版本
if (wp_is_post_autosave($post_id) || wp_is_post_revision($post_id)) {
return;
}
// 2. 只在 publish / future / draft 时处理(避免 auto-draft 干扰)
if (!in_array($post->post_status, ['publish', 'future', 'draft'], true)) {
return;
}
// 3. 如果已经有有效标题,则不处理
if (!empty($post->post_title) && $post->post_title !== '自动草稿') {
return;
}
// 4. 取内容生成标题
$content = trim(wp_strip_all_tags($post->post_content));
if (!empty($content)) {
$new_title = wp_trim_words($content, 10, '…');
} else {
$new_title = '碎语';
}
// 5. 防止递归触发
remove_action('save_post_talk', 'talk_generate_title_after_save', 20);
wp_update_post([
'ID' => $post_id,
'post_title' => $new_title,
]);
add_action('save_post_talk', 'talk_generate_title_after_save', 20, 3);
}
This is done, but there should be some problems, and the front-end formatting problem is directly changed to css and classname. The effect is as follows (test: https://jaketao.com/notes)

This site Original article All followed" Attribution—NonCommercial—ShareAlike 4.0 (CC BY-NC-SA 4.0) ”。 Please keep the following marks for sharing and interpretation:
Original author: Jake Tao Source: "WordPress Fragmentary Thoughts/Moments/Weibo Add Comment Function"
Post a reply