Software Development Principles for WordPress Plugins: LoD, SoC, SOLID, and More
Understanding and applying these principles will help you write cleaner, more maintainable WordPress plugin code. Here’s a detailed look at key software development principles with before-and-after PHP examples for WordPress developers:
1. Abstraction
Abstraction allows you to focus on what is necessary and hide underlying complexity. It’s used everywhere, like when WordPress abstracts database interactions through $wpdb.
Before:
global $wpdb;
$results = $wpdb->get_results("SELECT * FROM {$wpdb->prefix}posts WHERE post_status = 'publish'");
foreach ($results as $post) {
echo $post->post_title;
}
After (Abstraction Applied):
function get_published_posts() {
global $wpdb;
return $wpdb->get_results("SELECT * FROM {$wpdb->prefix}posts WHERE post_status = 'publish'");
}
$posts = get_published_posts();
foreach ($posts as $post) {
echo $post->post_title;
}
2. Encapsulate What Varies
Isolate parts of your code that may change so they can be modified without affecting other parts.
Before:
if ($baseCurrency == 'USD' && $targetCurrency == 'EUR') {
return $amount * 0.90;
}
if ($baseCurrency == 'USD' && $targetCurrency == 'GBP') {
return $amount * 0.80;
}
After (Encapsulation Applied):
function convert_currency($amount, $baseCurrency, $targetCurrency) {
$conversion_rates = [
'USD_EUR' => 0.90,
'USD_GBP' => 0.80,
];
$key = $baseCurrency . '_' . $targetCurrency;
return isset($conversion_rates[$key]) ? $amount * $conversion_rates[$key] : $amount;
}
3. DRY (Don’t Repeat Yourself)
Avoid code duplication by reusing common logic through functions or classes.
Before:
$meta_value1 = get_post_meta($post_id, '_meta_key1', true);
$meta_value2 = get_post_meta($post_id, '_meta_key2', true);
$meta_value3 = get_post_meta($post_id, '_meta_key3', true);
After (DRY Applied):
function get_custom_meta($post_id, $keys) {
$meta_values = [];
foreach ($keys as $key) {
$meta_values[$key] = get_post_meta($post_id, $key, true);
}
return $meta_values;
}
$meta_values = get_custom_meta($post_id, ['_meta_key1', '_meta_key2', '_meta_key3']);
4. KISS (Keep It Simple, Stupid)
Avoid complex solutions when simpler ones suffice.
Before (Complex Solution):
function check_user_access() {
if (is_user_logged_in() && current_user_can('manage_options') && !is_admin() && wp_get_current_user()->user_login == 'admin') {
return true;
}
return false;
}
After (KISS Applied):
function check_user_access() {
return current_user_can('manage_options');
}
5. YAGNI (You Aren’t Gonna Need It)
Don’t add features until you actually need them.
Before:
function calculate_price($amount, $tax, $discount = 0, $future_feature = null) {
// Future feature not needed yet
return ($amount + $tax) - $discount;
}
After (YAGNI Applied):
function calculate_price($amount, $tax, $discount = 0) {
return ($amount + $tax) - $discount;
}
6. Law of Demeter (LoD)
Minimize interactions with objects that are not directly related.
Before (Violation):
$wallet_balance = $customer->get_wallet()->get_balance();
After (LoD Applied):
$wallet_balance = $customer->get_wallet_balance(); // Encapsulates wallet access in Customer
7. Separation of Concerns (SoC)
Split your code into distinct sections, each with its own responsibility.
Before (Single Function):
function process_order_and_notify($order_id) {
$order = wc_get_order($order_id);
// Process order logic
wp_mail($order->get_billing_email(), 'Order Update', 'Your order has been processed.');
}
After (SoC Applied):
class OrderProcessor {
public function process_order($order_id) {
$order = wc_get_order($order_id);
// Process order logic
return $order;
}
}
class NotificationSender {
public function send_order_notification($email, $message) {
wp_mail($email, 'Order Update', $message);
}
}
$orderProcessor = new OrderProcessor();
$order = $orderProcessor->process_order($order_id);
$notificationSender = new NotificationSender();
$notificationSender->send_order_notification($order->get_billing_email(), 'Your order has been processed.');
8. SOLID Principles for WordPress Development
class Logger {
public function log($message) {
error_log($message);
}
}
interface Discount {
public function apply($amount);
}
class FixedDiscount implements Discount {
public function apply($amount) {
return $amount - 10; // Fixed discount logic
}
}
class PercentageDiscount implements Discount {
public function apply($amount) {
return $amount * 0.9; // 10% discount logic
}
}
abstract class BaseWidget {
abstract public function render();
}
class TextWidget extends BaseWidget {
public function render() {
echo 'Rendering Text Widget';
}
}
interface Renderable {
public function render();
}
interface Exportable {
public function export();
}
interface DataSource {
public function getData();
}
class DatabaseSource implements DataSource {
public function getData() {
// Fetch data from DB
}
}
class PluginService {
private $dataSource;
public function __construct(DataSource $dataSource) {
$this->dataSource = $dataSource;
}
}
9. GRASP Patterns in WordPress
class PostManager {
public function create_post($title, $content) {
return wp_insert_post(['post_title' => $title, 'post_content' => $content]);
}
}
class AdminController {
public function handle_save_settings() {
// Logic to handle settings save
}
}
class DataHelper {
public function sanitize_input($input) {
return sanitize_text_field($input);
}
}
Conclusion: These principles will help you write better, more maintainable, and scalable WordPress plugins. Mastering them sets you apart as a developer committed to quality and longevity in your code.