by shewa | Sep 15, 2024 | Workflow
This blog post will guide you through setting up an automated workflow to deploy your WordPress plugin to the official WordPress plugin SVN repository directly from GitHub. Using GitHub Actions, you can streamline the release process every time a new tag is pushed to your GitHub repository. Let’s create a build-and-deploy-to-svn.yml
file inside your Github repository/.github/workflows directory. Now, let’s follow the following steps:
1. Naming the Workflow
name: Build and Deploy to SVN
This defines the name of the workflow. It will appear under this title in the GitHub Actions tab, making it easy to identify the deployment workflow among others.
2. Triggering the Workflow on Tag Push
on:
push:
tag:
- "*"
This section specifies that the workflow will be triggered whenever a new Git tag is pushed to the repository. The - "*"
part means the workflow will run on any tag, no matter the version or format. This is useful when you want to deploy a specific version of your plugin (e.g., v1.0.0
) to the WordPress SVN.
3. Defining the Job
jobs:
build:
runs-on: ubuntu-latest
Here, we define a job called build
, which runs on the latest Ubuntu environment provided by GitHub. This is the virtual machine where all subsequent steps will be executed.
4. Checkout Repository
steps:
- name: Checkout repository
uses: actions/checkout@v4
This step checks out your GitHub repository so that the workflow can access the code. The actions/checkout@v4
action is a standard utility to fetch the repository’s content.
5. Set up Node.js
- name: Set up Node.js
uses: actions/setup-node@v2
with:
node-version: '16.17.0'
In this step, Node.js is installed on the virtual machine. The version 16.17.0
is specified here (use whatever version you need), ensuring compatibility with the plugin’s build tools. This is important if your plugin uses Node.js-based tooling like Webpack or Gulp for compiling assets.
6. Install Plugin Dependencies
- name: Install dependencies
run: npm install
This command installs the required npm dependencies for building your plugin. The --legacy-peer-deps
flag is used to bypass potential issues with peer dependencies, which can occur with newer versions of npm.
7. Install Composer
- name: Install Composer
run: sudo apt-get update && sudo apt-get install -y composer
WordPress development often relies on PHP packages, which are managed by Composer. This step installs Composer, making it available for use in the plugin’s build process.
8. Install WP-CLI
- name: Install WP CLI
run: |
curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
chmod +x wp-cli.phar
sudo mv wp-cli.phar /usr/local/bin/wp
wp --info
WP-CLI is a command-line interface that allows interaction with WordPress. This step downloads and installs WP-CLI. The chmod +x
command makes it executable, and wp --info
verifies that it has been successfully installed by displaying WP-CLI version and environment information.
9. Build the Plugin
- name: Build Plugin
run: npm run build
In this step, the plugin’s build process is executed by running the npm-run-build
script. This script is typically defined in your package.json
file and may include tasks like compiling assets, bundling code, or preparing the plugin for distribution.
10. Deploy the Plugin to WordPress SVN
- name: WordPress Plugin Deploy
id: deploy
uses: 10up/action-wordpress-plugin-deploy@stable
with:
generate-zip: true
env:
SVN_USERNAME: ${{ secrets.SVN_USERNAME }}
SVN_PASSWORD: ${{ secrets.SVN_PASSWORD }}
BUILD_DIR: build
This is the core of the deployment process. The 10up/action-wordpress-plugin-deploy@stable
action is a predefined GitHub Action built specifically to handle WordPress plugin deployments to the SVN repository.
generate-zip: true
tells the action to generate a ZIP file of the plugin, which is necessary for deploying to SVN.
SVN_USERNAME
and SVN_PASSWORD
are pulled from GitHub Secrets to securely authenticate with the WordPress SVN repository.
BUILD_DIR
is the directory where your built plugin resides. In this case, it’s set to build
, which should match the output folder of your build process.
11. Create GitHub Release
- name: Create GitHub release
uses: softprops/action-gh-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
After deploying to SVN, this step creates a new release in your GitHub repository. It uses the softprops/action-gh-release@v1
action, which automatically tags and releases the current build as a GitHub release. The GITHUB_TOKEN
is securely pulled from GitHub Secrets for authorization.
Summary
This workflow provides a powerful, automated way to deploy your WordPress plugin to the official WordPress plugin repository from GitHub. Each time you push a new version (via a Git tag), this workflow:
- Checks out your code from the repository.
- Installs necessary build tools and dependencies.
- Builds your plugin.
- Deploys it to the WordPress SVN repository.
- Creates a new GitHub release.
By automating the deployment process, you reduce the risk of manual errors and save time when releasing new versions of your plugin.
I am professional Web Designer & Developer. I have 5+ years of experience in relevant field. Currently I am working for a private software company named “Ollyo” as a Senior Staff Software Engineer.
by shewa | Apr 2, 2023 | OOP, PHP
OOP is a programming paradigm that computer programmers must encounter in their life. This article assumes you are already familiar with Class & Objects. To enhance your OOP understanding four pillars are worth discussing. So, let’s jump into the details:
Inheritance
The very first pillar is inheritance & it’s totally connected with the real world. As we know, if a father has property then his son will inherit it. And yes every child is going to inherit it. In programming, inheritance complies with the same concept. Let’s see in the code:
class Father {
public $name = "Sr. John Doe";
public function totalProperty() {
return "USD 1000000";
}
}
class Son extends Father {
public $name = "John Doe";
}
$son = new Son();
echo "{$son->name} inherit {$son->totalProperty()}";
Output: John Doe inherit USD 1000000
Here, we can see the Son class extends the Father class & a $son object. Though the Son class doesn’t contains the totalProperty() method still we can call it by using the son object, this is because of inheritance that has been done using the keyword extends! So if a class extends to another class then we call this class a child class & the main class (Father) is called a parent class. In a simple sense, this is inheritance. The child class will inherit all the properties & methods from the parent class except private data.
Polymorphism
At its base, polymorphism refers to many forms, but that’s not very helpful unless you understand it in the context of OOP. The real value of polymorphism is that objects with the same interface can be called to do different things. In a large complex structure (a great big program), additions and changes can blow the hinges off your program unless it has a common interface (from a parent class or interface). For example, the following program has two classes that share a common interface. The implementations of the interface are quite different:
interface ISpeed
{
public function speed();
}
class Jet implements ISpeed
{
public function speed(){
return 2500;
}
}
class Car
{
public function speed() {
return 100 + 50;
}
}
$jet = new Jet();
echo "Jet speed is {$jet->speed()} <br>";
$car = new Car();
echo "Car speed is {$car->speed()}";
Output: Jet speed is 2500
Car speed is 150
The two implementations of the ISpeed interface by the Jet and Car classes are very different. However, when making changes or additions within a given structure of a program, I can request or use the interface methods without having to worry about whether my program will crash or not.
One Name with Many Implementations
The easiest way to understand polymorphism is in the different implementations of an interface. The Jet class simply implements each method to return a primitive value, and the Car class makes an addition and then returns a value. Both used the same interface.
Encapsulation
In the previous two examples of inheritance & polymorphism, we have created classes & keep properties and methods inside them. This is basically called encapsulation! Yeah, as simple as it sounds. The term encapsulation simply makes things compact and hides unnecessary details. By using encapsulation, we can set visibility to expose information as per need & making staff secure. If we didn’t wrap properties & methods then it could be accessible from anywhere & it would be unorganized & unmanageable.
Class Abstraction
Abstraction in the real world
I’m a coffee addict. So, when I wake up in the morning, I go into my kitchen, switch on the coffee machine and make coffee. Sounds familiar?
Making coffee with a coffee machine is a good example of abstraction.
You need to know how to use your coffee machine to make coffee. You need to provide water and coffee beans, switch them on, and select the kind of coffee you want to get.
The thing you don’t need to know is how the coffee machine is working internally to brew a fresh cup of delicious coffee. You don’t need to know the ideal temperature of the water or the amount of ground coffee you need to use.
Someone else worried about that and created a coffee machine that now acts as an abstraction and hides all these details. You just interact with a simple interface that doesn’t require any knowledge about the internal implementation.
Abstraction in OOP
Objects in an OOP language provide an abstraction that hides the internal implementation details. Similar to the coffee machine in your kitchen, you just need to know which methods of the object are available to call and which input parameters are needed to trigger a specific operation. But you don’t need to understand how this method is implemented and which kinds of actions it has to perform to create the expected result.
abstract class CoffeeMachine {
// Child class must have to follow method signature
public abstract function getBeans(): string;
// Child class must have to follow method signature
public abstract function getMilk(): string;
// Making Coffee
public function makeCoffee() {
$beans = $this->getBeans();
$milk = $this->getMilk();
return 'Hot Cappucino!!!';
}
}
class CoffeeApp extends CoffeeMachine {
private $beans;
private $milk;
public function __construct($beans, $milk) {
$this->beans = $beans;
$this->milk = $milk;
}
public function getBeans(): string {
return $this->beans;
}
public function getMilk(): string {
return $this->milk;
}
}
// Client don't need to know coffee is getting ready
// They just need to pass beans & milk
$coffeeApp = new CoffeeApp('beans', 'milk');
echo $coffeeApp->makeCoffee();
Output: Hot Cappucino!!!
Yeah, as a coffee lover, we do care about the output 😀 not what is happening inside the machine!
I am professional Web Designer & Developer. I have 5+ years of experience in relevant field. Currently I am working for a private software company named “Ollyo” as a Senior Staff Software Engineer.
by shewa | Nov 30, 2022 | Data Security, WordPress
Data sanitization is crucial in WordPress. Even this is an essential security measurement. Every data from the user’s input must be sanitized as early as possible. WordPress provides many helper functions for data sanitization you can find here. Very easy & handy function! But the real scenario may not be straightforward.
What if we need to sanitize form data having a large set of data & sanitizing one by one field may feel cumbersome? So, to get rid of this we can create a helper function that can loop through all the array elements and sanitize them one by one for us. But a little gotcha here! Of course, we may not use the same sanitization function for each field. For example: for email sanitization, we need to use sanitize_email while for the post we will use wp_kses_post.
So let’s fix the above-discussed problem:
/**
* Sanitize array, single or multi dimensional array
* Explicitly setup how should a value sanitize by the
* sanitize function.
*
* @see available sanitize func
* https://developer.wordpress.org/themes/theme-security/data-sanitization-escaping/
*
* @param array $input array to sanitize.
* @param array $sanitize_mapping single dimensional map key value
* pair to set up sanitization process. Key name should by inside
* input array and the value will be callable func.
* For ex: [key1 => sanitize_email, key2 => wp_kses_post ]
*
* If key not passed then default sanitize_text_field will be used.
*
* @return array
*/
function sanitize_array( array $input, array $sanitize_mapping = array() ):array {
$array = array();
if ( is_array( $input ) && count( $input ) ) {
foreach ( $input as $key => $value ) {
if ( is_array( $value ) ) {
$array[ $key ] = sanitize_array( $value );
} else {
$key = sanitize_text_field( $key );
// If mapping exists then use callback.
if ( isset( $sanitize_mapping[ $key ] ) ) {
$callback = $sanitize_mapping[ $key ];
$value = call_user_func( $callback, wp_unslash( $value ) );
} else {
$value = sanitize_text_field( wp_unslash( $value ) );
}
$array[ $key ] = $value;
}
}
}
return is_array( $array ) && count( $array ) ? $array : array();
}
So the sanitize_array function is a cursive function that can do sanitization each array value using respective sanitization functions.
The first argument on the function is an array that could be single or multi-dimensional. And, the second argument is that is optional but we can tell which array element should use which function. A simple key value pair, where the key is the key name from the array and the value is the respective sanitization function name that we want to use for a particular value.
Hope you enjoyed it 😀
I am professional Web Designer & Developer. I have 5+ years of experience in relevant field. Currently I am working for a private software company named “Ollyo” as a Senior Staff Software Engineer.
by shewa | Jul 23, 2022 | PHP, PHPCS, WPCS
PHPCS (code sniffer) is a great tool for linting & checking your codes against the set of rules. Along with PHPCS, as WordPress folk, we use WordPress coding standards (WPCS) as well. It is very useful to maintain coding standards, ensure output escaping, nonce verification, SQL escape, etc. But sometimes, there will be cases to avoid rules checking for specific code snippets.
Let’s discuss the useful comments to suppress warnings
To Ignore code snippets we can use the below comments:
// @codingStandardsIgnoreStart
// @codingStandardsIgnoreEnd
All the codes inside the above comments will be ignored
Ignore just the below line:
//phpcs:ignore
Ignore nonce verification warning:
//phpcs:disable WordPress.Security.NonceVerification.Recommended
Suppress PHPCS(WordPress.DB.PreparedSQL.InterpolatedNotPrepared)
//phpcs:ignore WordPress.DB.PreparedSQL
Ignore nonce verification missing warning
// phpcs:disable WordPress.Security.NonceVerification.Missing
Suppress PHPCS(Squiz.Commenting.FileComment.Missing)
//phpcs:ignore Generic.Commenting.DocComment.MissingShort
PHPCS(WordPress.Files.FileName.NotHyphenatedLowercase)
//phpcs:ignore WordPress.Files.FileName.NotHyphenatedLowercase
There may have a lot more comments to suppress warnings. If you know others’ comments, feel free to share through the comments section below! Happy coding 😀
I am professional Web Designer & Developer. I have 5+ years of experience in relevant field. Currently I am working for a private software company named “Ollyo” as a Senior Staff Software Engineer.
by shewa | May 21, 2022 | Design Pattern, PHP, Software Development
Abstract factory method is useful for creating products of related family. Create objects of product from sub-classes. A family could have multiple member and each member could have variation among them but they behave similarly.
For example: Let’s consider a furniture family consist of member like chair, table, sofa. Here member may have different type in looks. Suppose chair may have different types like: modern, victorian, art deco. Similarly table and sofa may have different type as well.
4 Steps for implementing Abstract Factory Design Pattern
I have divided the implementation into four easy steps:
Step 1: Create Factory Abstract Class
Factory class will produce multiple product through abstract method.
abstract class FurnitureFactory
{
abstract public static function createChair(): ChairInterface;
abstract public static function createTable(): TableInterface;
abstract public static function createSofa(): SofaInterface;
}
Step 2: Create Factory Concrete Class
Factory concrete class will extends the Factory class so that it implement abstract method. Factory concrete class will implement each distinct product variation and responsible for creating object of product.
class ModernFurniture extends FurnitureFactory
{
public static function createChair(): ChairInterface
{
return new ModernChair();
}
public static function createTable(): TableInterface
{
return new ModernTable();
}
public static function createSofa(): SofaInterface
{
return new ModernSofa();
}
}
Step 3: Interface of each Distinct Product
Interface will be implemented by the product class so that each product have consistency in their behaviour. This way we don’t have to worry about the variations. Since all variations will implement same interface we can also use property and method of class same way.
interface ChairInterface
{
public function legs(): int;
public function sitting();
}
interface TableInterface
{
public function legs(): int;
public function hasDrawer(): bool;
}
interface SofaInterface
{
public function seats(): int;
public function hasDivan(): bool;
}
Step 4: Declare Product Concrete Class for each Product
Each product will have separate class by implementing interface.
class ModernChair implements ChairInterface
{
public function legs(): int
{
return 4;
}
public function sitting()
{
return 'fine';
}
}
class ModernTable implements TableInterface
{
public function legs(): int
{
return 4;
}
public function hasDrawer(): bool
{
return true;
}
}
class ModernSofa implements SofaInterface
{
public function seats(): int
{
return 5;
}
public function hasDivan(): bool
{
return false;
}
}
Now our product is ready to use by the client code
$modern_chair = ModernFurniture::createChair();
echo $modern_chair->legs();
From this Modern Furniture class will can create table & sofa as well and can show users as relevant product.
In future we need more variations for the furniture we can simple create another variation Factory Concrete class without touching any other code 🙂
I am professional Web Designer & Developer. I have 5+ years of experience in relevant field. Currently I am working for a private software company named “Ollyo” as a Senior Staff Software Engineer.