wordpress 正規API寫法教學

官方教學請參考:點我

非外掛情況:加入在function.php
外掛情況:加入在class的__construct()內

add_action('rest_api_init', function(){
   register_rest_route( 'apitest/v1', '/apitest01/', array(
                        'methods' => 'POST',
		        'callback' => array($this,'testapi'),
		         )
   );
});
//api網址=網站根目錄網址+wp-json/apitest/v1/apitest01

測試的function(實際上api做的事情)
要記得這邊有個小坑要注意,若上面的methods設定為post但實際上用get方式,反之亦然,api雖然依舊會執行function但會多回傳一個WP_ERROR的json將其視為路徑不存在

function testapi($data){
                //$data相當於PHP變數$POST
		echo json_encode(array('success'=>'測試成功'));
                //但純回傳測試成功
		exit();
	}

接下來讓我們建立一支html檔做簡單的測試,內容如下:

<form action="網站根目錄網址+wp-json/apitest/v1/apitest01" method="POST">
	<input type="submit" value="送交"/>
</form>

點擊按鈕送出後得到以下結果即代表成功!
{“success”:”\u6e2c\u8a66\u6210\u529f”}

wordpress外掛開發 綠界物流外掛開發踩雷分享

大概一年多前串了綠界金流的外掛,當時其實也有想試試看串物流,但因為看起來有點複雜加上各種偷懶到現在才補坑,經過一年的成長其實發現沒有當初想像的那麼難但也沒有多簡單而且還有很多坑

先附上外掛載點:

https://drive.google.com/drive/folders/1PcfhV4skRgFMiT9YhK_f-PyV7sH2gztW?usp=sharing

跟綠界的物流界接說明文件:

https://www.ecpay.com.tw/Content/files/ecpay_030.pdf

這次的範例外掛主要流程如下:

  1. 點下按鈕後 -> 開啟綠界超商api
  2. 接收到綠界超商api使用者選完回傳的商店資訊後 -> 建立物流訂單

外掛使用方式:

  1. 下載後安裝
  2. 建立一個頁面 輸入短代碼 [c2c-test type=”c2c_btn_test”]
  3. 點選按鈕”建立物流訂單”

開啟超商地圖api程式碼說明:

其實跟一般的api沒什麼兩樣,只是可能因為綠界那邊太少更新了,在串的時候就發現幾個點

  • ServerReplyURL IsCollection ->這個欄位在綠界的說明文件是要填 Y or N 實際上要填 YES or NO
  • LogisticsSubType ->這個欄位看文件說明會以為要切成C2C應該要改成UNIMARTC2C,實際上這樣寫會導致程式錯誤,應該要填寫 UNIMART_C2C即可正常運作
  • ServerReplyURL->綠界api回傳超商資料的網址
function createC2COrder(){
		// 一般物流訂單建立
		require_once(ECPAY_C2C_TEST_DIR.'/SDK/Ecpay.Logistic.Integration.php');
		try {
			$AL = new EcpayLogistics();
			$AL->Send = array(
				'MerchantID' => '2000132',
				'MerchantTradeNo' => 'no' . date('YmdHis'),
				'LogisticsSubType' => EcpayLogisticsSubType::UNIMART,
				'IsCollection' => EcpayIsCollection::NO,
				'ServerReplyURL' => get_home_url(). '/ServerReplyURL.php',
				'ExtraData' => '測試額外資訊',
				'Device' => EcpayDevice::PC
			);
			// CvsMap(Button名稱, Form target)
			$html = $AL->CvsMap('電子地圖(統一)');
			echo $html;
			exit();
		} catch(Exception $e) {
			echo $e->getMessage();
			exit();
		}
	}

建立物流訂單api程式碼說明:

  • LogisticsC2CReplyURL -> 建立訂單失敗會回傳的網址
  • ClientReplyURL -> 訂單物流狀態更改時會回傳的網址
if(strpos($_SERVER['REQUEST_URI'], '/ServerReplyURL')===0||strpos($_SERVER['REQUEST_URI'], '/ServerReplyURL')>0){
			require_once(ECPAY_C2C_TEST_DIR.'/SDK/Ecpay.Logistic.Integration.php');
			echo $_POST["MerchantID"]."\r\n";
			echo $_POST["MerchantTradeNo"]."\r\n";
			echo $_POST["LogisticsSubType"]."\r\n";
			echo $_POST["CVSStoreID"]."\r\n";
			echo $_POST["CVSStoreName"]."\r\n";
			echo $_POST["CVSAddress"]."\r\n";
			echo $_POST["CVSTelephone"]."\r\n";
			echo $_POST["CVSOutSide"]."\r\n";
			echo $_POST["ExtraData"]."\r\n";
                        //這些是超商地圖api選擇完後會回傳的參數
			try {
				$AL = new EcpayLogistics();
				$AL->HashKey = '5294y06JbISpM5x9';
				$AL->HashIV = 'v77hoKGq4kWxNNIS';
				$AL->Send = array(
					'MerchantID' => '2000132',
					'MerchantTradeNo' => 'no' . date('YmdHis'),
					'MerchantTradeDate' => date('Y/m/d H:i:s'),
					'LogisticsType' => EcpayLogisticsType::CVS,
					'LogisticsSubType' => EcpayLogisticsSubType::UNIMART,
					'GoodsAmount' => 1500,
					'CollectionAmount' => 10,
					'IsCollection' => EcpayIsCollection::NO,
					'GoodsName' => '測試商品',
					'SenderName' => '測試寄件者',
					'SenderPhone' => '0226550115',
					'SenderCellPhone' => '0911222333',
					'ReceiverName' => '測試收件者',
					'ReceiverPhone' => '0226550115',
					'ReceiverCellPhone' => '0933222111',
					'ReceiverEmail' => 'test_emjhdAJr@test.com.tw',
					'TradeDesc' => '測試交易敘述',
					'ServerReplyURL' => get_home_url() . '/ServerReplyURL.php',
					'ClientReplyURL' => get_home_url(),
					'LogisticsC2CReplyURL' => get_home_url() . '/LogisticsC2CReplyURL.php',
					'Remark' => '測試備註',
					'PlatformID' => '',
				);
				$AL->SendExtend = array(
					'ReceiverStoreID' => '991182',
					'ReturnStoreID' => '',
				);
				// CreateShippingOrder()
				$Result = $AL->CreateShippingOrder();
				echo '<pre>' . print_r($Result, true) . '</pre>';
				exit();
			} catch(Exception $e) {
				echo $e->getMessage();
				exit();
			}
		}

本次範例外掛只針對最核心的部分來做說明跟講解,各位小夥伴可依據自己開發的程式需求及功能做架構上的調整,有問題的話歡迎留言一起討論 。

wordpress 外掛適應多語言開發撰寫方式

使用時機:
網頁有多個語言版本供用戶閱覽,或是外掛開發目的是讓多國使用者使用,可提升外掛跨國通用程度。

外掛主檔設定

外掛主檔設定:

/*

 * Plugin Name: 

 * Description: * Author: nekoto

 * Plugin URI: 

 * Version: 

 * Text Domain: $文本域名

 * Domain Path: /languages

 */

1.建立.pot檔(開發主語言翻譯)

檔案名稱:$文本域名.pot

#. 翻譯文本1
msgid "翻譯索引1"
msgstr "翻譯後文字1"

#. 翻譯文本2
msgid "翻譯索引2"
msgstr "翻譯後文字2"

#. 翻譯文本3
msgid "翻譯索引3"
msgstr "翻譯後文字3"

#. 翻譯文本4
msgid "翻譯索引4"
msgstr "翻譯後文字4"

2.建立.po檔(依照語言命名)

檔案名稱:$文本域名.po

若此檔要套用至繁體中文
則檔案名稱命名為:$文本域名-zh_TW.po

(.mo檔命名同理)

3.將撰寫好的.po檔轉成.mo檔  (php只認.mo檔,所以po檔更改後要記得轉.mo檔才會套用變更)

https://po2mo.net/ 上傳撰寫好的.po檔後下載轉好的.mo檔

下載後改名
檔案名稱:$文本域名.mo

4.外掛內載入:在外掛主檔內寫入

/*
* Load plugin textdomain.
*/
function plugin_load_textdomain() {
load_plugin_textdomain( '$文本域名', false, basename( dirname( __FILE__ ) ) .'/languages/' );
//這邊等於我把翻譯檔路徑設在我外掛下的languages資料夾,wordpress框架會自動去抓翻譯檔
}
add_action( 'init', 'plugin_load_textdomain' );

5.在呼叫文字時使用

例如我語言設定檔內有個

#. 翻譯範例

msgid “apple”

msgstr “蘋果”

在頁面要呼叫的時候:

原本不用語言管理時:echo “蘋果”; 

使用語言管理寫法後: _e( ‘apple’ , ‘$文本域名’ );

兩個寫法在頁面上都會顯示 蘋果

若要翻譯的文檔中含有變數 則使用printf搭配使用:

printf(

__( ‘你的蘋果是 %s.’, ‘$文本域名’ ),$apple

);

WordPress外掛提交流程

  1. 前往 https://wordpress.org/plugins/developers/
  2. 點選 Submit your plugin for review

3.上傳你開發好的外掛zip檔
※外掛除了可運行的程式還會要求在根目錄要有readme.txt※
如果不清楚格式可到 https://generatewp.com/plugin-readme/ 自動生成
若要在描述的部分新增可點選的網址請按照此格式,不然會被當成純文字處理:
[要顯示的名稱](網址)
example: [Google](https://www.google.com/)

提交之後就等待wordpress他們的人員幫你審查,審查完後他們會寄信跟你說有那些問題,修改完後你再以github或是google雲端的方式告知他們程式碼已修正就好,反正就是能讓他們載的到你的程式就OK,接下來就是修正->審核->修正->審核的過程

以下講講我自己外掛被審出的需要修改的地方,有些真的是沒碰過不會發現有問題,但我覺的wordpress方也蠻用心地都有明確指出哪邊有哪個類型的錯誤,也有說明錯誤在哪支程式哪一行

插件名稱問題

大意是說你一開始取的外掛名稱不符合規範,他們會給你一個他們建議的名稱,照著改就好,記得要改readme.txt跟你外掛主代碼的外掛描述(如下圖)

插件包含多餘資料夾

開發的時候如果我們有引用第三方套件,常常都會將整包檔案放進程式裡,但這接第三方套件裡常常都包含如demo,example,doc等外掛並不需要使用到的部分,wordpress會要求您將這些非必要的部分移除外掛

插件呼叫遠程文件

開發外掛的時候為求方便有時候會直接call CDN , wordpress會要求可以下載到本地端做呼叫的檔案盡量下載到本地端,真的沒辦法本地呼叫的(如:googlemap相關的套件),可以允許遠端呼叫

插件必須驗證數據

我猜是因為安全性的考量,wordpress會要求您的後端程式碼在接收前端的數據時要做過驗證,這部分一開始我搞不太懂,想說我有對數據做檢查他怎麼還是回信說有問題
https://developer.wordpress.org/plugins/security/securing-input/
wordpress有提供蠻多現成的函式來讓開發者做數據驗證及清理,如果你接收的資料想要自定義(簡單來講不是像email這種有標準格式的),使用GET或POST接收前端數據的時候建議就使用sanitize_text_field這個函式,他主要是可以過濾使用者惡意插入的html tag

有興趣的可以自行搜尋: XSS攻擊

插件中含有通用的函式名稱

簡單來說就是你外掛中的function取的名字太通用了不夠有區別性,因wordpress上會同時掛載多個外掛,所以官方要確保你function的名字獨特才不會跟別的外掛相互影響

全部修正完之後官方就會給你一個svn網址讓你更新跟管理你的外掛,要進行第一次上傳之後你的外掛才會變為公開,這點請注意,至於如何使用svn就留待下一篇詳解吧!

wordpress本機基礎測試環境架設

開發外掛的過程一定會遇到很多不可預期的狀況,如果是接案的狀況再更改設定或外掛不小心玩壞了要修復也是件挺令人擔心的事情,所以這篇主要教大家如何在本地端架出wordpress的環境,出了問題也能夠比較好理解問題在哪哦!

首先先下載XAMPP

https://www.apachefriends.org/zh_tw/download.html

下載完之後進行安裝,預設安裝完的路徑會在C:\xampp

xampp下有個資料夾叫做htdocs是網站的根目錄

在htdocs下放一包wordprss(記得解壓縮)

https://drive.google.com/file/d/1XxxI75FTbDfuiOiX-cYWnnMu0emns3TY/view?usp=sharing

放好之後打開xampp程式

打開Apache跟MySQL

按下MySQL右邊的Admin
先建一個要給wordpress用的資料庫

打開網頁,輸入 http://localhost/wordpress/ ,會出現這個畫面

點擊開始安裝

資料庫名稱填上剛剛建的資料庫名稱,然後設定使用者名稱跟密碼,xampp的mysql預設的帳號密碼是root跟空白,基本上主機位置跟資料表前置詞可以用預設就好,輸入無誤後按傳送

點選執行安裝程式

輸入完畢後點選安裝Wordpress

完成啦!!!可以開始盡情的玩囉~

如果真的遇到玩壞了不知道該怎麼修復的情況,只要把wordpress刪掉重新安裝一次就可以了

wordpress外掛開發 讓外掛自動新建所需資料表

寫一個外掛的重點其中之一,讓外掛能自動建立本身所需的資料表是很重要的,如果是要在複數個網站安裝自己寫的外掛這個部分就更加重要
下面就讓我們來看看要如何做到讓外掛自動建立資料表

主要步驟如下:

首先在class的function __construct內加入

if(!defined('ABSPATH'))exit;
$this->CreateTable();
//自動新增所需資料表

CreateTable就是待會我們要建立資料表的function,將上述語法放在 function __construct 內是為了要讓其自動執行,達到自動建立的效果

接下來讓我們看CreateTable()內的內容

function CreateTable(){
	global $wpdb;

	require_once(ABSPATH.'wp-admin/includes/upgrade.php');
    //要更新資料表就得require這支wp程式
	$charset_collate=$wpdb->get_charset_collate();//取得資料表的預設編碼
	//如果有中文就設成utf8避免亂碼

	/*begin of 有多個table就要寫多個區塊*/
	$table_name=$wpdb->prefix.'_user_register';
	if($wpdb->get_var("SHOW TABLES LIKE '$table_name'")!=$table_name){
		$sql="CREATE TABLE `{$wpdb->prefix}_user_register` (
		  `ID` int(11) NOT NULL AUTO_INCREMENT,
		  `名字` varchar(10) NOT NULL,
		  `密碼` varchar(100) NOT NULL,
		  `信箱` varchar(50) NOT NULL,
		  `手機` varchar(10) NOT NULL PRIMARY KEY
		 )$charset_collate;";
		 //如果要限制一人只能註冊一個帳號,建議把手機設為primary key並且在註冊流程加上手機認證
		 dbDelta($sql);
		/*end of 有多個table就要寫多個區塊*/
	}
}

邏輯上簡單來說是先用 SHOW TABLES LIKE ‘$table_name’ 來確認是否已存在同名稱的資料表,若不存在就使用dbDelta這個函式來建立該資料表

以簡易框架教學那篇的架構來說的話,如果資料表少我就會放在main.php內