2024年3月23日 星期六

網站 / 改善wordpress網站的效能

之前網站因為增加了許多自訂的發文推播

導致網站速度變慢,GCP的VM觀測數據顯示發文的時候,CPU的執行率可以達到200%

所以也出現提升CPU等級的建議,但是往上升一級就多了近一倍的費用

對我來說實在吃不消,因為除了GCP的費用之外,還有youtube的月費、google 雲端硬碟的年費

一年付給google公司7~8千元跑不掉,GCP費用占了80%

當初建置網站的目的是為了紀錄一些學習程式的過程,順便紀錄自己感興趣的東西

所以想先試試看能不能透過一些方式來降低網站的執行負荷量

之前為了增加特定功能,會嘗試不同的外掛,從中挑選最適合的

但是其他的外掛,我通常只是設定成未啟用,沒有刪除

不過為了網站效能,這次刪除了所有沒有啟用、或者用不到的外掛

另外還進行了兩個改變

第一個是整併推播外掛程式

因為都是同一個觸發事件,這樣會導致網站同時執行多個程式

所以我把這些通通整併成一個程式

也就是事件觸發之後,Line、Blogger、facebook的推播都是接續處理

不再分開(卻可能同時)處理

也因為這些推播都是向外發出請求

都是非同步執行,所以每個部分都暫停5秒鐘才接續往下執行

剛好跟一般認知的概念相反,這裡是指各個程式的執行是各做各的

不會等其他程式完成,再進行下一個

第二個是不在網站的編輯器撰寫文章

後來發現在網站的編輯器撰寫文章,也會導致網站的負荷量飆高

所以我嘗試改成先在其他網頁編輯器完成內容,再將html格式的內容貼回去

之前一直使用的線上網頁編輯器,使用了CKEditor4的編輯器

出於好奇,查看了網站的程式碼,發現其實引用的方式很簡單

所以我自己也炮製了一個線上網頁編輯器

目前CKEditor除了4之外,最新的是5

不過CKEditor5是node架構了,而且好像也沒有免費授權的版本

而CKEditor4 除了LTS(Long-term support,長期支援)版本需要授權之外

其他版本都是可以免費使用,所以我引用了最後的4.22.1


目前這些方法似乎有效果,即使網站發文的時候,CPU執行率也沒有超過100%了

2024年3月18日 星期一

VBA / 使用Excel VBA批次寄信 3

之前在VBA / 使用Excel VBA批次寄信 是修改 彰化一整天所寫的excel VBA程式
而這個版本是精簡程式,原理是一樣的,都是使用 CDO.Message物件
但是省去了設定頁面,呈現核心程式
只要知道STMP的設定資料
各個郵件伺服器應該都可以使用
本文以Gmail為範例

1.取得google應用程式密碼

google為了保護帳戶安全性
之前可以用低安全性設定來使用帳密連線SMTP
不過現在這個設定應該已經無法使用了
必須要設定並開啟兩步驟驗證 然後設定應用程式密碼,取代原本的帳號密碼
這組密碼是隨機產生的16位英文字母 換言之,就是改用隨機密碼取代原始密碼
而這組隨機密碼只能用在一種googgle應用程式
例如:當密碼第一次使用是用在gmail登入,之後就只能用在登入gmail,不能一組密碼用遍所有google功能
設定流程可以參考google文件說明,不知道之後會不會又改安全性設定

2.CDO.Message的參數設定

宣告Mail變數,使用晚期繫結的方式建立CDO.Message
再用Configuration.Fields.Item 設定參數
  Dim Mail As Object
  Set Mail = CreateObject("CDO.Message")
  With Mail.Configuration.Fields
      .Item("http://schemas.microsoft.com/cdo/configuration/smtpusessl")= True
      .Item("http://schemas.microsoft.com/cdo/configuration/smtpauthenticate")= 1
      .Item("http://schemas.microsoft.com/cdo/configuration/smtpserver")= "smtp.gmail.com"
      .Item("http://schemas.microsoft.com/cdo/configuration/smtpserverport")= 465
      .Item("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2
      .Item("http://schemas.microsoft.com/cdo/configuration/sendusername")= "goohle帳號"
      .Item("http://schemas.microsoft.com/cdo/configuration/sendpassword")= "google程式密碼"
      .Update
  End With

3.郵件設定

  With Mail
    .Subject = "VBA透過gmail寄mail"
    .From = "XXX@gmail.com"
    .To = "YYY@gmail.com"
    .CC = "ZZZ@gmail.com"
    .HTMLBody = "<h1>test 測試</h1>"
    .HTMLBodyPart.Charset = "utf-8"
    .Send
  End With

基本上,這樣程式就能夠使用Gmail帳號寄出信件了
其他的可以再依據需求來細部設定的
像是郵件內容,可以是純文字,也可以是Html格式
也可以增加附件檔案
要批量寄信就可以連結工作表以迴圈方式執行

2024年3月15日 星期五

JS / 在Blogger增加”分享到臉書”功能

之前在網站 / 從wordpress發佈新文章同步發文到臉書粉絲專頁提到
臉書只能夠用分享的方式將訊息貼到個人頁面
於是,開始思考如何在Blogger達成這個效果
(雖然後來發現Blogger的佈景主題有這個功能...)

思路如下  

1.臉書分享的功能

這個可以參考臉書的官方文件-分享對話方塊

2.開啟新視窗,而不是新頁籤

想要達成的效果是點選圖檔,能夠開新視窗 如果單純用超連結,瀏覽器會開啟新頁籤
在這篇文章笨問題 - window.open() 有時在新頁籤有時在新視窗開啟提到
4.若同時指定 width/height,所有瀏覽器都會依指定寬度及高度開啟新視窗
同時為了讓開啟的新視窗緊鄰圖片,所以需要取得圖片的位置
這個參考了使用 Javascript 取得元素的座標的程式碼
程式碼如下,因為是在CodePen執行,會被臉書封鎖,不過整個流程是預期的 

See the Pen blogger fb 開新視窗 by 莊幸諺 (@trico109748007) on CodePen.

3.如何在Blogger透過圖像觸發

這裡有個知識點:如何判斷點選的是哪一個元素
(雖然不太懂觸發的原理...為什麼用立即函式可以達成這樣效果)
於是在文章的結構新增了一個span>a>img>的節點,原理跟JS / 在Blogger增加"修改"連結標籤-1.取得postID 一樣
並且在a標籤內增加了一個名稱為a2_fb的class讓程式判斷是哪一個被觸發
然後將相關的參數送到window.open()

See the Pen 判斷是哪一個DIV被觸發 by 莊幸諺 (@trico109748007) on CodePen.



  1. <script>
  2. function getPosition(element) {
  3.   var x = 0;
  4.   var y = 0;
  5.   while (element) {
  6.     x += element.offsetLeft - element.scrollLeft + element.clientLeft;
  7.     y += element.offsetTop - element.scrollLeft + element.clientTop;
  8.     element = element.offsetParent;
  9.   }
  10. return {
  11.   x: x,
  12.   y: y
  13.   };
  14. }
  15. var fb = document.getElementsByClassName('a2_fb');
  16. for (var i = 0; i < fb.length; i++) {
  17.   (function(i) {
  18.     fb[i].addEventListener('click', function(e) {
  19.       e.preventDefault();
  20.       var position = getPosition(this);
  21.       window.open(fb[i].href, '分享到臉書', config = `height=900,width=800,left= ${position.x}    ,top=${position.y} `); //引用變數的寫法 ES6 模板文字
  22.       }, false);
  23.   })(i)
  24. }
  25. </script>
 最後,程式碼還是要依靠Html/Javascipt小工具來執行

執行的畫面





2024年3月14日 星期四

JS / 移除或修改 iframe的屬性

前幾天辦公室裡其他計畫的助理
抱怨網站嵌入的google表單出現

「您的瀏覽器尚未啟用javascript...」


經詢問網站維護廠商,說因為資安掃描被列為需改善的漏洞
不過之前的表單都是正常
所以我比較了前後網頁的html內容

原來後面的表單iframe增加了sandbox標籤

我因為無聊想試試看能不能移除或修改snadbox標籤
一開始是在chrome按F12,直接編輯html
但是沒有效果,用關鍵字爬文之後
才知道已經載入的iframe是不會有任何影響

移除或修改sandbox之後必須再重新載入iframe

所以現在問題變成:如何移除或修改sandbox之後,再重新載入iframe,卻又不會重新載入原本網頁
不然原本網頁跟著重載入,又會載入原本的iframe,等於白做工
不過不是被打勾的回答,reload()會無法執行
document.getElementById('some_frame_id').contentWindow.location.reload();
而是再下一個回覆內容,重新指定iframe src的屬性值,iframe就會馬上重新載入
document.getElementById('iframeid').src =
document.getElementById('iframeid').src
接下來是如何在頁面執行javascript
我想到之前用來移除某些網站鎖右鍵功能的方式

用書籤輸入程式碼來執行javascript

將以下程式碼輸入在網址即可
javascript: (function () {  var link = document.querySelector("iframe"); link.setAttribute("sandbox","allow-same-origin allow-scripts
allow-popups allow-forms"); link.src = link.src; })();
  1. javascript: (
  2. function () {
  3. var link = document.querySelector("iframe");
  4. link.setAttribute("sandbox","allow-same-origin allow-scripts allow-popups allow-forms");
  5. link.src = link.src;
  6. }
  7. )();
  
最後,測試是可以執行的
不過後來廠商也修改sandbox的屬性值
開放可以執行表單功能~~~~

2024年3月8日 星期五

網站 / 從wordpress發佈新文章同步發文到臉書粉絲專頁

既然可以透過寄信到Blogger發文 
那有沒有可能在臉書粉絲專頁貼文?
答案是可以的!! 
接下來可能會問:有沒有可能在個人臉書貼文 
可惜答案是不可能~~,
但是可以用分享的方式

臉書已經算是商業平台了,社交只是功能之一 
粉絲頁的功能主要是為了跟成員互動,所以功能比較豐富 
可以透過Facebook 粉絲專頁 API 來貼文

臉書提供的範例剛好就是PHP語言

  1. curl -X POST "https://graph.facebook.com/v19.0/page_id/feed" \
  2.      -H "Content-Type: application/json" \
  3.      -d '{
  4.            "message":"your_message_text",
  5.             "link":"your_url",
  6.             "published":"false",
  7.             "scheduled_publish_time":"unix_time_stamp_of_a_future_date",
  8.             }'
 
臉書的說明如下: 
若要發佈貼文至粉絲專頁,請傳送 POST 要求至 /page_id/feed 端點(其中 page_id 為粉絲專頁編號),並使用下列參數:
  • message 設為貼文的文字
  • link 設為您的網址(若要張貼連結)
  • published 設為 true 以立即發佈貼文(預設),或設為 false 以稍後發佈。
    • 若設為 false,請包含 scheduled_publish_time,並使用下列任一日期格式:
      • 整數 UNIX 時間戳記(以秒為單位),例如 1530432000
      • ISO 8061 時間戳記字串(例如 2018-09-01T10:15:30+01:00)
      • 可用 PHP 語言 strtotime() 解析的字串(例如 +2 weeks、tomorrow)
可以知道要用POST方法傳遞Json格式的資料 資料內要有:message、link、published

不過如果按照這個範例程式是無法在執行的,會有2個問題

1.執行這樣的curl 指令,必須經過轉譯

但是wordpress不能轉譯,而且wordpress有自己的函式wp_remote_post()

2.資料,少了重要的應用程式API編號:access_token

這個取得流程可以參考:Facebook粉專自動發文以及留言API 
在多次嘗試以及餵狗之後,最後可以執行的程式碼如下 
整體程式碼的架構跟之前的同步寄信到Blogger基本相同,都是藉由wordpress本身的觸發函示來執行相關程式碼

程式碼

  1. //
  2. function post_fb($new_status, $old_status, $post){
  3.     $postOne = get_post($post);
  4.     $postUrl = get_permalink($post);
  5.     $postBody= $postOne->post_content;
  6.     $postExcerpt= $postOne->post_excerpt; /* 文章摘要 */
  7.     $titleOne = $postOne->post_title;
  8.     $author = $post->post_author; /* Post author ID. */
  9.     $name = get_the_author_meta( 'nickname', $author );
  10.  
  11. //判斷文章狀態
  12. if ( $new_status == "publish" && $old_status !== "publish" && $post->post_type == "post")
  13.   {
  14.     $endpoint = 'https://graph.facebook.com/v19.0/*********粉絲頁編號**********/feed';
  15.  
  16.     $body = [
  17.                'message' => $postExcerpt, /* 文章摘要 */
  18.                'link' => $postUrl,
  19.                'published' => 'true',
  20.                'access_token' =>'---取得的長期權杖---'
  21.             ];
  22.  
  23.     $body = wp_json_encode( $body );
  24.  
  25.     $options = [
  26.                 'body' => $body,
  27.                 'headers' => [
  28.                 'Content-Type' => 'application/json',
  29.               ],
  30.               'timeout' => 60,
  31.               'redirection' => 5,
  32.               'blocking' => true,
  33.               'httpversion' => '1.0',
  34.               'sslverify' => false,
  35.               'data_format' => 'body',
  36.               ];
  37.  
  38.     wp_remote_post( $endpoint, $options );
  39.   }
  40.  
  41. }
  42. add_action('transition_post_status','post_fb',10,3);
 
主要的程式碼是#14~39,執行wp_remote_post()的參數設定 
$endpoint 是要發出請求的網址 
$body是陣列,架構為 key => value,之後用 wp_json_encode()轉為Json 
$options是要帶入wp_remote_post()的參數陣列

後續編寫貼文的調整

過往沒有寫「 內容摘要」

但是為了讓分享內容時可以帶入訊息,所以要把寫在粉絲頁的訊息寫入摘要

 
程式裡的$postExcerpt就是用來接收文章的摘要 
這應該是最簡單的方式 原本想嘗試能不能跳出一個訊息框,將訊息輸入後帶回程式 
但是光想就很麻煩

備註

本篇文章發布之後,也同時貼文在粉絲頁

但是好像因為同時發文又寄信
導致網站速度變得很慢...
 

2024年3月5日 星期二

網站 / 從wordpress發佈新文章同步寄信到blogger儲存成草稿

google blogger可以接收電子郵件來發佈文章

當然這個電子郵件不是自己的gmail,而是指定的用於貼文的電子信箱

格式是google帳號名稱.自訂文字@blogger.com

因此,嘗試從wordpress發佈新文章,同步寄信到blogger設定的專用信箱來發佈草稿(因為通常會跑版,而且需要手動設定標籤)

這個可以透過add_action()勾點 transition_post_status事件來觸發郵寄文件的函式

所以可以修改 網站 / LINE Notify 推播其中的發佈新文章程式碼

程式碼的說明如下:

#3~23 自定義的發佈郵件函式 function send_email()

其中的#5是用來篩選 ‘wp_mail_content_type’ 資料,透過自訂的函式wpdocs_set_html_mail_content_type()

將預設的text/plain 轉換為’text/html

當郵件發出之後,再透過 #22刪除篩選器,回復成預設值

這個是參考WordPress Developer Resources的範例

不過後來沒有用到

因為原本的流程是將wordpress的文章,以html格式寄到blogger

但是,在blogger的編輯器會再解析一次內文,內容不是跑板就是有莫名的解析

例如: XXX.yyy,會加上a標籤變成超連結

於是改以純文字格式傳出html字串,之後再從編輯器貼到HTML編輯器

#7~12是文章的資料

#15~20 判斷文章的狀態,當文章的狀態從不是發佈狀態改變成發佈狀態才執行 wp_mail()

#17~19 是郵件的設定值,會傳入wp_mail()

#24 增加勾點 add_action()

當網站發佈新文章時,將文章資訊輸入並執行function send_email()

#26~27 function wpdocs_set_html_mail_content_type()

在#5要觸發用來修改wp_mail_content_type的函式

  1. //發佈文章的通知
  2. //
  3. function send_email($new_status, $old_status, $post){
  4. //修改內文格式為text/html
  5. //add_filter( ‘wp_mail_content_type’, ‘wpdocs_set_html_mail_content_type’ );
  6.  
  7.     $postOne = get_post($post);
  8.     $postUrl = get_permalink($post);
  9.     $postBody= $postOne->post_content;
  10.     $titleOne = $postOne->post_title;
  11.     $author = $post->post_author; /* Post author ID. */
  12.     $name = get_the_author_meta( ‘nickname’, $author );
  13.  
  14. //判斷文章狀態
  15.     if ( $new_status == “publish” && $old_status !== “publish” && $post->post_type == “post”)
  16.   {
  17.     $to = ‘trico109748007.**************@blogger.com’; $subject = ‘莊生趣味發佈-‘.$titleOne; $message = $postBody;
  18.     $headers = ‘From:莊生趣味<trico109748007@gmail.com>’;
  19.     wp_mail( $to, $subject, $message, $headers );
  20.   }
  21. //移除格式設定,回復成預設格式 text/plain
  22. //remove_filter( ‘wp_mail_content_type’, ‘wpdocs_set_html_mail_content_type’ );
  23. }
  24. add_action(‘transition_post_status’,‘send_email’,10,3);
  25.  
  26. function wpdocs_set_html_mail_content_type() {
  27.   return ‘text/html’;
  28. }
 

如果網站本來就可以正常發出郵件的話,增加以上程式碼

當發佈新文章之後,就會將文章寄到blogger接收郵件的信箱,並存成草稿

可以使用WP Mail Logging查看紀錄,不過有時候會沒有紀錄,不知道是不是文章主旨太長的緣故?