wordpress外掛開發 簡易綠界API串接結合自己開發的外掛

架構上開發主要分為三個部分

1.主要處理使用者購買物品的function ,這個function主要的邏輯是將使用者購買的東西資料送往綠界的網址

function ,這個function主要的邏輯是將使用者購買的東西資料送往綠界的網址

2.放在SDK(我個人習慣)的ECPay.Payment.Integration.php(綠界提供的SDK),1跟3步驟的過程中都需要引入此檔案,其中這支程式的 static function CheckOut 要進行修改,要在送出此筆交易時紀錄該筆訂單的資訊

下載網址 :

https://drive.google.com/file/d/1b_kac8bhpClNAU19kwtI6i_CmmIW1RZF/view?usp=sharing

3.綠界交易結果的回傳頁面,做法就是將回傳頁面建立成模板,新建一個頁面當回傳頁面,可以自訂網址

主要的function


function MPBuy(){
		include MP_DIR.'/SDK/ECPay.Payment.Integration.php';

		global $wpdb;
		$ID=CheckLogin();//檢查是否登入
		//這邊先以單個商品購買作範例
		//若有多個改用array傳入即可
		$pointNum=$_POST["pointnum"];//商品數量

		$pointCost=$_POST["pointcost"];//商品價格

		//這邊給個建議,如果擔心程式安全性問題,建議這邊傳入商品ID,再去資料庫抓出當前價格

		if($pointNum==0||$pointCost==0){
			echo "<script>alert('購買失敗!');</script>";
			exit();
		}
		$pointSum=$_POST["pointnum"]*$_POST["pointcost"];
		$pointrent=ceil_dec((int)$pointSum*0.0275,0);

		if($pointrent<15){
			$pointrent=15;
		}
		//綠界那邊好像是不會計算手續費,所以這部份得要自己依據需求將手續費列入
		//不然手續費的部分就變成自行吸收了
		//這邊只是粗略的計算方式,想知道詳細可以去閱讀綠界的API說明

		try {

			$obj = new ECPay_AllInOne();

			//服務參數
			$obj->ServiceURL  = "https://payment.ecpay.com.tw/Cashier/AioCheckOut/V5";  //服務位置
			$obj->HashKey     = '$HashKey' ;                                          //請自行帶入ECPay提供的HashKey
			$obj->HashIV      = '$HashIV' ;                                          //請自行帶入ECPay提供的HashIV
			$obj->MerchantID  = '$MerchantID';                                                  //請自行帶入ECPay提供的MerchantID
			$obj->EncryptType = '1';                                                          //CheckMacValue加密類型,請固定填入1,使用SHA256加密


			//基本參數(請依系統規劃自行調整)
			$MerchantTradeNo = 'Myshop'.time() ;
			//這邊是序號,我自己習慣是網站名稱+timestamp
			$MerchantTradeDate = date('Y/m/d H:i:s');
			$obj->Send['ClientBackURL']="$消費者付款完畢跳轉的網址";
			//$obj->Send['ReturnURL']         = "http://www.ecpay.com.tw/receive.php" ;     //付款完成通知回傳的網址
			$obj->Send['ReturnURL']         = "$付款完成我方處理綠界回傳資訊的網址" ;
			$obj->Send['MerchantTradeNo']   = $MerchantTradeNo;                           //訂單編號
			$obj->Send['MerchantTradeDate'] = $MerchantTradeDate;                        //交易時間
			$obj->Send['TotalAmount']       = $pointSum+$pointrent;                        //交易金額
			$obj->Send['TradeDesc']         = "購買XXX" ;                           //交易描述
			$obj->Send['ChoosePayment']     = ECPay_PaymentMethod::ALL ;                  //付款方式:全功能

			//訂單的商品資料
			array_push($obj->Send['Items'],array('Name' => "XXX " , 'Price' => (int)$pointCost,'Currency' => "元", 'Quantity' => (int)$pointNum, 'URL' => "dedwed"),
array('Name' => "手續費", 'Price' => (int)$pointrent,'Currency' => "元", 'Quantity' => 1, 'URL' => "dedwed"));
			$sql = "INSERT INTO {$wpdb->prefix}coserorder (`MerchantTradeNo`,`orderTime`,`orderFee`,`orderUserId`) VALUES ('".$MerchantTradeNo."','".$MerchantTradeDate."','".$pointrent."','".$ID."')";
			$intReturn=$wpdb->query($sql);
			if($intReturn==0){
				echo "<script>alertify.log('購買失敗!');</script>";
				exit();
			}

			# 電子發票參數
			/*
        $obj->Send['InvoiceMark'] = ECPay_InvoiceState::Yes;
        $obj->SendExtend['RelateNumber'] = "Test".time();
        $obj->SendExtend['CustomerEmail'] = 'test@ecpay.com.tw';
        $obj->SendExtend['CustomerPhone'] = '0911222333';
        $obj->SendExtend['TaxType'] = ECPay_TaxType::Dutiable;
        $obj->SendExtend['CustomerAddr'] = '台北市南港區三重路19-2號5樓D棟';
        $obj->SendExtend['InvoiceItems'] = array();
        // 將商品加入電子發票商品列表陣列
        foreach ($obj->Send['Items'] as $info)
        {
            array_push($obj->SendExtend['InvoiceItems'],array('Name' => $info['Name'],'Count' =>
                $info['Quantity'],'Word' => '個','Price' => $info['Price'],'TaxType' => ECPay_TaxType::Dutiable));
        }
        $obj->SendExtend['InvoiceRemark'] = '測試發票備註';
        $obj->SendExtend['DelayDay'] = '0';
        $obj->SendExtend['InvType'] = ECPay_InvType::General;
        */


			//產生訂單(auto submit至ECPay)
			$obj->CheckOut();

		} catch (Exception $e) {
			echo $e->getMessage();
		} 
	}

綠界提供的SDK

接下來說明ECPay.Payment.Integration.php我有做修改的部分

static function CheckOut($target = "_self",$arParameters = array(),$arExtend = array(),$HashKey='',$HashIV='',$ServiceURL=''){
		global $wpdb;
	 	$MerchantTradeNo=$arParameters['MerchantTradeNo'];
		$MerchantTradeDate=$arParameters['MerchantTradeDate'];
        $arParameters = self::process($arParameters,$arExtend);
        //產生檢查碼
        $szCheckMacValue = ECPay_CheckMacValue::generate($arParameters,$HashKey,$HashIV,$arParameters['EncryptType']);
		//在資料表新增一筆訂單號與檢查碼
		$sql = "update {$wpdb->prefix}order set `szCheckMacValue`='".$szCheckMacValue."' where MerchantTradeNo='".$MerchantTradeNo."'";
    	$intReturn=$wpdb->query($sql);
		if($intReturn==0){
			echo "<script>alertify.log('購買失敗!');</script>";
			exit();
		}

        //生成表單,自動送出
        $szHtml = parent::HtmlEncode($target, $arParameters, $ServiceURL, $szCheckMacValue, '') ;
        echo $szHtml;
        exit;
    }

其中以下這段是我新增進去的,可依個人開發需求做調整,主要做的事情是記錄下訂單的資訊跟檢查碼,記得最上面要加global $wpdb; , 不然無法使用wp的資料庫哦!

$sql = "update {$wpdb->prefix}order set `szCheckMacValue`='".$szCheckMacValue."' where MerchantTradeNo='".$MerchantTradeNo."'";
    	$intReturn=$wpdb->query($sql);
		if($intReturn==0){
			echo "<script>alertify.log('購買失敗!');</script>";
			exit();
		}

綠界交易結果的回傳頁面

用模板的方式新建一個wp頁面,可以另外自訂網址,程式碼如下:

<?php
/*
Template Name: ECPay Template
*/
//要加這個註解wp框架才知道這支程式是模板
global $wpdb;
require_once dirname(__FILE__).'/ECPay.Payment.Integration.php';
define( 'ECPay_MerchantID', '$ECPay_MerchantID' );
define( 'ECPay_HashKey', '$ECPay_HashKey' );
define( 'ECPay_HashIV', '$ECPay_HashIV' );
 
// 重新整理回傳參數。
$arParameters = $_POST;
foreach ($arParameters as $keys => $value) {
    if ($keys != 'CheckMacValue') {
        if ($keys == 'PaymentType') {
            $value = str_replace('_CVS', '', $value);
            $value = str_replace('_BARCODE', '', $value);
            $value = str_replace('_CreditCard', '', $value);
        }
        if ($keys == 'PeriodType') {
            $value = str_replace('Y', 'Year', $value);
            $value = str_replace('M', 'Month', $value);
            $value = str_replace('D', 'Day', $value);
        }
        $arFeedback[$keys] = $value;
    }
}
 
// 計算出 CheckMacValue
$CheckMacValue = ECPay_CheckMacValue::generate( $arParameters, ECPay_HashKey, ECPay_HashIV );
// 必須要支付成功並且驗證碼正確
if ( $_POST['RtnCode'] =='1' && $CheckMacValue == $_POST['CheckMacValue'] ){
    // 
    // 要處理的程式放在這裡,例如將線上服務啟用、更新訂單資料庫付款資訊等
    // 
    $MerchantTradeNo=$_POST["MerchantTradeNo"];
    $RtnCode=$_POST["RtnCode"];
    $TradeAmt=$_POST["TradeAmt"];
    $CheckMacValue=$_POST["CheckMacValue"];
}
else{
}
 
// 接收到資訊回應綠界
echo '1|OK';
?>

然後在class_myplugin-main.php的__construct內加上,這個方法要記得在開發完後的ECPay-template.php要以ECPay-template.txt的方法儲存,不然複製到目的資料夾時只會是執行結果而非內容,ECPay.Payment.Integration.txt則是txt跟php檔都得各存一份,一份是留給外掛function呼叫,一份是給複製完的模板頁面使用

copy(MP_DIR."/APItemplates/ECPay-template.txt", get_template_directory()."/ECPay-template.php");
		//get_template_directory()取得當前主題路徑
		//記得原頁面開發完要轉成txt
		//phpA 複製給 phpB的話 phpB的內容只會是phpA執行完的的結果(非內容)

		copy(MP_DIR."/SDK/ECPay.Payment.Integration.txt", get_template_directory()."/ECPay.Payment.Integration.php");
		//複製綠界SDK到相對路徑下

以方法二撰寫外掛要記得到wordpress的頁面新增一個頁面,模板選擇ECPay Template,就可以自訂處理綠界回傳值的網址啦!
記得網址設定完後記得修改第一步驟內的回傳網址
看到這邊如果對以上程式的相對路徑有疑問的可以直接載這包來看,會比較好理解!
記得這包是不能直接跑的哦,如果要測試新增一個頁面使用ajax呼叫function即可

外掛結合簡易綠界程式載點

https://drive.google.com/file/d/1sh0ysyTMbi_LfN6Pn3NqJ9TNXOdgoiiS/view?usp=sharing

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內

wordpress外掛開發 結合PHPMailer發信(低安全性模式)+簡易信箱認證

本篇主要 在介紹 當自己開發的外掛有發信需求時,如何使用PHPMailer來達成需求,記得用本篇教學方式用來發信的gmail信箱請記得設定成 ‘低安全性’ 否則google會阻擋來自你外掛的發信請求,之後再詳細寫一篇如何用高安全性模式發信

首先先下載PHPMailer:

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

然後將其解壓縮放在外掛資料夾下,我自己的習慣是設個email資料夾再把PHPMailer解壓縮到資料夾內

接下來是主要的發信部分,我開發成function的方式,後來發現如果你本身要開發的外掛有數種不同的發信需求的話,這樣會比較便於使用,如果有閱讀本網站的簡易外掛開發的話,我習慣將此function放在class_myplugin-cofunction.php

<?php
    use PHPMailer\PHPMailer\PHPMailer;//必須加在call這支函式的php檔的最上方<?php之後
	function MPsendMail($title,$content,$email){
		//記得要替換成PHPMailer與根目錄的相對位置
		require_once MP_DIR.'/email/PHPMailer/src/PHPMailer.php';
		require_once MP_DIR.'/email/PHPMailer/src/SMTP.php';
		require_once MP_DIR.'/email/PHPMailer/src/Exception.php';
		$mail= new PHPMailer();                             //建立新物件
		$mail->SMTPDebug = 0;                        
		$mail->IsSMTP();                                    //設定使用SMTP方式寄信
		$mail->SMTPAuth = true;                        //設定SMTP需要驗證
		$mail->SMTPSecure = "ssl";                    // Gmail的SMTP主機需要使用SSL連線
		$mail->Host = "smtp.gmail.com";             //Gamil的SMTP主機
		$mail->Port = 465;                                 //Gamil的SMTP主機的埠號(Gmail為465)。
		$mail->CharSet = "utf-8";                       //郵件編碼
		$mail->Username = "$Gamil帳號";       //Gamil帳號
		$mail->Password = "$Gmail密碼";       //Gmail密碼
		$mail->From = "$寄件者信箱";        //寄件者信箱
		$mail->FromName = "XX網站";                  //寄件者姓名
		$mail->Subject = $title; //郵件標題
		$mail->Body = $content; //郵件內容
		$mail->IsHTML(true);//郵件內容為html
		$mail->AddAddress($email);//收件者郵件及名稱
		$mail->Send();
	}
?>

記得呼叫此函式的php檔開頭的地方要加上use PHPMailer\PHPMailer\PHPMailer;
這是 PHPMailer 的標準使用方式,一定要加不然程式不能正常執行!

加碼一下簡易的信箱認證邏輯

首先要建立認證頁面的部分,方法的話有推薦兩種
1.寫成templates的形式然後用shortcode插入elementor,不了解的可以翻一下本網站的外掛框架教學
2.把這個頁面設成wordpress範本,在發佈頁面的時候可以使用該模板

個人比較推薦方法一,因為方法二得要直接打開檔案進行編輯,無法在wp後台進行處理
但有時候這種處理回傳值的頁面必須得採用方法二的方式,尤其是在串接第三方API需要回傳值的時候,這牽扯到wp的頁面展示方式,之後會用另一篇跟大家說明

首先是模板的程式碼,各位可以依需求自行調整機制
邏輯上很簡單,就是用get的方式取得網址後面的驗證碼,然後到資料庫check是否有相同驗證碼跟期限是否已過,個人覺得這方法的驗證可能有點過於簡單,但這邊先以達到需求為主,有興趣的各位可以再延伸研究較為安全的驗證方式

<?php
global $wpdb;
if($_GET['verify']==""){
	echo '<script>alert("不要亂點");location.href = "./";</script>';
	//避免被亂玩,建議沒驗證碼的時候導回首頁
	return;
}
$verify = stripslashes(trim($_GET['verify']));
$nowtime = time();

$cond = $wpdb->prepare(' AND `信箱驗證碼` = %s ', $verify); //記得AND前面要留空
$sql = "select `ID`,`信箱驗證有效期` from {$wpdb->prefix}Mailregister where `信箱認證狀態`=''";
$sql.=$cond;

$dbResult = $wpdb->get_results($sql);
if($dbResult){
	foreach($dbResult as $value){
		if($nowtime>$value->信箱驗證有效期){ 
			$msg = '<div style="font-size:20px">您的帳號認證有效期已過,請登錄您的帳號重新發送認證郵件!再<div id="time" style="display:inline;"></div>秒跳轉到主頁面</div>';
		}
		else{
			$sql = "UPDATE {$wpdb->prefix}Mailregister SET `信箱認證狀態` = 'T' WHERE `ID` = '".$value->ID."'";
			$intReturn=$wpdb->query($sql);
			if($intReturn==0){
				$msg = '<div style="font-size:20px; letter-spacing:5px;">帳號認證失敗!再<div id="time" style="display:inline;"></div>秒跳轉到主頁面</div>'; 
			}

			$msg = '<div style="font-size:20px; letter-spacing:5px;">帳號認證成功!再<div id="time" style="display:inline;"></div>秒跳轉到主頁面</div>';
		}
	}    
}
else{
	$msg = '<div style="font-size:20px; letter-spacing:5px;">帳號認證失敗!再<div id="time" style="display:inline;"></div>秒跳轉到主頁面</div>'; 
}    

echo $msg;
echo "
        <script>
        //設定倒數秒數
        var t = 5;

        //顯示倒數秒收
        function showTime()
        {
            t -= 1;
            document.getElementById('time').innerHTML=t;

            if(t==0)
            {
                location.href='https://codream.empathy.tw/wordpress/';
            }

            //每秒執行一次,showTime()
            setTimeout('showTime()',1000);
        }
        //執行showTime()
        showTime();</script>";


?>

接下來是發送驗證信的function
這邊的呼叫方式是使用ajax呼叫我自己的習慣是放在include裡的main

add_action('wp_ajax_nopriv_$hook的ajax名稱', array($this, 'MPEmailVerify'));
add_action('wp_ajax_$hook的ajax名稱', array($this, 'MPEmailVerify'));
<?php
function MPEmailVerify(){
		global $wpdb;
		$ID=MPCheckLogin();//這個函式是我做登入模組用來確認登入狀態的.之後會有另一篇介紹簡易的登入模組如何製作
		$cond = $wpdb->prepare(' AND ID = %s ', $ID); //記得AND前面要留空
		$sql = "SELECT * FROM {$wpdb->prefix}userdata where 1=1";
		//假設有個資料表裡面有user的ID,密碼,暱稱
		$sql.=$cond;

		$dbResult = $wpdb->get_results($sql);
		if($dbResult){
			foreach($dbResult as $value){
				$password = md5(trim($value->密碼)); //加密密碼
				$email =$value->信箱; //信箱
				$nickname = $value->暱稱;
			}
		}
		$regtime = time();
		$token = md5($email.$password.$regtime); //使用user的ID,密碼,暱稱創建用於驗證的識別碼
		$token_exptime = time()+60*15;//過期時間為15分鐘後

		$sql="UPDATE {$wpdb->prefix}Mailregister SET `信箱驗證碼`= '".$token."', `信箱驗證有效期` ='".$token_exptime."' WHERE ID = '".$ID."'";//ID是用來記錄是哪個帳號進行認證
		$wpdb->query($sql);

		$title="XX網站認證信";
		$content="親愛的用戶您好:<br /><br />歡迎您註冊,請點擊認證您的帳號<br /> <a href=$認證頁面網址?verify=".$token." 'target='_blank'>$認證頁面網址?verify=".$token."</a><br/>如果以上連結無法點擊,請將它複製到你的瀏覽器網址欄中進入訪問,該連結15分鐘內有效。";

		MPsendMail($title,$content,$email);
		echo json_encode(array('success'=>'認證信已發送至您的信箱!'));
		exit();
	}
?>

wordpress外掛開發 簡易設定頁面

建議如果還沒看過這篇的可以先去看一下還有載一下範例程式碼

本篇主要是介紹用結合外掛的方式撰寫配合外掛的設定頁面,變數的儲存機制則使用wp本身提供的方式,不需要再額外建立資料表

首先先附上程式碼:
只要把框架那篇提供的同名程式碼換掉即可

https://drive.google.com/file/d/1hKarpGikxe3EdYH8pEFqN9Xwh5JChqTa/view?usp=sharing

接下來進入正題:

<?php
add_action('admin_menu', 'add_setting_menu');

function add_setting_menu() {
	add_submenu_page('my-plugin_main', __('設定'), __('設定'), __('manage_options'), 'pm-extend_setting','add_settings_page');
	add_action( 'admin_init', 'register_plugin_settings' );
}
//先加上設定的頁面

function register_plugin_settings() {
	register_setting( 'myplugin-group', 'plugin_date' );
	register_setting( 'myplugin-group', 'plugin_flag' );
}
//記得表格中有新的設定時要在這邊註冊變數名稱,否則變數不會記錄進options.php

function add_settings_page() {
?>
<!--以下是頁面的範例內容,可依據設定頁面需求自己做更改 -->
<div class="wrap">
	<h2>範例系統設定</h2>
	<br><br>
	<!-- option.php是固定的,wordpress會自動記錄所有設定值 -->
	<form method="post" action="options.php">
		<?php settings_fields('myplugin-group'); ?>
		<!-- 要先宣告這句下面才有辦法使用上面註冊的變數 -->
		<input type="checkbox" name="plugin_flag" value="1"
			   <?php if (get_option('plugin_flag')==1) echo "checked" ; ?> />
		測試勾選框<br/>
		<br>
		測試input框  :
		<input type="text" id="plugin_date" name="plugin_date" value="<?php echo get_option('plugin_date'); ?>"/>
		<p class="submit">
			<input type="submit" class="button-primary" value="儲存" />
			<!-- 這邊就submit表單所有欄位的值就會做紀錄了,不需要另外自己寫js處理,如果要debug就去wp後台首頁,去掉index.php改成options.php-->
			<!--  網址會變成類似 worpress根目錄網址/wp-admin/options.php 可在這個頁面查詢變數是否有被記錄-->
		</p>
	</form>
</div>
<?php
}
?>

設定頁面寫好之後,如果之後要在本外掛任意地方的程式碼or甚至別支外掛的程式碼(比較不建議),使用設定值都輕鬆容易,只要在php代碼的地方寫上get_option(‘註冊的變數名稱’)就抓的到值囉!

wordpress外掛開發 簡易框架教學

當初自學wordpress外掛的時候遇到不少瓶頸,因為不熟悉wordpress的框架與運作模式,所以在外掛的開發上遇到不少問題,所以才有了撰寫這篇教學的想法,希望可以幫助到想撰寫wordpress外掛卻又不知從何下手的新手們 ,本篇教學是依據我本身開發經驗撰寫而成,觀念上可能有些許錯誤,還請各位多多包涵!

相信大家看教學最在意的就是範例程式碼,畢竟辛辛苦苦地跟著教學做了半天,如果最後弄出來無法執行,應該會很挫折吧!

下面的範例程式碼是經過實測過的,建議小夥伴們先下載下來配合著教學服用

範例程式碼:

https://drive.google.com/file/d/14Awz8BMIZdwPPRxUe1kUflViS6VSN2tL/view?usp=sharing

首先,建立一個外掛的根目錄下一定會有一個php檔,是用來載入這個外掛其他程式碼的切入點,以範例程式碼來說我將它取名為myplugin.php,讓我們先來看這支程式的內容

/*
 * Plugin Name: 外掛名稱
 * Description:外掛名稱 by 開發者名稱
 * Author: 開發者名稱
 * Plugin URI: 網址 不重要
 * Version: 版本(EX:1.0)
 */

//此區域是描述外掛的區域(必填)

//假設我的外掛名稱叫myplugin,我將其簡稱為MP(可依個人喜好)
if(!defined('MP_DIR')){
	define('MP_DIR', dirname(__FILE__));
}
//把MP_DIR定義為本外掛的根目錄,後面要呼叫相對路徑時會方便很多
define('MP_URL', plugin_dir_url(__FILE__));

//這邊要include主要是'後端處理'的php,我習慣將這些放在include資料夾內
function LoadMyplugin_Class(){
	include MP_DIR.'/includes/class_myplugin-main.php';
	include MP_DIR.'/includes/class_myplugin-cofunction.php';
	include MP_DIR.'/includes/class_myplugin-setting.php';
	$GLOBALS['MP']=MP();
}
//我自己會建議至少有這三支程式
//cofunction用來寫共用函式,setting則用來撰寫此外掛的設定頁面,會在之後的教學詳細說明
function MP(){
	return My_Plugin::instance();
}
add_action('plugins_loaded', 'LoadMyplugin_Class');
//綁定action讓wordpress載入本外掛

到這邊外掛的切入點主要就已經完成了,接下來讓我們看include資料夾內主要的class_myplugin-main.php這支程式

if(!class_exists('My_Plugin')):

class My_Plugin{
	public static $_instance=NULL;

	//我的理解是建構子
	function __construct(){
		global $wpdb;//讓外掛可以呼叫wp資料庫函式

		//這邊是判斷當前頁面是不是wp的後台,所以後台所需的東西要在這裡引入
		if(is_admin()){
			add_action('admin_menu', array($this, 'AdminMenu'), 1);
			//在後台頁面的左側加上自己設定的頁面的函式,如果外掛不需要做後台頁面就不用加
		}
		else{
			add_shortcode('mp-extend', array($this, 'RenderShortCode'));
			add_action('wp_head', array($this, 'AddScripts'));
			add_action('wp_head', array($this, 'AddStyles'));
			//這邊我習慣預設這三個
			//RenderShortCode是用來產生短代碼,在用elementor建構頁面時可以把外掛的頁面嵌入在適當的地方
			//AddScripts是用來引入全域會用到的js
			//AddStyles用來引入全域會用到的css
		}

		add_action('wp_ajax_nopriv_MPexecAjax', array($this, 'MPexecAjax'));
		add_action('wp_ajax_MPexecAjax', array($this, 'MPexecAjax'));
		//這邊先簡單說明一下,這兩行是前端用到ajax時url設為 admin_url('admin-ajax.php') 這個位置然後傳送到後端的data內action設為A
		//後端的add_action('wp_ajax_nopriv_A', array($this, 'Afunction'));只要在Afunction內做好對ajax送來的資料的處理就好
		//有興趣的之後會再開文章詳細說明
		//wp_ajax_MPexecAjax跟wp_ajax_nopriv_MPexecAjax的差別是前者是操作者有登入wordpress的情況才有權限
		//後者是沒有登入wordpress的操作者才有權限
		//所以如果是自製的外掛沒有要結合wp的會員機制的話,建議兩個都加比較保險
	}

	function AddScripts(){
		wp_register_script('my-plugin_script', MP_URL.'/js/my-plugin.js');
		wp_enqueue_script('my-plugin_script');

		wp_localize_script(	
			'my-plugin_script', 
			'MP_vars',
			array(
				'imgroot'		=>MP_URL.'/images/', 
				'templateroot'		=>MP_URL.'/templates/', 
				'ajaxurl'		=>admin_url('admin-ajax.php'),
			));
		//這是wordpress傳php值供前端js使用的方式
		//js的呼叫方式是 EX:MP_vars.ajaxurl,MP_vars.imgroot
		//imgroot跟templateroot建議可以先預設好,js在呼叫圖片或是跳轉頁面的時候比較方便
	}

	function AddStyles(){
		wp_register_style('my-plugin_style', MP_URL.'/css/my-plugin.css');
		wp_enqueue_style('my-plugin_style');
	}
    
    //設定後端管理頁面的時候用
	function AdminMenu(){	
		add_menu_page('我的外掛', __('我的外掛'), __('manage_options'), 'my-plugin_main', create_function('', 'require_once \''.MP_DIR.'/templates/my-plugin_admin.php\';'), 'dashicons-nametag', 56);
		// Add to admin_menu
		//是選單旁邊的符號,可以自己更換
		add_submenu_page('my-plugin_main', __('我的外掛功能一'), __('我的外掛功能一'), __('manage_options'), 'my-plugin_func1', create_function('', 'require_once \''.MP_DIR.'/templates/my-plugin_admin_func1.php\';'));
		//若要在主選單下面加上子選單可以使用此語法
		//這邊不是重點先簡易帶過,有興趣可以google add_menu_page跟add_submenu_page會有更詳細的介紹
	}

	public function RenderShortCode($args){
		if(!is_array($args))return;
		switch($args['type']){
			case 'example_page':
				$this->ExamplePage();
				break;
		}
	}
	//[mp-extend type='example_page'] 可在elementor以shortcode的方式直接插入自製頁面或功能
	//這是我目前覺得最好結合elementor的開發方式

	function ExamplePage(){
		include MP_DIR.'/templates/example_page.php';
	}
        //引入該頁面
	//這邊有需求還可引入只有該功能或頁面需要的特定css跟js

	//讓myplugin.php呼叫用
	public static function instance(){
		if(is_null(self::$_instance))self::$_instance=new self();
		return self::$_instance;
	}
}

endif;

這邊其實我多加了很多一般外掛教學沒有的部分,當初開發的時候照著別的外掛教學做完,雖然外掛是可以執行的,但還有許多常用的功能不知道要如何結合,所以這邊就把一些外掛基本上都會使用到的功能結合進來,建議大家可以稍微做修改拿來當作自己開發外掛的基礎模板

細心的小夥伴應該會發現範例程式碼有幾支引用的程式我都先留空,那是因為要在這篇內全部說明完可能會過於複雜,有興趣的人可以關注一下,之後會不定時更新剩餘部分的範例,當然如果對php及前端語言原本就有些底子的人就可以開始用這個框架玩玩看啦!

google recaptcha驗證串接教學

下載recaptcha
https://github.com/google/recaptcha
載完之後放好就可以了,只要記得呼叫相對路徑就好

先引入https://www.google.com/recaptcha/api.js

function LoginForm(){
		wp_register_script('pm-google_script','https://www.google.com/recaptcha/api.js');
		wp_enqueue_script('pm-google_script');
	}

前端html加入

<div class="g-recaptcha" data-callback="captcha_onclick" data-sitekey="your sitekey" style="margin-top:50px;"></div>
				<input type="hidden" name="recaptcha" id="recaptchaValidator" />

js部分

function captcha_onclick() {
	document.getElementById('recaptchaValidator').value = grecaptcha.getResponse();
}

後端驗證時加入

require(PM_DIR.'/recaptcha/src/autoload.php');
//記得改成最前面那包recaptcha的相對路徑
		// _GOOGLE_RECAPTCHA_SEC_KEY 就是 google 給的 Secret Key
		$recaptcha = new \ReCaptcha\ReCaptcha('6LeXo70UAAAAAORn5xn-s9QFPvBwAj2xOQKXhY63');
		$gRecaptchaResponse = $_POST['recaptcha'];
		$remoteIp = $_SERVER['REMOTE_ADDR'];
		$resp = $recaptcha->verify($gRecaptchaResponse, $remoteIp);
		if(!$resp->isSuccess()){
			echo json_encode(array('error'=>'請先證明您不是機器人'));
			exit();
		}else{
                  //驗證成功時做的事情
                }

記得回傳失敗的時候需要做以下處理,否則登入失敗時驗證區塊會卡死

grecaptcha.reset();