WP DEVELOP

EP090. “My Notes 页面、Note 文章类型与笔记列表”

首页 WordPress 开发课程 MY NOTES 前端功能 · EP090
约 13 分钟· #EP090#MY NOTES 前端功能
🔒 登录后可标记已读

开始做「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 => falsenote 文章类型不会出现在前台查询、搜索结果、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 速查

名称类型用途
publicregister_post_type 参数)WP 内建注册参数控制文章类型是否在前台可查询/可搜索/出现在 Sitemap
show_uiregister_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