WordPress创建自定义文章类型 CPT (custom post type)

注册自定义文章类型,代码如下:

add_action('init', 'my_custom_post_product');
function my_custom_post_product() {
    $labels = array(
        'name'               => _x('产品中心', 'post type 名称'),
        'singular_name'      => _x('产品', 'post type 单个 item 时的名称,因为英文有复数'),
        'add_new'            => _x('添加产品', '添加新内容的链接名称'),
        'add_new_item'       => __('添加新产品'),
        'edit_item'          => __('编辑产品'),
        'new_item'           => __('新产品'),
        'all_items'          => __('产品列表'),
        'view_item'          => __('查看产品'),
        'search_items'       => __('搜索产品'),
        'not_found'          => __('没有找到有关产品'),
        'not_found_in_trash' => __('回收站里面没有相关产品'),
        'parent_item_colon'  => '',
        'menu_name'          => '产品管理'
    );

    $args = array(
        'labels'        => $labels,
        'description'   => '我们网站的产品信息',
        'public'        => true,
        'menu_position' => 5,
        'menu_icon'     => 'dashicons-money-alt',
        // 支持的功能,还可以添加:'excerpt', ,  'comments'
        'supports'      => array('title', 'editor', 'thumbnail'),
        /*这个设置为true,
        才能在前台 single-[post_type].php 和 archive-[post_type].php 显示列表*/
        'has_archive'   => true

    );
    // 注册文章类型,第一个参数为类型名称,即post type name
    register_post_type('product', $args);
}

为新注册的类型,添加分类功能,代码如下:

/**
 * 为产品 post type 添加分类功能
 */
add_action('init', 'my_taxonomies_product', 0);
function my_taxonomies_product() {
    $labels = array(
        'name'              => _x('产品分类', 'taxonomy 名称'),
        'singular_name'     => _x('产品分类', 'taxonomy 单数名称'),
        'search_items'      => __('搜索产品分类'),
        'all_items'         => __('所有产品分类'),
        'parent_item'       => __('该产品分类的上级分类'),
        'parent_item_colon' => __('该产品分类的上级分类:'),
        'edit_item'         => __('编辑产品分类'),
        'update_item'       => __('更新产品分类'),
        'add_new_item'      => __('添加新的产品分类'),
        'new_item_name'     => __('新产品分类'),
        'menu_name'         => __('产品分类'),
    );

    $args = array(
        'labels' => $labels,
        'hierarchical' => true,
    );
    /** 注册分类,第一个参数为分类法的名字,即taxonomy
    第二个参数为该分类属于哪个文章类型 */
    register_taxonomy('product_category', 'product', $args);
}


为新注册的文章类型添加额外的输入框,即 meta box

/**
 * 为产品发布类型 添加自定义 Meta Box
 * 功能特征 meta box
 */
add_action('add_meta_boxes', 'product_gongneng');
function product_gongneng() {
    // add_meta_box( $id, $title, $callback, $post_type, $context,$priority, $callback_args );
    add_meta_box(
        'product_gongneng',                 // id
        '功能特征',                          // title        
        'product_gongneng_meta_box',        // callback
        'product',                          // post_type
        'normal',                           // context
        'low'                               // priority
    );
}

/**
 * 为meta box 添加html表单
 */
function product_gongneng_meta_box($post) {
    // 创建临时隐藏表单,为了安全
    wp_nonce_field('product_gongneng_meta_box', 'product_gongneng_meta_box_nonce');

    // 获取之前存储的值
    $field_value = get_post_meta($post->ID, '_product_gongneng', false);
?>
    <p>
        <label for="_product_gongneng"></label>
        <?php
        $settings = array(
            'quicktags' => array('buttons' => 'em,strong,link',),
            'quicktags' => true,
            'tinymce' => true,
            'editor_height' => 100, // In pixels, takes precedence and has no default value
            'textarea_rows' => 20,  // Has no visible effect if editor_height is set, default is 20
        );

        wp_editor(html_entity_decode($field_value[0]), '_product_gongneng', $settings);
        ?>
    </p>
<?php

}


// 保存meta_box
add_action('save_post', 'product_gongneng_save_meta_box');
function product_gongneng_save_meta_box($post_id) {
    // 安全检查
    // 检查是否发送了一次性隐藏表单内容(判断是否为第三者模拟提交)
    if (!isset($_POST['product_gongneng_meta_box_nonce'])) {
        echo 'a11111';
        exit();
        return;
    }

    // 判断隐藏表单的值与之前是否相同
    if (!wp_verify_nonce($_POST['product_gongneng_meta_box_nonce'], 'product_gongneng_meta_box')) {
        echo '222';
        exit();
        return;
    }

    // 判断该用户是否有权限
    if (!current_user_can('edit_post', $post_id)) {
        echo '333';
        exit();
        return;
    }


    // 判断 Meta Box 是否为空
    if (!isset($_POST['_product_gongneng'])) {
        echo '444';
        exit();
        return;
    }

    // 使用 wpautop 函数,是因为表单中 使用了富文本编辑器,要对文本进行处理
    $gongeng = htmlentities(wpautop($_POST['_product_gongneng']));
    $_product_gongneng = sanitize_text_field($gongeng);
    // 把字段值保存到数据库
    update_post_meta($post_id, '_product_gongneng', $_product_gongneng);
}

查看Debian开机启动项

查看所有启用的服务:

systemctl list-unit-files --type=service

该命令会列出所有服务的启动状态,其中标记为 enabled 的服务会在开机时自动启动。

查看当前正在运行的服务:

systemctl list-units --type=service

这个命令会列出当前正在运行的服务,已启动的服务会标记为 running。

systemctl list-unit-files --type=service 输出 列表太长,如果不想看整个列表,只想简单地查看启用的服务,可以运行以下命令:

systemctl list-unit-files --type=service | grep enabled

这个命令会列出所有启用(enabled)的服务,只有那些会在系统启动时自动启动的服务会被显示。

查看当前运行的服务

systemctl list-units --type=service --state=running

这个命令会显示当前正在运行的服务,但它不会直接列出所有已配置为开机启动的服务。它只会列出系统启动后当前处于运行状态的服务。

检查特定服务是否设置为开机启动

systemctl is-enabled <service-name>

例如,要查看 ssh 服务是否在开机时启动:

systemctl is-enabled ssh

如果返回 enabled,则表示该服务已配置为开机启动。

使用 grep 筛选开机启动的服务(更简洁的命令)

systemctl list-unit-files --type=service | awk '$2=="enabled" {print $1}'

这个命令会只输出那些标记为 enabled 的服务名称,避免显示其他无关的服务信息。

最后,也可以查看/etc/init.d/目录(SysVinit 脚本,这个适合于老旧的系统,新系统中也会有这个目录,但不太推荐使用了)

ls /etc/init.d/

查看Debian内核版本

查看已安装的内核列表:

dpkg --list | grep linux-image

查看当前使用中的内核版本:

uname -r

如果有新内核,需要重启系统,重新启动后,会自动使用最新版本的内核。

最好不要折腾内核,稳定性第一!

查看kexec是否安装 :

dpkg -l | grep kexec-tools

安装 :

apt install kexec-tools

正常来说不需要这个东西,感觉没什么用,都要重启了,也不差那几秒。所以说,更新的时候如果有新内核,提示是否使用kexec,那么选No就行了,正常重启即可。

更新laravel安装程序

如果你使用laravel installer来安装框架,那么当需要更新laravel installer时可以执行以下命令:

composer global remove laravel/installer
composer global require laravel/installer

你大概看出来了,对!就是卸载然后重装,就是这么简单又暴力,喜欢吗?

laravel 前后台分别登录,互不影响

该标题的意思即:Laravel 中的多重身份验证,简化了一下标题,让人能看懂。

在 Laravel 中,“多重身份验证”(也称为“多重保护身份验证”)是指在单个应用程序中管理多个用户身份验证系统的能力。当您有不同类型的用户(例如普通用户和管理员)且每个用户都有自己的身份验证要求和用户模型时,这非常有用。

要在 Laravel 中实现多重身份验证,您通常需要遵循以下步骤:

第 1 步:创建多个用户模型:

为要验证的每种类型的用户创建单独的用户模型。例如,您可能有一个User针对普通用户的模型和一个Admin针对管理员的模型。您可以使用以下artisan命令生成这些模型:

php artisan make:model User  
php artisan make:model Admin

注意:这一步可以省略,完全可以都用User表。

步骤 2:配置身份验证防护:

在config/auth.php文件中,定义多个防护(guard),每个防护与一个用户模型关联。Laravel 允许您为每个守卫配置不同的身份验证驱动程序。例如,您可以将“web”防护用于具有基于会话的身份验证的普通用户,将“admin”防护用于具有基于会话或基于令牌的身份验证的管理员。

下面是一个简化的文件示例config/auth.php:

'guards' => [  
	'web' => [  
		'driver' => 'session',  
		'provider' => 'users',  
	],  
  
	'admin' => [  
		'driver' => 'session',  
		'provider' => 'admins',  
	],  
],

第 3 步:定义身份验证提供程序:

为每个用户模型配置身份验证提供程序。提供者决定 Laravel 应在何处检索用户记录。在同一config/auth.php文件中,为指定相应 Eloquent 模型的“users”和“admins”定义提供程序:

'providers' => [  
	'users' => [  
		'driver' => 'eloquent',  
		'model' => App\Models\User::class,  
	],  
	  
	'admins' => [  
		'driver' => 'eloquent',  
		'model' => App\Models\Admin::class,  
	],  
],

第 4 步:实施身份验证逻辑:

在你的应用程序中,根据所选的防护实现身份验证逻辑。你可以使用auth()辅助方法来访问所需的防护:

// Authenticate a regular user  
if (auth()->guard('web')->attempt(['email' => $email, 'password' => $password])) {  
	// User is logged in  
}  
  
// Authenticate an administrator  
if (auth()->guard('admin')->attempt(['email' => $email, 'password' => $password])) {  
	// Admin is logged in  
}

第 5 步:保护路由:

使用中间件根据所选的防护来保护路由。例如,您可以应用“auth:web”中间件来保护普通用户的路由,使用“auth:admin”中间件来保护管理员的路由:

Route::middleware(['auth:web'])->group(function () {  
	// Routes accessible to regular users  
});  
  
Route::middleware(['auth:admin'])->group(function () {  
	// Routes accessible to administrators  
});

第 6 步:注销:

要注销用户,可以logout在相应的守卫上使用该方法:

auth()->guard('web')->logout(); // Log out a regular user  
auth()->guard('admin')->logout(); // Log out an administrator 

结论:

这就是 Laravel 中实现多重身份验证的基本流程。你可以创建多个用户模型(或者只用User模型),配置防护和提供程序,实施身份验证逻辑,并根据所选防护保护路由。这允许你在单个 Laravel 应用程序中使用自己的身份验证系统来管理不同类型的用户。

参考文章:

https://sagardhiman021.medium.com/exploring-multi-authentication-in-laravel-a-step-by-step-guide-to-implementation-edd3bf304fce

laravel 使用 layui 分页样式

把以下代码放在 views/vendor/pagination/layui.blade.php里,这个路径是使用 php artisan vendor:publish --tag=laravel-pagination 发布出来的:

<div class="layui-box layui-laypage layui-laypage-default">  
  
    {{-- Previous Page Link --}}  
    @if ($paginator->onFirstPage())  
        <a class="layui-laypage-prev layui-disabled">上一页</a>  
  
    @else  
        <a class="layui-laypage-prev" href="{{ $paginator->previousPageUrl() }}">上一页</a>  
  
    @endif  
  
  
    {{-- Pagination Elements --}}  
    @foreach ($elements as $element)  
        {{-- Array Of Links --}}  
        @if (is_array($element))  
            @foreach ($element as $page => $url)  
                @if ($page == $paginator->currentPage())  
                    <span class="layui-laypage-curr"><em class="layui-laypage-em"></em><em>{{ $page }}</em></span>  
                @else  
                    <a href="{{ $url }}">{{ $page }}</a>  
                @endif  
            @endforeach        @endif    @endforeach  
    {{-- Next Page Link --}}  
    @if ($paginator->hasMorePages())  
        <a class="layui-laypage-next" href="{{ $paginator->nextPageUrl() }}">下一页</a>  
    @else  
        <a class="layui-laypage-next  layui-disabled" href="{{ $paginator->nextPageUrl() }}">下一页</a>  
    @endif  
  
  
</div>

使用:

<div style="text-align: center">  
    {{ $rooms->links('vendor.pagination.layui') }}  
</div>

补充一个Layui2.9.x的样式:

<div class="layui-box layui-laypage layui-laypage-default">  
  
    {{-- Previous Page Link --}}  
    @if ($paginator->onFirstPage())  
        <a class="layui-laypage-prev layui-disabled">上一页</a>  
  
    @else  
        <a class="layui-laypage-prev" href="{{ $paginator->previousPageUrl() }}">上一页</a>  
  
    @endif  
  
  
    {{-- Pagination Elements --}}  
    @foreach ($elements as $element)  
        {{-- Array Of Links --}}  
        @if (is_array($element))  
            @foreach ($element as $page => $url)  
                @if ($page == $paginator->currentPage())  
                    <span class="layui-laypage-curr"><em class="layui-laypage-em"></em><em>{{ $page }}</em></span>  
                @else  
                    <a href="{{ $url }}">{{ $page }}</a>  
                @endif  
            @endforeach        @endif    @endforeach  
    {{-- Next Page Link --}}  
    @if ($paginator->hasMorePages())  
        <a class="layui-laypage-next" href="{{ $paginator->nextPageUrl() }}">下一页</a>  
    @else  
        <a class="layui-laypage-next  layui-disabled" href="{{ $paginator->nextPageUrl() }}">下一页</a>  
    @endif  
  
  
</div>

laravel api resource 返回数组

不解释了,有需要的人会懂。

<?php

namespace App\Http\Resources;

use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\ResourceCollection;

class GuestbookCollection extends ResourceCollection
{
    /**
     * Transform the resource collection into an array.
     *
     * @return array<int|string, mixed>
     */
    public function toArray(Request $request): array
    {
        return $this->collection->map(function ($item){
            return [
                'username' => $item->user->username,
                'content' => $item->content,
                'created_at' => $item->created_at->format('Y-m-d H:i:s'),
                'reply_content' => $item->reply->content,
                'id' => $item->id,

            ];
        })->toArray();
    }
}

从laravel 中删除 personal_access_tokens 表

这个表是laravel/sanctum这个包带的,Laravel Sanctum 是 Laravel 官方推出的一个轻量级的身份验证系统,专门用于为单页应用(SPA)、移动应用以及简单的 token-based API 提供身份验证解决方案,它提供了一种简洁且安全的方式来处理用户身份验证。

如果不需要,当然可以删除,执行下面的命令把它干掉:

composer remove laravel/sanctum