EP090. “My Notes 页面、Note 文章类型与笔记列表”
🔒 登录后可标记已读开始做「My Notes」功能:登录用户可以在前台创建、编辑、删除自己的私人课堂笔记。这是练习 CRUD 里剩下三个操作(Create/Update/Delete,之前只学过 Read)的实战项目。这一讲先完成基础骨架:新建 note 自定义文章类型(设成 public => false,不公开、不出现在搜索结果里,只有本人能看到)、新建 /my-notes 页面并加上未登录自动跳转首页的保护、以及查询并列出当前用户自己的笔记(每条笔记先渲染成输入框+文本域,附带编辑/删除按钮,但按钮暂时还没接后端逻辑)。
涉及文件
wp-content/mu-plugins/university-post-types.php(修改,新增note文章类型)wp-content/themes/fictional-university-theme/page-my-notes.php(新建)wp-content/themes/fictional-university-theme/header.php(修改)- 后台新建页面「My Notes」(slug:
my-notes,后台操作,无对应代码文件) - 后台手动新建两条 Note 测试数据(后台操作,无对应代码文件)
代码实现
mu-plugins/university-post-types.php:新增 note 文章类型(复制 professor 类型改造):
// wp-content/mu-plugins/university-post-types.php
// note post type
register_post_type('note', array(
'show_in_rest' => true,
'supports' => array('title', 'editor'),
'public' => false,
'show_ui' => true,
'labels' => array(
'name' => 'Notes',
'add_new_item' => 'Add New Note',
'edit_item' => 'Edit Note',
'all_items' => 'All Notes',
'singular_name' => 'Note'
),
'menu_icon' => 'dashicons-welcome-write-blog'
));
page-my-notes.php(新建,复制自 page.php 精简改造):
<?php
if (!is_user_logged_in()) {
wp_redirect(esc_url(site_url('/')));
exit;
}
get_header();
while(have_posts()) {
the_post();
pageBanner();
?>
<div class="container container--narrow page-section">
<ul class="min-list link-list" id="my-notes">
<?php
$userNotes = new WP_Query(array(
'post_type' => 'note',
'posts_per_page' => -1,
'author' => get_current_user_id()
));
while($userNotes->have_posts()) {
$userNotes->the_post(); ?>
<li>
<input class="note-title-field" value="<?php echo esc_attr(get_the_title()); ?>">
<span class="edit-note"><i class="fa fa-pencil" aria-hidden="true"></i> Edit</span>
<span class="delete-note"><i class="fa fa-trash-o" aria-hidden="true"></i> Delete</span>
<textarea class="note-body-field"><?php echo esc_attr(wp_strip_all_tags(get_the_content())); ?></textarea>
</li>
<?php }
?>
</ul>
</div>
<?php }
get_footer();
?>
header.php:登录用户在 Log Out 按钮左侧新增 My Notes 入口:
<a href="<?php echo esc_url(site_url('/my-notes')); ?>" class="btn btn--small btn--orange float-left push-right">My Notes</a>
关键改动点:
public => false让note文章类型不会出现在前台查询、搜索结果、Sitemap 里(笔记是私人内容,不该被任何人看到),但这样做的副作用是后台管理菜单也会一并被隐藏——所以要另外加一行show_ui => true把后台管理界面单独找回来,两者互不冲突page-my-notes.php顶部在get_header()之前就先判断!is_user_logged_in(),未登录直接wp_redirect()+exit弹回首页——放在最前面是因为要在任何 HTML 输出之前完成重定向,一旦有内容输出过,wp_redirect()会失败- 笔记查询用
'author' => get_current_user_id(),这是保证「只看到自己笔记」的关键条件——没有这行的话会查出全站所有用户的笔记 'posts_per_page' => -1表示不分页、一次性拿全部结果,因为笔记通常数量不多,不需要分页- 标题用
<input value="...">而不是纯文本显示,是因为这个界面设计成「直接内联编辑」——用户点编辑按钮后可以直接在这个输入框/文本域里修改内容,不需要跳转到单独的编辑页 - 输出到 HTML 属性(
value="...")的数据库内容要用esc_attr()转义(不是esc_html()),这是 WordPress 里「输出到属性」和「输出到正文」两种不同转义函数的用法区别 - 笔记正文用
wp_strip_all_tags(get_the_content())先去掉 HTML 标签和 WordPress 注释(编辑器存正文时会带一些<p>标签和内部注释),这样塞进<textarea>里才是纯文字,不会把标签原样显示出来
[截图:前台 /my-notes 页面,登录用户看到自己的笔记列表,每条笔记带 Edit/Delete 按钮]
Hook / Function 速查
| 名称 | 类型 | 用途 |
|---|---|---|
public(register_post_type 参数) | WP 内建注册参数 | 控制文章类型是否在前台可查询/可搜索/出现在 Sitemap |
show_ui(register_post_type 参数) | WP 内建注册参数 | 独立控制后台管理界面菜单是否显示,可以跟 public 分开设置 |
esc_attr() | WP 内建 function | 转义字符串,用于输出到 HTML 属性值 |
wp_strip_all_tags() | WP 内建 function | 去除字符串里的全部 HTML 标签 |
常见坑
- 只设置
public => false却不加show_ui => true——这样后台管理菜单也会一起消失,连管理员自己都找不到手动新建/管理笔记的入口 - WP_Query 忘记加
author条件——不加的话会查出全站所有用户的笔记,而不是当前登录用户自己的
延伸 / 后续讲座会用到
现在编辑/删除按钮点击后还没有任何反应,下一讲开始接入 REST API,让创建/编辑/删除笔记真正生效。
Sources
Udemy:
- Become a WordPress Developer: Unlocking Power With Code — Section 19, EP090