感覺我們接觸到的一切都是經過精心設計的:網站、電話、地鐵地圖等等。即使是我們過去認為理所當然的東西:恒溫器、煙霧探測器和汽車儀表板現在也得到了仔細的用戶體驗處理。
設計不僅僅是外觀和感覺:它還需要考慮用戶與我們的設備/工具/屏幕/對象交互所需的各種方式。
這也適用于編程。
(未)設計的編程
編程語言是一個龐大而復雜的世界。即使是許多編程勢利小人認為太“簡單”的 php,實際上也是函數和類的相當復雜的組合,其行為方式非常不一致。
多年來,語法、方法和命名在數百萬不同的用戶和應用程序中不斷發展。大多數傾向于反映內部的底層構造 – 不一定是您想要如何使用它。
API 設計的偉大時刻:jquery
??>
當我在 2006 年左右開始編寫 JavaScript 時,情況一團糟。以下是我如何找到具有特定類的標簽并將其在 dom 中移動的方法:
var uls = getElementsByTagName("ul"); var classToSearch = "foods"; for (var i = 0; i <p>完成!</p> <p>jQuery 讓 JavaScript 再次變得有趣。在 2000 年代末,這種影響是如此巨大,以至于我記得我父親問我他在《華爾街日報》上讀到的“一些奇怪的事情”。但盡管效果巨大,jQuery 并沒有為 JavaScript 添加任何“新功能”。它只是將開發人員必須做的事情分解為非常清晰的模式。</p> <p>他們沒有重新發明如何在頁面上查找內容,而是利用了人們已經知道的東西:css 選擇器。然后,只需收集大量常見操作并將它們組織成幾十個函數即可。讓我們再次嘗試前面的示例,現在使用 jQuery:</p> <pre class="brush:javascript;toolbal:false;">var $li = $('
‘); $(“ul.foods”).append($li);
2006 年,我買了一本 680 頁的 ajax 書籍。有了 jQuery 出色的 API,它幾乎被這個取代了:
$.post();
WordPress API
雖然 API 已經開始代表“第三方服務”,但它僅僅意味著與系統對話的編程接口。就像 Twitter API 或 Facebook API 一樣,WordPress API 也存在。您不會進行原始數據庫查詢來創建帖子,對吧?您使用 wp_insert_post。
但是許多設計漏洞困擾著 WordPress API。您可能使用 get_the_title 但 get_the_permalink 會生成錯誤,您使用 get_permalink 。嘿,當您有一個長達數十年的開源項目,涉及數千人的代碼和數百萬用戶時:您會遇到一些怪癖。
通過掩蓋這些怪癖并根據您正在編寫的程序員(可能是您)的習慣和行為進行編寫,您可以節省大量時間。您可以在這里設計正確的界面來對您日常使用的插件和主題進行編程。
解決方案
為了加快工作速度并減少重復性任務,我創建了庫來處理我一直需要的命令和自定義設置。
1。常見任務的快捷方式
以獲取帖子縮略圖的來源為例。事實證明,WordPress 沒有內置功能來根據帖子 ID(僅附件 ID)獲取縮略圖。
這意味著我經常發現自己這樣做:
$thumb_id = get_post_thumbnail_id( get_the_ID() ); $src = wp_get_attachment_thumb_url( $thumb_id ); echo '@@##@@';
但是一定有更好的方法!
function get_thumbnail_src( $post ){ $thumb_id = get_post_thumbnail_id( $post ); $src = wp_get_attachment_thumb_url( $thumb_id ); return $src; } echo '@@##@@';
2:不可預測的輸入,可預測的輸出
好多了!事實上,您發現自己一直在使用它,然后與公司的其他開發人員共享。
你的朋友遇到了麻煩,所以他打電話給你來調試,你看到:
echo '@@##@@';
看來他不小心使用了 get_post?而不是 get_the_ID。你對他大喊大叫。但是等一下,為什么不讓它更容易被接受呢?
也許我們可以調整我們的函數,以便它可以采用 WP_Post 對象,并且仍然為用戶提供他們所期望的內容。讓我們回到該函數:
function get_thumbnail_src( $post ){ if ( is_object( $post ) && isset( $post->ID ) ){ $post = $post->ID; } else if ( is_array( $post ) && isset( $post['ID'] ) ) { $post = $post['ID']; } $thumb_id = get_post_thumbnail_id( $post ); $src = wp_get_attachment_thumb_url( $thumb_id ); return $src; }
因此,如果他們發送 WP_Post 對象或一個數組,您的函數仍然可以幫助他們獲得所需的內容。這是成功 API 的重要組成部分:隱藏混亂的內部結構。您可以為 get_thumbnail_src_by_post_id 和 get_thumbnail_src_by_wp_post_object. 制作單獨的函數
事實上,對于更復雜的轉換可能更可取,但是您可以通過將單個函數路由到正確的子例程來簡化界面。無論用戶發送什么內容,該函數都會始終返回圖像源的字符串。
讓我們繼續:如果他們什么也沒發送怎么辦?
3。合理的默認值
function get_thumbnail_src( $post = false ) { if ( false === $post ) { $post = get_the_ID(); } else if ( is_object( $post ) && isset( $post->ID ) ) { $post = $post->ID; } else if ( is_array( $post ) && isset( $post['ID'] ) ) { $post = $post['ID']; } $thumb_id = get_post_thumbnail_id( $post ); $src = wp_get_attachment_thumb_url( $thumb_id ); return $src; }
我們再次進行了簡化,因此用戶無需發送帖子,甚至無需發送帖子 ID。在循環中時,所需要做的就是:
echo '@@##@@';
我們的函數將默認為當前帖子的 ID。這正在變成一個非常有價值的功能。為了確保它能很好地發揮作用,讓我們將它包裝在一個類中,這樣它就不會污染全局命名空間。
/* Plugin Name: JaredTools Description: My toolbox for WordPress themes. Author: Jared Novack Version: 0.1 Author URI: http://upstatement.com/ */ class JaredsTools { public static function get_thumbnail_src( $post = false ) { if (false === $post ) { $post = get_the_ID(); } else if ( is_object( $post ) && isset( $post->ID ) ) { $post = $post->ID; } else if ( is_array( $post ) && isset( $post['ID'] ) ) { $post = $post['ID']; } $thumb_id = get_post_thumbnail_id( $post ); $src = wp_get_attachment_thumb_url( $thumb_id ); return $src; } }
并且請不要在您的類前面添加 WP。我將其設為公共靜態函數,因為我希望它可以在任何地方訪問,并且它不會改變:輸入或執行不會更改函數或對象。
該函數的最終調用是:
echo '@@##@@';
先設計,后構建
讓我們繼續處理更復雜的需求。當我編寫插件時,我發現我總是需要生成不同類型的錯誤和/或更新消息。
但是基于事件的語法一直困擾著我:
add_action( 'admin_notices', 'show_my_notice'); functon show_my_notice(){ echo '<div class="updated"><p>Your thing has been updated</p></div>'; }
WordPress 遵循這種基于事件的架構有很多充分的理由。但這并不直觀,除非您想坐下來記住不同的過濾器和操作。
讓我們將此匹配作為最簡單的用例:我需要顯示管理員通知。我喜歡首先設計這個 API:我找出在代碼中引用該函數的最佳方式。我希望它讀起來像這樣:
function thing_that_happens_in_my_plugin($post_id, $value){ $updated = update_post_meta($post_id, $value); if ($updated){ JaredsTools::show_admin_notice("Your thing has been updated") } else { JaredsTools::show_admin_notice("Error updating your thing", "error"); } }
一旦我設計了端點,我就可以滿足設計要求:
class JaredsTools { public static function show_admin_notice($message, $class = 'updated'){ add_action('admin_notices', function() use ($message, $class){ echo '<div class="'.$class.'"><p>'.$message.'</p></div>'; }); } }
好多了!現在我不需要創建所有這些額外的函數或記住瘋狂的鉤子名稱。在這里,我使用 PHP 匿名函數(也稱為“閉包”),它讓我們可以將函數直接綁定到操作或過濾器。
這可以讓您避免在文件中出現大量額外的函數。 use 命令讓我們將參數從父函數傳遞到子閉包中。
保持直覺
現在另一位同事打電話給您。她不知道為什么她的管理通知沒有變成紅色:
JaredsTools::show_admin_notice("Error updating your thing", "red");
這是因為她正在發送“紅色”(她希望將盒子變成紅色),而實際上她應該發送觸發紅色的類名稱。但為什么不讓它變得更容易呢?
public static function show_notice( $message, $class = 'updated' ) { $class = trim( strtolower( $class ) ); if ( 'yellow' == $class ) { $class = 'updated'; } if ('red' == $class ) { $class = 'error'; } add_action( 'admin_notices', function() use ( $text, $class ) { echo '<div class="'.$class.'"><p>' . $text . '</p></div>'; }); }
我們現在已經接受了更多的用戶容忍度,這將使我們在幾個月后回來使用它時更容易分享。
結論
在構建了其中一些之后,以下是我學到的一些原則,這些原則使這些原則對我和我的團隊真正有用。
1.首先進行設計,讓函數的構建符合人們想要使用它的方式。
2. 拯救你的鍵盤!為常見任務創建快捷方式。
3. 提供合理的默認值。
4. 保持最小化。讓您的庫來處理處理。
5. 對輸入要寬容,對輸出要精確。
6. 也就是說,使用盡可能少的函數參數,最多四個是一個很好的參數。之后,您應該將其設為選項數組。
7. 將您的庫組織成單獨的類,以涵蓋不同的領域(管理、圖像、自定義帖子等)。
8. 包含示例代碼的文檔。
在 Upstatement,我們的 Timber 庫使構建主題變得更加容易,而 Jigsaw 提供了節省時間的快捷方式來自定義每個安裝。
這些工具節省的時間讓我們可以花更多時間構建每個網站或應用程序的新的和創新的部分。通過執行深奧的命令(例如向管理帖子表添加一列)并制作簡單的界面:我們公司的任何設計師或開發人員都可以使用與專業 WordPress 開發人員相同的能力完全自定義每個網站。