分类
WordPress

博客升级到 PHP8.1

由于 php7.4 马上结束维护了,所以把博客服务器 PHP 版本做了个升级,直接升级到当前的最新稳定版 PHP8.1。

当前 PHP 各版本维护周期

PHP8.1 的安装命令如下:

apt install php8.1-fpm php8.1-mysql php8.1-mbstring php8.1-curl php8.1-xml php8.1-imagick php8.1-zip php8.1-gd php8.1-intl php8.1-bcmath

安装完成后,顺便开启了 PHP8.1 的 JIT,以提高性能,开启方法如下:

编辑 php.ini,在 opcache 配置部分添加加粗的两行:

[opcache]
; Determines if Zend OPCache is enabled
opcache.enable=1
opcache.jit=tracing
opcache.jit_buffer_size=50M

保存后记得重启 php8.1-fpm。最后通过 phpinfo()查看效果:

PHP8.1 开启 JIT 成功

参考链接:https://stitcher.io/blog/php-8-jit-setup

分类
WordPress

wordpress 网站根目录权限设置

网站文件权限设置,在网站根目录下执行

for directories

find . -type d -print0 | xargs -0 chmod 0755

for files

find . -type f -print0 | xargs -0 chmod 0644

for wp-config.php

chmod 600 wp-config.php

如果wordpress站点健康检查提示无法自动更新,则执行下面这两句,把当前文件夹以及所有文件加入php-fpm用户组

chown -R www-data:www-data *
chown -R www-data:www-data .

www-data 是 debian/ubuntu 系统的 php-fpm 默认用户名。

分类
WordPress

wordpress custom post type 的 category 页面的模板文件命名规则

在使用自定义文章类型时,对应的 category 页面的文件名应该是taxonomy-{taxonomy}.php

例如有一个自定义 Post Type 的分类法是 product_category,那么该分类法对应的 category 页面的模板文件名就是taxonomy-product_category.php

如果该分类法下有一个分类,名为adva,那么该分类对应的模板文件名为taxonomy-product_category-adva.php


如果是默认的文章类型,即 post type 是 post ,它的 category 页面的名字就是category.php,默认的分类法其实就是category,但却不能写成taxonomy-category,只能自定义类型才能这么写。

如果默认分类法下有一个news的分类,那么对应的模板文件名就是category-news.php

分类
WordPress

wordpress category 和 archive 的区别

一个post type可以没有分类(category),但一定可以进行文章归档(archive)。

分类(category),是针对分类法(taxonomy)的,而归档而是针对文章的。

所以,模板命名上,category 总是和分类关联,比如news分类模板:category-news.php。

而 archive 总是和 post type 关联,比如有一个 custom post type 名字是 product,那么对应的归档页面就是 archive-product.php。

分类
WordPress

wordpress 实现文件下载功能

本想这个功能应该不难,但却费了好些工夫。

在wordpress中想要实现点击下载,有两种方法:

 1、在下载链接上增加download=""属性

<a href="<?php echo $download_url; ?>" download="">下载</a>

但是这种方法查资料发现,只支持chrome和firefox,兼容性不好。

2、第二种方法也是费了好大劲才查找到的资料,直接上代码

<?php
// add the download ID query var which we'll set in the rewrite rule
function wpd_query_var($query_vars) {
    $query_vars[] = 'download_id';
    return $query_vars;
}
add_filter('query_vars', 'wpd_query_var');

// add rewrite rule
function wpd_rewrite() {
    add_rewrite_rule(
        'download/([0-9]+)/?$',
        'index.php?download_id=$matches[1]',
        'top'
    );
}
add_action('init', 'wpd_rewrite');

// check for download_id and output the file
function wpd_request($wp) {
    if (array_key_exists('download_id', $wp->query_vars)) {
        // 在此实现下载代码的书写
        // output your headers and file here
        // ID is in $wp->query_vars['download_id']
        // then exit to halt any further execution
        $download_id = $wp->query_vars['download_id'];
        $filename =  get_attached_file($download_id);
        if (file_exists($filename)) {
            include get_template_directory() . '/inc/download.php';
            downloadFile($filename);
        } else {
            wp_die(__('要下载的文件不存在!'));
        }
    }
}
add_action('parse_query', 'wpd_request');

下载时,引用了一个inc目录下的download.php,代码如下:

<?php
/**
 * @param $filePath //下载文件的路径
 * @param int $readBuffer //分段下载 每次下载的字节数 默认1024bytes
 * @param array $allowExt //允许下载的文件类型
 * @return void
 */
function downloadFile($filePath, $readBuffer = 1024, $allowExt = ['jpeg', 'jpg', 'peg', 'gif', 'zip', 'rar', 'txt', 'pdf']) {
    //检测下载文件是否存在 并且可读
    if (!is_file($filePath) && !is_readable($filePath)) {
        return false;
    }

    //检测文件类型是否允许下载
    $ext = strtolower(pathinfo($filePath, PATHINFO_EXTENSION));
    if (!in_array($ext, $allowExt)) {
        return false;
    }

    //设置头信息
    //声明浏览器输出的是字节流
    header('Content-Type: application/octet-stream');

    //声明浏览器返回大小是按字节进行计算
    header('Accept-Ranges:bytes');

    //告诉浏览器文件的总大小
    $fileSize = filesize($filePath); //坑 filesize 如果超过2G 低版本php会返回负数
    header('Content-Length:' . $fileSize); //注意是'Content-Length:' 非Accept-Length

    header('Content-Disposition:attachment;filename=' . basename($filePath)); //声明作为附件处理和下载后文件的名称

    //获取文件内容
    $handle = fopen($filePath, 'rb'); //二进制文件用‘rb’模式读取
    while (!feof($handle)) { //循环到文件末尾 规定每次读取(向浏览器输出为$readBuffer设置的字节数)
        echo fread($handle, $readBuffer);
    }
    fclose($handle); //关闭文件句柄
    exit;
}

这样,下载链接只要按如下写法即可实现下载:

<a href="/download/<?php echo $ids[$i]; ?>">点击下载</a>

$ids[$i] 表示 wordpress 附件的 id。

分类
WordPress

wordpress 自定义文章类型文章列表显示分类列

只需要在register_taxonomy函数的第三个参数中,添加show_admin_column=>true即可。代码如下:

<?php

/**
 * 为产品 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,
        'show_admin_column' => true,
    );
    register_taxonomy('product_category', 'product', $args);
}

如果要在列表中添加自定义字段,即wp_postmeta表中的字段(通过meta_box添加的),可以使用下面的代码:

<?php
// 在列表中把加的字段显示出来
add_action("manage_posts_custom_column",  "product_custom_columns");
function product_custom_columns($column) {
    global $post;
    switch ($column) {
        case "product_director":
            echo get_post_meta($post->ID, '_product_director', true);
            break;
    }
}

add_filter("manage_edit-product_columns", "movie_edit_columns");
function movie_edit_columns($columns) {
    $columns['product_director'] = '产品分类';
    return $columns;
}
分类
WordPress

wordpress 自定义文章类型添加分类筛选功能

想实现的效果如下图:

自定义文章类型添加分类筛选功能

代码如下:

<?php
add_action('restrict_manage_posts', 'product_type_filter');
function product_type_filter() {
    global $typenow;
    $post_type = 'product'; // 发布类型
    $taxonomy = 'product_category'; // 该类型对应的分类法
    if ($typenow == $post_type) {
        $selected = isset($_GET[$taxonomy]) ? $_GET[$taxonomy] : '';
        $info_taxonomy = get_taxonomy($taxonomy);
        wp_dropdown_categories(array(
            'show_option_all' => __("所有{$info_taxonomy->label}"),
            'taxonomy' => $taxonomy,
            'name' => $taxonomy,
            'orderby' => 'name',
            'selected' => $selected,
            'value_field' => 'slug',
            'show_count' => true,
            'hide_empty' => true,
        ));
    };
}
分类
WordPress

wordpress 自定义文章类型的固定链接

自定义文章类型无法在后台设置固定链接格式,可以在 functions.php 中通过代码来实现。代码如下:

<?php
/**
 * 实现 solution 文章类型的 URL 重写
 */
add_filter('post_type_link', 'custom_solution_link', 1, 3);
function custom_solution_link($link, $post) {
    if ($post->post_type == 'solution') {
        return home_url('solution/' . $post->ID . '.html');
    } else {
        return $link;
    }
}

add_action('init', 'custom_solution_rewrites_init');
function custom_solution_rewrites_init() {
    add_rewrite_rule(
        'solution/([0-9]+)?.html$',
        'index.php?post_type=solution&p=$matches[1]',
        'top'
    );
}

比较重要的一点:

代码添加完成后,一定要在后台 “ 固定链接设置” 页面,点击一下 “保存更改” 按钮才能生效!!

分类
WordPress

使用PHP内置服务器运行wordpress造成的404问题

使用内置服务器时,无法把请求转到发 index.php 。可以通过新加一个 routing.php 文件来实现该功能。

运行 wordpress 时使用如下命令:

php -S localhost:80 routing.php

routing.php 文件的内容如下:

<?php
$root = $_SERVER['DOCUMENT_ROOT'];
$path = '/'. ltrim( parse_url( urldecode( $_SERVER['REQUEST_URI'] ) )['path'], '/' );

if ( file_exists( $root.$path ) ) {

    // Enforces trailing slash, keeping links tidy in the admin
    if ( is_dir( $root.$path ) && substr( $path, -1 ) !== '/' ) {
        header( "Location: $path/" );
        exit;
    }

    // Runs PHP file if it exists
    if ( strpos( $path, '.php' ) !== false ) {
        chdir( dirname( $root.$path ) );
        require_once $root.$path;
    } else {
        return false;
    }
} else {

    // Otherwise, run `index.php`
    chdir( $root );
    require_once 'index.php';
}

参考:

https://old.romaricpascal.is/writing-about/running-worpdress-with-php-built-in-server/

分类
WordPress

wordpress 获取文章内的第一张图片

<?php
// 获取文章第一张图片
function catch_that_image() {
    global $post, $posts;
    $first_img = '';
    ob_start();
    ob_end_clean();
    $output = preg_match_all('/<img.+?src=[\'"]([^\'"]+)[\'"].*?>/i', $post->post_content, $matches);
    if ($output) {
        $first_img = $matches[1][0];
    }

    if (empty($first_img)) {
        $first_img = bloginfo('template_url') . "/assets/images/default_image.jpeg";
    }
    return $first_img;
}