17 mins read2022/08/08 HEN難

php 自動生成文章精選圖片


前言

Code-WP 的文章精選圖片 ( 封面圖 ) 大概是這樣子

post type in archive

文章精選圖片 ( 封面圖 ) 規格是這樣

  • 符合 Facebook 分享文章的大小 1200 x 630
  • 中間是文章標題
  • 左上角有閱讀難度標示
  • 左下角有預估閱讀時間
  • 右下角是文章發布的日期

因為我很懶,每次發新文章都要同一個步驟 ↓

步驟:

打開 PSD 檔 》 修改文字 》 另存新檔 》 上傳檔案

這個流程非常的制式與無聊,而且萬一發文時間改了,或者標題改了,又要重來一次

所以就想要做這個題目

需求:

  1. 每次文章發表時,要自動產生文章精選圖片,尺寸要合乎規範
  2. 文章精選圖片要能自動抓取文章的參數,標題、時間、難度、閱讀時間等等…
  3. 產生完之後要能自動上傳到 WordPress 上,並套用成為指定文章的精選圖片

這個題目也非常符合我想發展自動化的精神

如果有大神覺得有更簡單的做法也歡迎留言討論,我認為我的作法可能不是最好的辦法,總感覺有點繞

 

核心思路

需求的 23 我應該都有辦法處理

2 可以用 $post 物件就可以處理好,主要是看怎麼傳遞參數

3 應該有對應的 Hooksfunctions 可以處理

1 的產生圖片,可能才會是我的技術難點,我也沒有做過

做為一個前端與後端都會寫的工程師,再來要思考的點是 – 應該要在前端還是在後端產生圖片

因為最後圖片要變成文章的精選圖片,因此我的答案是 – 由後端在伺服器的位置生成圖片

 

於是我在 Google 、 GitHub 跟 Packagist ( php Library )搜尋 phptoimage, htmltoimage 等關鍵字

有找到許多 API 的作法,但是短時間內呼叫太多次會收費,但我認為我需求不算太複雜,應該可更容易的方式

折騰一下之後,接著找到這個 Library KnpLabs / snappy

KnpLabs / snappy

用這個 Library 可以用 html 產生 pdf 也可以吃到 CSS ( 但經過實驗,像 flex 這類屬性會失效 )

在使用 KnpLabs / snappy 之前,⭐必須在你的機器上要安裝 wkhtmltoimage ,否則這個 Library 無法運作 ( 相依 )

裡面的程式碼範例主要是以 html 轉 pdf 為主,但裡面也有提到可以 html 轉 image,只是沒有範例,要自己看源代碼

  1. 用 composer 安裝 KnpLabs / snappy
  2. 安裝 wkhtmltoimage

如果你可以用指令產生 pdf 的話,就代表你安裝成功了

例如:wkhtmltopdf https://computingforgeeks.com computingforgeeks.pdf 

看一下原始碼,修改成這樣,就可以產生 png 了



<?php
// 這個是 htmltoimage.php
use Knp\Snappy\Image;
/**
 * KnpLabs/snappy
 * Snappy is a PHP library allowing thumbnail, snapshot or PDF generation from a url or a html page. It uses the excellent webkit-based wkhtmltopdf and wkhtmltoimage available on OSX, linux, windows.
 * @see https://github.com/KnpLabs/snappy
 */
require __DIR__ . '/../composer/vendor/autoload.php';

/**
 * 使用 getopt 接受參數 getopt('n:') 取得 -n 跟 -p 的值
 * @see https://blog.csdn.net/qq_36663951/article/details/82760613
 */

$opt = getopt('n:p:');
$file_name = $opt['n'];
$uploadpath = $opt['p'];

ob_start();
// 載入你要變成圖片的 HTML 檔案
include_once( __DIR__ . '/post_thumbnail_HTML_template.html' );
$html = ob_get_clean();

$snappy = new Image('/usr/local/bin/wkhtmltoimage');
$snappy->generateFromHtml($html, $uploadpath . '/' . $file_name . '.png', [
    'crop-w' => 1200,
    'crop-h' => 630,
    'crop-x' => 8,
    'crop-y' => 8,
]);





 ?>


 

原本想說把整個功能,包裝成一個 function ,在想要的地方呼叫

結果如果直接用 WordPress 呼叫會發生

"Fatal error: Uncaught Exception: attempt to perform an operation not allowed by the security policy `PDF' @ error/constitute.c/IsCoderAuthorized/408"

但這個問題我之前就解過了,只要把 /etc/ImageMagick-6/policy.xml 裡面的 rights 改掉就好,參考資料

我不懂為什麼,我用 php cli 可以執行,但是包裝成函式用 WordPress 執行就會報錯

有知道的大大可以留言在底下🙏‍

因為這個坑的關係,我要執行這個輸入函示,就必須使用 php cli

// 這個是 thumnail_generator.php

/*
 * 執行 php cli
 * 輸出成圖片
 * 傳參 @see https://blog.csdn.net/qq_36663951/article/details/82760613
 * 把 post{id} 作為 n 的 value 傳進 htmltoimage.php
 * 把 upload路徑 作為 p 的 value 傳進 htmltoimage.php
 */
$command = 'php ' . __DIR__ . '/htmltoimage.php -n' . 'post' . get_the_ID() . ' -p' . wp_upload_dir()['path'];
$output = shell_exec($command);

像這樣,會把參數傳到 htmltoimage.php 裡面 ( 上圖的 n 與 p 都可以自己改掉 )

n 是圖片名稱,我用 post{id} 來命名,例如文章 id 是 575,那這張縮圖我就命名為 post575.png

p 是圖片上傳的路徑,會自動儲存到 /wp-content/uploads/{年分}/{月份}/ 裡面

 

專案結構

好,這樣整體的邏輯算是離清楚了

Composer資料夾 裡面用Composer 安裝 KnpLabs / snappy
檔案名稱 說明
courier_new.ttf 這隻是字形檔

套用到要產生的 HTML 模板裡面

htmltoimage.php 這隻是要用 php cli 執行的 php 檔

用途:將載入的 HTML 轉換成 PNG

post_thumbnail_HTML_template.html 這隻是要被 htmltoimage.php 載入的 HTML 檔

本身也是由 php 產生,不是寫死的

thumnail_generator.php⭐ 這隻是核心函式檔,插在 transition_post_status這隻 Hooks 上,當文章發佈時觸發

主要做的事情:

發佈時會自動用文章參數產生 post_thumbnail_HTML_template.html

用 php cli 執行 htmltoimage.php

wp_insert_attachment 函式自動將生成的圖片加入為精選圖片

想看原始碼的朋友們可以到我的 GitHub ,如果覺得不錯,也請給我顆星星 ⭐

 

像這種有底圖的或者漸層的,只要用我代碼再去修改也都做得到,也可以做成每篇文章不同底圖

 

其他未錄取的解法

PHP 內建的 imagepng 函式產生圖片

這個感覺只能畫出一般的幾何圖形,而且 CSS 不能使用,我覺得用起來好麻煩,所以放棄

 

Google page speed API

可以輸入網址,產生縮圖

但縮圖似乎無法控制尺寸,而且 API 用多應該也是要付費,故不考慮

 

覺得不錯的話,請給我點個推薦

您的支持與鼓勵是我們前進的最大動力!