You can rest easy knowing that you have the web’s best security guards working on your behalf.
WORDPRESS
Making a WordPress plugin extensible with PHP classes
WordPress plugins can be extended with additional functionality, as demonstrated by popular plugins like WooCommerce and Gravity Forms. In the article “Architecting a WordPress plugin to support extensions,” we learn there are two primary ways to make a WordPress plugin extensible:
- By setting up hooks (actions and filters) for extension plugins to inject their own functionality
- By providing PHP classes that extension plugins can inherit
The first method relies more on documentation, detailing available hooks and their usage. The second method, by contrast, offers ready-to-use code for extensions, reducing the need for extensive documentation. This is advantageous because creating documentation alongside code can complicate the plugin’s management and release.
Providing PHP classes directly effectively replaces documentation with code. Instead of teaching how to implement a feature, the plugin supplies the necessary PHP code, simplifying the task for third-party developers.
Let’s explore some techniques for achieving this, with the ultimate goal of fostering an ecosystem of integrations around our WordPress plugin.
Defining base PHP classes in the WordPress plugin
The WordPress plugin will include PHP classes intended for use by extension plugins. These PHP classes might not be used by the main plugin itself but are provided specifically for others to use.
Let’s see how this is implemented in the open-source Gato GraphQL plugin.
AbstractPlugin class:
AbstractPlugin
represents a plugin, both for the main Gato GraphQL plugin and its extensions:
abstract class AbstractPlugin implements PluginInterface
{
protected string $pluginBaseName;
protected string $pluginSlug;
protected string $pluginName;
public function __construct(
protected string $pluginFile,
protected string $pluginVersion,
?string $pluginName,
) {
$this->pluginBaseName = plugin_basename($pluginFile);
$this->pluginSlug = dirname($this->pluginBaseName);
$this->pluginName = $pluginName ?? $this->pluginBaseName;
}
public function getPluginName(): string
{
return $this->pluginName;
}
public function getPluginBaseName(): string
{
return $this->pluginBaseName;
}
public function getPluginSlug(): string
{
return $this->pluginSlug;
}
public function getPluginFile(): string
{
return $this->pluginFile;
}
public function getPluginVersion(): string
{
return $this->pluginVersion;
}
public function getPluginDir(): string
{
return dirname($this->pluginFile);
}
public function getPluginURL(): string
{
return plugin_dir_url($this->pluginFile);
}
// ...
}
AbstractMainPlugin class:
AbstractMainPlugin
extends AbstractPlugin
to represent the main plugin:
abstract class AbstractMainPlugin extends AbstractPlugin implements MainPluginInterface
{
public function __construct(
string $pluginFile,
string $pluginVersion,
?string $pluginName,
protected MainPluginInitializationConfigurationInterface $pluginInitializationConfiguration,
) {
parent::__construct(
$pluginFile,
$pluginVersion,
$pluginName,
);
}
// ...
}
AbstractExtension class:
Similarly, AbstractExtension
extends AbstractPlugin
to represent an extension plugin:
abstract class AbstractExtension extends AbstractPlugin implements ExtensionInterface
{
public function __construct(
string $pluginFile,
string $pluginVersion,
?string $pluginName,
protected ?ExtensionInitializationConfigurationInterface $extensionInitializationConfiguration,
) {
parent::__construct(
$pluginFile,
$pluginVersion,
$pluginName,
);
}
// ...
}
Notice that AbstractExtension
is included within the main plugin, providing functionality to register and initialize an extension. However, it is only used by extensions, not by the main plugin itself.
The AbstractPlugin
class contains shared initialization code invoked at different times. These methods are defined at the ancestor level but are invoked by the inheriting classes according to their lifecycles.
The main plugin and extensions are initialized by executing the setup
method on the corresponding class, invoked from within the main WordPress plugin file.
For instance, in Gato GraphQL, this is done in gatographql.php
:
$pluginFile = __FILE__;
$pluginVersion = '2.4.0';
$pluginName = __('Gato GraphQL', 'gatographql');
PluginApp::getMainPluginManager()->register(new Plugin(
$pluginFile,
$pluginVersion,
$pluginName
))->setup();
setup method:
At the ancestor level, setup
contains the common logic between the plugin and its extensions, such as unregistering them when the plugin is deactivated. This method is not final; It can be overridden by the inheriting classes to add their functionality:
abstract class AbstractPlugin implements PluginInterface
{
// ...
public function setup(): void
{
register_deactivation_hook(
$this->getPluginFile(),
$this->deactivate(...)
);
}
public function deactivate(): void
{
$this->removePluginVersion();
}
private function removePluginVersion(): void
{
$pluginVersions = get_option('gatographql-plugin-versions', []);
unset($pluginVersions[$this->pluginBaseName]);
update_option('gatographql-plugin-versions', $pluginVersions);
}
}
Main plugin’s setup method:
The main plugin’s setup
method initializes the application’s lifecycle. It executes the main plugin’s functionality through methods like initialize
, configureComponents
, configure
, and boot
, and triggers corresponding action hooks for extensions:
abstract class AbstractMainPlugin extends AbstractPlugin implements MainPluginInterface
{
public function setup(): void
{
parent::setup();
add_action('plugins_loaded', function (): void
{
// 1. Initialize main plugin
$this->initialize();
// 2. Initialize extensions
do_action('gatographql:initializeExtension');
// 3. Configure main plugin components
$this->configureComponents();
// 4. Configure extension components
do_action('gatographql:configureExtensionComponents');
// 5. Configure main plugin
$this->configure();
// 6. Configure extension
do_action('gatographql:configureExtension');
// 7. Boot main plugin
$this->boot();
// 8. Boot extension
do_action('gatographql:bootExtension');
}
// ...
}
// ...
}
Extension setup method:
The AbstractExtension
class executes its logic on the corresponding hooks:
abstract class AbstractExtension extends AbstractPlugin implements ExtensionInterface
{
// ...
final public function setup(): void
{
parent::setup();
add_action('plugins_loaded', function (): void
{
// 2. Initialize extensions
add_action(
'gatographql:initializeExtension',
$this->initialize(...)
);
// 4. Configure extension components
add_action(
'gatographql:configureExtensionComponents',
$this->configureComponents(...)
);
// 6. Configure extension
add_action(
'gatographql:configureExtension',
$this->configure(...)
);
// 8. Boot extension
add_action(
'gatographql:bootExtension',
$this->boot(...)
);
}, 20);
}
}
Methods initialize
, configureComponents
, configure
, and boot
are common to both the main plugin and extensions and may share logic. This shared logic is stored in the AbstractPlugin
class.
For example, the configure
method configures the plugin or extensions, calling callPluginInitializationConfiguration
, which has different implementations for the main plugin and extensions and is defined as abstract and getModuleClassConfiguration
, which provides a default behavior but can be overridden if needed:
abstract class AbstractPlugin implements PluginInterface
{
// ...
public function configure(): void
{
$this->callPluginInitializationConfiguration();
$appLoader = App::getAppLoader();
$appLoader->addModuleClassConfiguration($this->getModuleClassConfiguration());
}
abstract protected function callPluginInitializationConfiguration(): void;
/**
* @return array,mixed> [key]: Module class, [value]: Configuration
*/
public function getModuleClassConfiguration(): array
{
return [];
}
}
The main plugin provides its implementation for callPluginInitializationConfiguration
:
abstract class AbstractMainPlugin extends AbstractPlugin implements MainPluginInterface
{
// ...
protected function callPluginInitializationConfiguration(): void
{
$this->pluginInitializationConfiguration->initialize();
}
}
Similarly, the extension class provides its implementation:
abstract class AbstractExtension extends AbstractPlugin implements ExtensionInterface
{
// ...
protected function callPluginInitializationConfiguration(): void
{
$this->extensionInitializationConfiguration?->initialize();
}
}
Methods initialize
, configureComponents
and boot
are defined at the ancestor level and can be overridden by inheriting classes:
abstract class AbstractPlugin implements PluginInterface
{
// ...
public function initialize(): void
{
$moduleClasses = $this->getModuleClassesToInitialize();
App::getAppLoader()->addModuleClassesToInitialize($moduleClasses);
}
/**
* @return array> List of `Module` class to initialize
*/
abstract protected function getModuleClassesToInitialize(): array;
public function configureComponents(): void
{
$classNamespace = ClassHelpers::getClassPSR4Namespace(get_called_class());
$moduleClass = $classNamespace . '\Module';
App::getModule($moduleClass)->setPluginFolder(dirname($this->pluginFile));
}
public function boot(): void
{
// By default, do nothing
}
}
All methods can be overridden by AbstractMainPlugin
or AbstractExtension
to extend them with their custom functionality.
For the main plugin, the setup
method also removes any caching from the WordPress instance when the plugin or any of its extensions is activated or deactivated:
abstract class AbstractMainPlugin extends AbstractPlugin implements MainPluginInterface
{
public function setup(): void
{
parent::setup();
// ...
// Main-plugin specific methods
add_action(
'activate_plugin',
function (string $pluginFile): void {
$this->maybeRegenerateContainerWhenPluginActivatedOrDeactivated($pluginFile);
}
);
add_action(
'deactivate_plugin',
function (string $pluginFile): void {
$this->maybeRegenerateContainerWhenPluginActivatedOrDeactivated($pluginFile);
}
);
}
public function maybeRegenerateContainerWhenPluginActivatedOrDeactivated(string $pluginFile): void
{
// Removed code for simplicity
}
// ...
}
Similarly, the deactivate
method removes caching and boot
executes additional action hooks for the main plugin only:
abstract class AbstractMainPlugin extends AbstractPlugin implements MainPluginInterface
{
public function deactivate(): void
{
parent::deactivate();
$this->removeTimestamps();
}
protected function removeTimestamps(): void
{
$userSettingsManager = UserSettingsManagerFacade::getInstance();
$userSettingsManager->removeTimestamps();
}
public function boot(): void
{
parent::boot();
add_filter(
'admin_body_class',
function (string $classes): string {
$extensions = PluginApp::getExtensionManager()->getExtensions();
$commercialExtensionActivatedLicenseObjectProperties = SettingsHelpers::getCommercialExtensionActivatedLicenseObjectProperties();
foreach ($extensions as $extension) {
$extensionCommercialExtensionActivatedLicenseObjectProperties = $commercialExtensionActivatedLicenseObjectProperties[$extension->getPluginSlug()] ?? null;
if ($extensionCommercialExtensionActivatedLicenseObjectProperties === null) {
continue;
}
return $classes . ' is-gatographql-customer';
}
return $classes;
}
);
}
}
From all the code presented above, it is clear that when designing and coding a WordPress plugin, we need to consider the needs of its extensions and reuse code across them as much as possible. Implementing sound Object-Oriented Programming patterns (such as the SOLID principles) helps achieve this, making the codebase maintainable for the long term.
Declaring and validating the version dependency
Since the extension inherits from a PHP class provided by the plugin, it’s crucial to validate that the required version of the plugin is present. Failing to do so could cause conflicts that bring the site down.
For example, if the AbstractExtension
class is updated with breaking changes and releases a major version 4.0.0
from the previous 3.4.0
, loading the extension without checking the version could result in a PHP error, preventing WordPress from loading.
To avoid this, the extension must validate that the installed plugin is version 3.x.x
. When version 4.0.0
is installed, the extension will be disabled, thus preventing errors.
The extension can accomplish this validation using the following logic, executed on the plugins_loaded
hook (since the main plugin will be loaded by then) in the extension’s main plugin file. This logic accesses the ExtensionManager
class, which is included in the main plugin to manage extensions:
/**
* Create and set-up the extension
*/
add_action(
'plugins_loaded',
function (): void {
/**
* Extension's name and version.
*
* Use a stability suffix as supported by Composer.
*/
$extensionVersion = '1.1.0';
$extensionName = __('Gato GraphQL - Extension Template');
/**
* The minimum version required from the Gato GraphQL plugin
* to activate the extension.
*/
$gatoGraphQLPluginVersionConstraint="^1.0";
/**
* Validate Gato GraphQL is active
*/
if (!class_exists(GatoGraphQLGatoGraphQLPlugin::class)) {
add_action('admin_notices', function () use ($extensionName) {
printf(
'',
sprintf(
__('Plugin %s is not installed or activated. Without it, plugin %s will not be loaded.'),
__('Gato GraphQL'),
$extensionName
)
);
});
return;
}
$extensionManager = GatoGraphQLGatoGraphQLPluginApp::getExtensionManager();
if (!$extensionManager->assertIsValid(
GatoGraphQLExtension::class,
$extensionVersion,
$extensionName,
$gatoGraphQLPluginVersionConstraint
)) {
return;
}
// Load Composer’s autoloader
require_once(__DIR__ . '/vendor/autoload.php');
// Create and set-up the extension instance
$extensionManager->register(new GatoGraphQLExtension(
__FILE__,
$extensionVersion,
$extensionName,
))->setup();
}
);
Notice how the extension declares a dependency on version constraint ^1.0
of the main plugin (using Composer’s version constraints). Thus, when version 2.0.0
of Gato GraphQL is installed, the extension will not be activated.
The version constraint is validated via the ExtensionManager::assertIsValid
method, which calls Semver::satisfies
(provided by the composer/semver
package):
use ComposerSemverSemver;
class ExtensionManager extends AbstractPluginManager
{
/**
* Validate that the required version of the Gato GraphQL for WP plugin is installed.
*
* If the assertion fails, it prints an error on the WP admin and returns false
*
* @param string|null $mainPluginVersionConstraint the semver version constraint required for the plugin (eg: "^1.0" means >=1.0.0 and getPlugin();
$mainPluginVersion = $mainPlugin->getPluginVersion();
if (
$mainPluginVersionConstraint !== null && !Semver::satisfies(
$mainPluginVersion,
$mainPluginVersionConstraint
)
) {
$this->printAdminNoticeErrorMessage(
sprintf(
__('Extension or bundle %s requires plugin %s to satisfy version constraint %s
, but the current version %s
does not. The extension or bundle has not been loaded.', 'gatographql'),
$extensionName ?? $extensionClass,
$mainPlugin->getPluginName(),
$mainPluginVersionConstraint,
$mainPlugin->getPluginVersion(),
)
);
return false;
}
return true;
}
protected function printAdminNoticeErrorMessage(string $errorMessage): void
{
add_action('admin_notices', function () use ($errorMessage): void {
$adminNotice_safe = sprintf(
'',
$errorMessage
);
echo $adminNotice_safe;
});
}
}
Running integration tests against a WordPress server
To make it easier for third-party developers to create extensions for your plugins, provide them with tools for development and testing, including workflows for their continuous integration and continuous delivery (CI/CD) processes.
During development, anyone can easily spin up a web server using DevKinsta, install the plugin for which they are coding the extension, and immediately validate that the extension is compatible with the plugin.
To automate testing during CI/CD, we need to have the web server accessible over a network to the CI/CD service. Services such as InstaWP can create a sandbox site with WordPress installed for this purpose.
If the extension’s codebase is hosted on GitHub, developers can use GitHub Actions to run integration tests against the InstaWP service. The following workflow installs the extension on an InstaWP sandbox site (alongside the latest stable version of the main plugin) and then runs the integration tests:
name: Integration tests (InstaWP)
on:
workflow_run:
workflows: [Generate plugins]
types:
- completed
jobs:
provide_data:
if: ${{ github.event.workflow_run.conclusion == 'success' }}
name: Retrieve the GitHub Action artifact URLs to install in InstaWP
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: shivammathur/setup-php@v2
with:
php-version: 8.1
coverage: none
env:
COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- uses: "ramsey/composer-install@v2"
- name: Retrieve artifact URLs from GitHub workflow
uses: actions/github-script@v6
id: artifact-url
with:
script: |
const allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: context.payload.workflow_run.id,
});
const artifactURLs = allArtifacts.data.artifacts.map((artifact) => {
return artifact.url.replace('https://api.github.com/repos', 'https://nightly.link') + '.zip'
}).concat([
"https://downloads.wordpress.org/plugin/gatographql.latest-stable.zip"
]);
return artifactURLs.join(',');
result-encoding: string
- name: Artifact URL for InstaWP
run: echo "Artifact URL for InstaWP - ${{ steps.artifact-url.outputs.result }}"
shell: bash
outputs:
artifact_url: ${{ steps.artifact-url.outputs.result }}
process:
needs: provide_data
name: Launch InstaWP site from template 'integration-tests' and execute integration tests against it
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: shivammathur/setup-php@v2
with:
php-version: 8.1
coverage: none
env:
COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- uses: "ramsey/composer-install@v2"
- name: Create InstaWP instance
uses: instawp/wordpress-testing-automation@main
id: create-instawp
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
INSTAWP_TOKEN: ${{ secrets.INSTAWP_TOKEN }}
INSTAWP_TEMPLATE_SLUG: "integration-tests"
REPO_ID: 25
INSTAWP_ACTION: create-site-template
ARTIFACT_URL: ${{ needs.provide_data.outputs.artifact_url }}
- name: InstaWP instance URL
run: echo "InstaWP instance URL - ${{ steps.create-instawp.outputs.instawp_url }}"
shell: bash
- name: Extract InstaWP domain
id: extract-instawp-domain
run: |
instawp_domain="$(echo "${{ steps.create-instawp.outputs.instawp_url }}" | sed -e s#https://##)"
echo "instawp-domain=$(echo $instawp_domain)" >> $GITHUB_OUTPUT
- name: Run tests
run: |
INTEGRATION_TESTS_WEBSERVER_DOMAIN=${{ steps.extract-instawp-domain.outputs.instawp-domain }}
INTEGRATION_TESTS_AUTHENTICATED_ADMIN_USER_USERNAME=${{ steps.create-instawp.outputs.iwp_wp_username }}
INTEGRATION_TESTS_AUTHENTICATED_ADMIN_USER_PASSWORD=${{ steps.create-instawp.outputs.iwp_wp_password }}
vendor/bin/phpunit --filter=Integration
- name: Destroy InstaWP instance
uses: instawp/wordpress-testing-automation@main
id: destroy-instawp
if: ${{ always() }}
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
INSTAWP_TOKEN: ${{ secrets.INSTAWP_TOKEN }}
INSTAWP_TEMPLATE_SLUG: "integration-tests"
REPO_ID: 25
INSTAWP_ACTION: destroy-site
This workflow accesses the .zip file via Nightly Link, a service that allows accessing an artifact from GitHub without logging in, simplifying the configuration of InstaWP.
Releasing the extension plugin
We can provide tools to help release the extensions, automating the procedures as much as possible.
The Monorepo Builder is a library for managing any PHP project, including a WordPress plugin. It provides the monorepo-builder release
command to release a version of the project, incrementing either the major, minor, or patch component of the version according to semantic versioning.
This command executes a series of release workers, which are PHP classes that execute certain logic. The default workers include one that creates a git tag
with the new version and another that pushes the tag to the remote repository. Custom workers can be injected before, after, or in between these steps.
The release workers are configured via a configuration file:
use SymplifyMonorepoBuilderConfigMBConfig;
use SymplifyMonorepoBuilderReleaseReleaseWorkerAddTagToChangelogReleaseWorker;
use SymplifyMonorepoBuilderReleaseReleaseWorkerPushNextDevReleaseWorker;
use SymplifyMonorepoBuilderReleaseReleaseWorkerPushTagReleaseWorker;
use SymplifyMonorepoBuilderReleaseReleaseWorkerSetCurrentMutualDependenciesReleaseWorker;
use SymplifyMonorepoBuilderReleaseReleaseWorkerSetNextMutualDependenciesReleaseWorker;
use SymplifyMonorepoBuilderReleaseReleaseWorkerTagVersionReleaseWorker;
use SymplifyMonorepoBuilderReleaseReleaseWorkerUpdateBranchAliasReleaseWorker;
use SymplifyMonorepoBuilderReleaseReleaseWorkerUpdateReplaceReleaseWorker;
return static function (MBConfig $mbConfig): void {
// release workers - in order to execute
$mbConfig->workers([
UpdateReplaceReleaseWorker::class,
SetCurrentMutualDependenciesReleaseWorker::class,
AddTagToChangelogReleaseWorker::class,
TagVersionReleaseWorker::class,
PushTagReleaseWorker::class,
SetNextMutualDependenciesReleaseWorker::class,
UpdateBranchAliasReleaseWorker::class,
PushNextDevReleaseWorker::class,
]);
};
We can provide custom release workers to augment the release process tailored to the needs of a WordPress plugin. For example, the InjectStableTagVersionInPluginReadmeFileReleaseWorker
sets the new version as the “Stable tag” entry in the extension’s readme.txt file:
use NetteUtilsStrings;
use PharIoVersionVersion;
use SymplifySmartFileSystemSmartFileInfo;
use SymplifySmartFileSystemSmartFileSystem;
class InjectStableTagVersionInPluginReadmeFileReleaseWorker implements ReleaseWorkerInterface
{
public function __construct(
// This class is provided by the Monorepo Builder
private SmartFileSystem $smartFileSystem,
) {
}
public function getDescription(Version $version): string
{
return 'Have the "Stable tag" point to the new version in the plugin's readme.txt file';
}
public function work(Version $version): void
{
$replacements = [
'/Stable tag:s+[a-z0-9.-]+/' => 'Stable tag: ' . $version->getVersionString(),
];
$this->replaceContentInFiles(['/readme.txt'], $replacements);
}
/**
* @param string[] $files
* @param array $regexPatternReplacements regex pattern to search, and its replacement
*/
protected function replaceContentInFiles(array $files, array $regexPatternReplacements): void
{
foreach ($files as $file) {
$fileContent = $this->smartFileSystem->readFile($file);
foreach ($regexPatternReplacements as $regexPattern => $replacement) {
$fileContent = Strings::replace($fileContent, $regexPattern, $replacement);
}
$this->smartFileSystem->dumpFile($file, $fileContent);
}
}
}
By adding InjectStableTagVersionInPluginReadmeFileReleaseWorker
to the configuration list, whenever executing the monorepo-builder release
command to release a new version of the plugin, the “Stable tag” in the extension’s readme.txt file will be automatically updated.
Publishing the extension plugin to the WP.org directory
We can also distribute a workflow to help release the extension to the WordPress Plugin Directory. When tagging the project on the remote repository, the following workflow will publish the WordPress extension plugin to the directory:
# See: https://github.com/10up/action-wordpress-plugin-deploy#deploy-on-pushing-a-new-tag
name: Deploy to WordPress.org Plugin Directory (SVN)
on:
push:
tags:
- "*"
jobs:
tag:
name: New tag
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: WordPress Plugin Deploy
uses: 10up/action-wordpress-plugin-deploy@stable
env:
SVN_PASSWORD: ${{ secrets.SVN_PASSWORD }}
SVN_USERNAME: ${{ secrets.SVN_USERNAME }}
SLUG: ${{ secrets.SLUG }}
This workflow uses the 10up/action-wordpress-plugin-deploy
action, which retrieves the code from a Git repository and pushes it to the WordPress.org SVN repository, simplifying the operation.
Summary
When creating an extensible plugin for WordPress, our goal is to make it as easy as possible for third-party developers to extend it, thereby maximizing the chances of fostering a vibrant ecosystem around our plugins.
While providing extensive documentation can guide developers on how to extend the plugin, an even more effective approach is to supply the necessary PHP code and tooling for development, testing, and releasing their extensions.
By including the additional code needed by extensions directly in our plugin, we simplify the process for developers.
Do you plan to make your WordPress plugin extensible? Let us know in the comments section.
WORDPRESS
Five Takeaways from WordCamp Europe 2024 (From a First-Time WordCamp Attendee) – WordPress.com News
This year’s WordCamp Europe was held in Torino, Italy, the capital city of the Piedmont region in northern Italy. Torino is known for its rich automotive history, beautiful architecture, and, of course, incredible food.
From June 13-15, 2024, over 2,500 folks from the WordPress community, including many of us from the WordPress.com team, came together to learn, connect, and give back to the WordPress project that powers over 43% of the entire internet.
I joined the WordPress.com team back in January of this year, so WordCamp Europe 2024 was my first WordCamp experience. In today’s post, I thought it might be interesting to hear about the conference from a first-timer, especially if you’re considering attending a WordCamp or WordPress meetup in the future.
Here are my top five takeaways from my very first WordCamp:
1. In-person connection is powerful.
If your typical workday looks similar to mine––sitting at a desk at your house all day by yourself––going to a conference as large as WordCamp Europe may be a wee bit out of your comfort zone. It certainly was out of mine.
That said, I’ve recently found myself craving in-person connection after the pandemic and working almost exclusively from home for over eight years. Not only did attending this conference just get me out of my normal routine, it allowed me to connect with folks who love the tool I’ve used personally and professionally for over a decade: WordPress.
I staffed the WordPress.com booth, so I had a ton of opportunities to chat with other business owners, developers, creators, and makers over the course of the conference. I actually talked with a few fellow self-taught women developers like me, and I walked away feeling inspired, motivated, and just really thankful to be a part of this community.
But the best conversations happened in places I wouldn’t have expected: over spritzes, grabbing a cafe at the venue, or just walking around the city.
Embracing connection was a big focus of Matt’s final keynote speech during the event, and I couldn’t agree more. Events like WordCamps allow for swapping ideas, collaborating and troubleshooting, and experiencing a sense of community that you just don’t get while sitting behind a computer.
That said, if large-scale conferences like a flagship WordCamp just aren’t for you, try checking out a local WordPress meetup to connect with other like-minded folks in your community.
2. It takes a ton of people to make WordCamps great.
One of the most moving parts of WordCamp Europe was at the very end when all of the volunteers and organizers were called to the stage; it’s truly amazing just how many people need to be involved to make an event like WordCamp actually happen.
Everything was smooth and well-organized, and the volunteers and organizers could not have been more helpful. Their enthusiasm about the event, WordPress, and community in general throughout the conference was infectious.
WordCamps and local WordPress meetups are always looking for volunteers; donating your time and expertise for events and meetups like this are a great way to give back to the WordPress project and community.
And if you’re an organizer of your local WordPress meetup, check out this post for information on how you can get a free WordPress.com website for your local meetup.
3. Contributor Day isn’t intimidating for a first-timer.
I’ve never contributed to WordPress core, but it was one of my goals for this year. That’s why I was so excited to participate in Contributor Day at WordCamp Europe.
If you’re unfamiliar with Contributor Day, it’s an event that usually kicks off a WordCamp. Teams focus on contributing to the WordPress open source project, with groups focused on code, support, translations, sustainability, inclusion, and more.
After listening to all of the team presentations, I decided to join the Accessibility team. Accessibility is something that has always interested me, but it’s also something I don’t have a ton of experience with.
That said, my inexperience wasn’t just accepted, it was actively welcomed.
Once I got to the Accessibility team table, I was immediately greeted and welcomed. Then I paired with a fellow contributor, Marco Acato from Acato Digital Agency, to test the accessibility of a new theme for the WordPress theme repository.
I learned so much, asked a ton of questions, and felt surprisingly accomplished after just a few hours of testing this theme. We were actually able to publish feedback for the theme developer at the end of the day as well.
Contributor Day gave me an even deeper appreciation for the entire community that supports the WordPress project every single day. So much work and effort goes into maintaining and improving this tool that millions of websites across the world rely on to run their businesses, amplify their messages, and stay in touch with others. I felt so grateful to have been a part of it during Contributor Day and would encourage any other first-timers to attend a Contributor Day in the future as well.
Luckily, WordPress core is always looking for volunteers and contributors; check out this guide or the new Contributor Mentorship Program if you’re interested in becoming a contributor yourself.
4. Torino was a great host city, and the WordCamp team made navigating a new city easy.
Between attending Contributor Day and sessions, to checking out sponsor booths and attending side events, I didn’t think we’d have a ton of time to actually see the city or Torino.
I actually had plenty of time to explore with my coworkers, eat pizza every single day, and scope out the best gelato spots outside of conference hours.
The WordCamp Europe team did a great job preparing attendees to make the most of our time in the city as well; their travel guides helped me feel confident navigating the city and finding some of the foods that come from this area in Italy.
As a first-timer in Torino, I really appreciated the extra work that the WordCamp team did to ensure everyone had a chance to explore and experience the city.
5. Pizza really is poetry.
I would be remiss to not mention the food that we ate during our time in our host city! While we like to say that “Code is poetry” around here, so is pizza.
One of my very favorite memories from the event was the branding. The design team for WordCamp Europe 2024 added subtle nods to our host country throughout the venue, which was incredibly clever and well-done.
And while pizza is indeed poetry, it’s even better when shared amongst coworkers, friends, and people who get excited about the same things that excite you.
Wrapping up
I loved my time at WordCamp Europe, and I’m already looking forward to the next time I can connect face-to-face with the WordPress community.
Were you at WordCamp Europe this year? Leave a comment with your favorite memory from the event below.
Join 111.4M other subscribers
WORDPRESS
Inside WordPress.com’s World-Class Security Features – WordPress.com News
It’s never been easier to create a website—especially with WordPress.com—but keeping that site secure can be challenging. When you host with WordPress.com, though, we do the heavy lifting for you and let you focus on the fun of creating your dream website. Whether you’re a blogger, entrepreneur, or hobbyist, our top-notch security features safeguard your site day and night so that you don’t need to stress.
Whether you’ve known about it or not, we’ve long been scanning and monitoring your site’s files to catch and remove threats. Let’s dig in just a bit more.
Built-in protection at your fingertips
Using Automattic’s homegrown Jetpack software, every WordPress.com site is scanned on a daily basis for dangerous plugins, themes, malware, and other vulnerabilities. Once weaknesses are spotted, our security team swiftly resolves the issues, updating or reverting files as needed depending on the problem.
Perhaps the best part is that we offer this peace of mind for free, on every plan. This certainly isn’t the case everywhere. Many WordPress hosts charge for the type of protection that WordPress.com offers on all of our website plans.
Plus, you don’t have to do a thing to activate or maintain these security features. Our scanning tools are up and running as soon as your site is created. You can rest easy knowing that you have the web’s best security guards working on your behalf.
Why does website security even matter?
It’s possible you’ve never before thought of the importance of website security. The reality of the modern web, however, is that bad actors are out there looking to take advantage of you and your site’s visitors.
If your site is hacked, it’s liable to cause serious damage to your reputation and your livelihood (not to mention your emotional well-being). Hackers can manipulate your website’s data, steal information from you or your users (including passwords), install and execute malicious code, and even distribute the malicious code to your visitors, infecting their sites and machines. It’s not an insignificant problem or threat, that’s for sure.
Jetpack’s web application firewall (WAF) monitors every request to your site and blocks requests from anything malicious. Our team of security experts continually updates the web application firewall’s rules to ensure you are protected against the most up‑to‑date threats. You don’t have time for downtime.
Even more robust security tools are available
On our higher-tier plans you also have access to the scan history, which shows a record of all previous threats on your site. Additionally, you’ll have access to real-time backups, real-time security scans, malware removal, spam protection, and vulnerability notifications for core code and plugins.
Set it and forget it
At WordPress.com, we want you dreaming big rather than spending your energy worrying about your website’s security. This is why we provide automatically-installed best-in-class monitoring with no extra charge, on every single plan.
And our security features will grow right alongside you; whether your dream is to blog about your adorable cats, highlight your stunning landscape photography, or build a home base for your budding technology startup, we have your back. Learn more about all our security features or get started building right now:
Join 111.4M other subscribers
WORDPRESS
WordPress Themes 101: Free vs. Premium and Everything in Between
Do you want to learn about WordPress themes and how they can take your website to the next level? If so, you’re in the right place!
There’s no question that choosing the right WordPress theme is vital for building a website that not only looks great but also offers your customers the best experience possible.
But as a beginner or someone looking for a change, this process can be overwhelming, after all, there are thousands of themes to choose from!
We believe that by understanding themes and the important factors around them, you’ll be better prepared to choose one that aligns with your goals. Today, we will give you the full rundown on WordPress themes. Keep reading, and you’ll learn everything you need to know about finding the perfect theme for your site.
Let’s begin!
Understanding WordPress themes
At its core, WordPress themes are a collection of files that define the appearance and functionality of a WordPress website. Themes control everything from the layout and color scheme to the typography and navigation menus. They are the visual and structural foundation that dictates how content is presented to visitors.
Not only do themes determine the look of your site, but they have a direct impact on performance and your overall user experience (UX).
Choosing the best WordPress themes can enhance the overall branding, improve readability, and provide a seamless browsing experience across different devices. But a quick look at the ecosystem will show you that the possibilities are quite endless. You can find sleek and minimalist themes as well as incredibly in-depth, feature-rich options and everything in between.
One way to start exploring your options is to see what themes your favorite websites use. There are various tools and resources available that can help you with your research. A popular option is “What WordPress Theme Is That?,” which allows users to enter a website URL and quickly discover the active theme. Additionally, “WordPress Theme Detector” can automatically detect and display the theme information for any WordPress site you visit.
Choosing the right theme
Now that you know a bit more about themes, let’s talk about some of the major factors you need to know when choosing one for your website.
- Responsive Design: Did you know there are over 5.48 billion mobile users? This statistic highlights why it’s essential to choose a theme that offers a responsive design that looks great and works perfectly across all devices and screen sizes.
- SEO Optimized: You’ll want to find a WordPress theme that can help with search engine optimization (SEO). For example, some themes come with a schema markup alongside the theme. This feature can give your website a competitive edge in search engine rankings and lead to more traffic.
- Customizable Design: Depending on your needs, you may want to choose a theme that allows for easy and flexible customization, whether through theme options, page builders, or the ability to modify the code directly. This feature can help you add some personal flair and style to your site.
- Compatibility with WordPress plugins: WordPress plugins can add powerful functionality to your website, so it’s crucial to choose a theme that is compatible with the plugins you plan to use or might need in the future. Trust us, you don’t want to buy a theme that isn’t compatible with what you’re currently using.
- Loading Times: Research shows that 53% of people will leave a website if it takes too long to load. So, this means a fast-loading website is crucial for boosting engagement, sales, and your search visibility. When looking for a theme that can help, choose one with optimized code and a lightweight design.
Free vs. premium themes
When it comes to choosing the best WordPress themes for your site, you’ll need to balance the factors above with the decision to use a free or premium option. Both have their advantages and drawbacks that you should know.
Here’s a quick overview of each, as well as when you should use them on your site:
Free WordPress Themes:
- Cost-effective solution, which can be helpful for people on a tight budget.
- A wide range of free themes are available in the official WordPress directory and third-party repositories. This means you’ll have options, even if you decide to take the free route.
- Ideal for basic websites or those with limited customization needs.
- Free themes are usually not updated as often, which can pose security risks if not maintained properly.
- There are limited support options, so you’ll need to check out forums if you get stuck.
When to choose a free theme:
- You’re on a tight budget and have basic website design needs
- You’re comfortable with limited customization options, or don’t need advanced customization
- You’re willing to take precautions to keep your site safe and maintained due to the lack of support and updates
Premium WordPress themes:
- Typically come with more advanced features, which means you can tweak your site in a way that perfectly matches your needs.
- Outside of standard page building, these themes are often highly customizable with various built-in options and integrations.
- Provide access to dedicated support and step-by-step guides when you have a specific problem.
- It can be more expensive, ranging from one-time fees to recurring subscriptions.
When to choose a premium theme:
- You require advanced features and functionality.
- You value regular updates, support, and maintenance.
- You need a highly customizable and unique design.
- Your website handles a lot of sensitive information or traffic.
Ultimately, the decision between a free or premium WordPress theme will depend on your specific needs, budget, and the level of customization and support you require for your website. Both have a place in the community.
Popular WordPress themes
Now that you know a little more about themes and how they work, let’s have a look at some of the best themes and how they can help you take your website to the next level.
Astra
Price: Free + $59 per year
Astra theme is a multipurpose and lightweight theme that has become extremely popular among WordPress users due to its performance, customizability and compatibility with popular page builders such as Elementor, Beaver Builder etc.
The free version of the theme offers basic yet important features such as responsive layout, typography controls, different layouts etc. The premium version of Astra, Astra Pro, offers advanced features such as custom layouts, header builder, footer builder, typography options etc. Weighing less than 100KB, this theme is one of the fastest WordPress themes and is suitable for any type of website.
GeneratePress
Price: Free + $59 per year
Another modern and popular theme, GeneratePress, is known for its speed and ease of use. The free version already has an integrated layout builder, typography options, and basic pages such as services, portfolio, and contact.
GeneratePress is also an ideal WordPress theme for website layout because of its visual page builder in the premium version. Some of the premium features of this theme include a site library, custom layouts, sections, headers, typography, pricing tables, WooCommerce support, and advanced theme settings. If you’re looking for WordPress eCommerce themes, this is an excellent option.
OceanWP
Price: Free + $44 per year, $176 for life
A multipurpose theme with strong eCommerce and online store capabilities, OceanWP offers a range of pre-built website demos in the free version, as well as WooCommerce integration and all the customization options you’d expect from a popular WordPress theme.
Further premium features include a pop-up builder, sticky headers, content slider, icon box, feature grid, table of contents and more. The theme also includes premium add-ons for integrating with some of the most popular plugins such as MonsterInsights, WP Rocket, and AIOSEO. Overall, OceanWP is a powerful theme suitable for business websites and online stores.
Avada
Price: Premium $69 per year
Avada is a top-selling theme on ThemeForest. It is a fully packed, highly functional, responsive, and versatile premium WordPress theme with a visual page builder, dozens of pre-built website layouts, tons of custom options, header builder, footer builder, and e-commerce shopping cart options.
Out of the box, Avada comes with lots of layout possibilities and you can create any type of website from business and corporate sites to e-commerce stores, restaurants, cafes, product showcases, portfolio sites, travel and wedding sites, medical and law firms, SEO and marketing agencies, and any type of responsive website.
We like the Visual Pagebuilder, which allows users complete creative freedom to build stunning and highly effective web pages. In addition to that, it offers Header Builder and Footer Builder as well. Avada is a complete theme which will fulfill all your requirements.
Divi
Price: 30-day free trial, $89 per year
Divi is a bestselling premium WordPress theme by ElegantThemes which comes with a great drag-and-drop page builder. This enables complete control over your website’s design along with remarkable layout choices.
The user-friendly visual builder helps create personalized layouts, incorporate animations, and take advantage of the pre-designed layouts and modules. Other advanced options that Divi offers are split testing, custom CSS controls, and robust theme options. All these make Divi a versatile choice for agency websites, designers, and for everyone looking for a totally customizable web solution.
Thrive Themes
Price: $149 per year
Thrive Themes offers a great theme builder that can help you create stunning, high-performing websites. It comes with a list of designer-made and tested themes that can be installed with a click. Set global website branding effortlessly, including smart brand colors, global font sets and pairings, and dark/light brand logos.
With Thrive Themes, you can visually edit all your theme template files, including blog posts, headers, footers, sidebars, 404 pages, and more. The theme builder allows you to edit and style blog lists with ease and make sweeping changes across your entire website or fine-tune each pixel.
Ideal for marketers and eCommerce business owners, Thrive Themes provides the flexibility and power to create engaging, conversion-optimized websites. It integrates seamlessly with other popular WordPress plugins, making it a great choice for both new and established businesses.
Kadance
Price: Free + $149 per year
Specialized WordPress themes
WordPress themes are very versatile, but sometimes you need something more targeted – a specialized WordPress theme just for your site and its unique purpose.
With that thought in mind, let’s look at some of the top theme choices for some of the most common website types, including blog, e-commerce, and business themes.
WordPress blog templates
Perhaps your #1 priority is to create a successful blog. In that case, you need a WordPress theme that’s optimized for writing and blogging. Here are some of the top WordPress blog themes featuring user-friendly elements that bloggers will love:
- Design elements that encourage readability and content discovery
- Built-in featured posts, related posts, and popular posts widgets
- Integration with social networks for sharing
- Easy customization of author boxes
- Integrated email/newsletter signup forms
Some of the most popular WordPress blog templates include Editorial, Novelty, and Poseidon. Many of the best blog themes emphasize clean design and minimal distractions for readers while still offering plenty of customization and tools.
WordPress Ecommerce templates
If you’re ready to create an online store, you’ll need an eCommerce WordPress theme. All of the best WordPress eCommerce templates are optimized for shopping and include integration with the popular WooCommerce plugin and other shopping cart systems.
Other features include:
- Product catalogs and shopping carts
- Secure checkouts
- Advanced product filters and search
- Cross- and upselling
- Customer reviews and ratings
Astra Pro, OceanWP, and Divi all offer strong eCommerce support, while dedicated eCommerce templates like Shoptimizer and GrooveKart are specifically designed for this.
When choosing an eCommerce WordPress theme, consider the size of your product catalog, the payment options you need, and any other functionality like memberships or subscriptions.
WordPress business and corporate templates
Whether you’re a business, agency, or professional, your WordPress theme can make or break your credibility and trust with clients and customers.
Many of the best WordPress themes for business and corporate sites feature professional designs and useful business tools, including:
- Clean, corporate layouts
- Staff profile pages
- Team portfolio and case studies
- Testimonials and client logo sliders
- Advanced contact forms and map integrations
Neve, Customizr, and the Divi theme are all popular choices for business templates. The latter offers a whole suite of professional layouts and designs for many types of industries.
When selecting a business WordPress theme, consider your industry niche, whether you need eCommerce, and your branding and design style. All of this information will help you determine the right theme for your site.
Ultimately, picking the right template can help you start your website strong, whatever it may be. We suggest doing some additional research and looking for themes targeting your specific niche – it will be worth your time, and your visitors will appreciate the fact that your site is optimized for them.
Theme selection based on content needs
Apart from special use cases like blogs or e-commerce websites, you can also consider the type of content you’ll publish and choose the theme that best fits your needs.
Let’s consider some good themes for posts/comments and visual content like portfolios and galleries.
Best themes for posts and comments
Do you think user comments and community engagement will be a major part of your workflow? If so, you should pick a theme that prioritizes posts and comments.
The best themes for posts and comments WordPress provides customizations like blog layouts, commenting, social sharing, related feature tabs, and customizable user profiles.
Some well-known themes in this category include Editorial, Zine, and Suffice. These themes will give you a blank slate for long-form content to go alongside engagement via comments, sharing buttons, and related posts.
Best themes for visual content
On the other hand, if your website is going to contain a lot of visual elements like photography, designs, or graphics, you need a theme that helps in showcasing this type of content.
The themes that are best for websites with lots of visual content usually come with the following features: gallery and portfolio project system, lightbox, grid options, distraction-free modes, and slider integrations.
Some of the well-known themes for websites with lots of visual content include Divi, Neve, Astra, and specialized portfolio themes like Accountor and Imprint. Many of them make use of WordPress’ native media handling while adding better visual layouts and display features.
When selecting a theme that focuses on visual content, consider the type of media you’ll be displaying (images, videos, 3D models, etc.), whether you need proofing areas for clients, and whether print/download options will be needed.
Regardless of the type of content you’ll be publishing, investing time in identifying a theme well-suited to managing how you organize and present that content can lead to a much better user experience for your target audience.
Affordable options
Creating a website needn’t be expensive. There are high-quality, cheap WordPress themes available that ensure your website looks professionally crafted without compromising on performance or usability.
Startups, small enterprises, and people with limited budgets need cost-effective solutions when it comes to choosing WordPress themes. Here are some guidelines on how to find cheap, responsive WordPress themes:
Visit free theme repositories
The official WordPress.org theme repository is the first place you should consider. There are thousands of free themes available there. Free doesn’t necessarily mean the theme is of low quality. There are well-coded, responsive, and regularly maintained themes in the repository if you’re willing to look and be aware of ones that haven’t been updated in a while.
Check for developer/student discounts
Most premium theme providers give attractive discounts to developers, agencies, students, and beginners. Ask if there are special discounts available even if you don’t see any listed.
Freemium themes
There are WordPress theme companies which provide themes based on a freemium model. Kandance from our list above is one such option. You can start with the free version and upgrade to premium features as and when your resources permit.
Watch out for sales and bundles
If you have a flexible deadline, you can wait for the next sale or bundle offer from prominent theme providers. Many of them offer attractive discounts (as much as 30-70%) around various festive seasons like Black Friday and so on.
Wrapping it up
Choosing the very best WordPress theme for your website is a key part of the design process. Not only does your theme determine the appearance of your site but it also determines the experience you build with visitors.
Whether you are creating a blog, an online store, a business website, or a portfolio that is heavy on images, choosing the right WordPress theme from the start will make all the difference to the success of your site.
In this article, we’ve covered the different types of WordPress themes available, some of the popular choices, specialist themes, and even some free alternatives.
So, take the time to research, experiment, and use the advice and resources we shared today. With the right WordPress theme in hand, you’ll be well on your way to creating a thriving website that resonates with your audience.
Additional resources
Theme libraries
- WordPress.org Theme Directory: The official WordPress theme repository with thousands of free themes.
- ThemeForest: A vast marketplace for premium WordPress themes across various categories.
- Elegant Themes: Home to the popular Divi theme and other premium themes and plugins.
Tools for detecting themes
- What WordPress Theme Is That?: A free online tool to detect the theme and plugins used by a WordPress site.
- WPThemeDetector: Another tool for identifying the theme and plugins on a WordPress site.
Theme comparison and review sites
- WPBeginner: Offers reviews and comparisons of various WordPress themes and plugins.
- SeedProd: Provides curated lists and reviews of free and premium WordPress themes.
- IsItWP: Helps you find the best WordPress themes and provides in-depth reviews.
FAQs
What is a WordPress theme?
A: A WordPress theme is a collection of templates and stylesheets used to define the appearance and display of a WordPress-powered website.
How do I install a WordPress theme?
A: To install a theme, go to your WordPress dashboard, navigate to Appearance > Themes, click “Add New,” search for a theme, and click “Install.” Once installed, click “Activate” to apply the theme to your site.
What is the difference between free and premium WordPress themes?
A: Free themes are available at no cost and offer basic features and customization options. Premium themes come with advanced features, dedicated support, and regular updates but require a purchase.
Can I customize my WordPress theme?
A: Yes, most WordPress themes offer customization options through the WordPress Customizer or theme-specific settings. You can change colors, fonts, layouts, and more.
What should I consider when choosing a WordPress theme?
A: Consider factors like design, responsiveness, customization options, compatibility with plugins, SEO friendliness, speed, and support.
How can I find out which theme a website is using?
A: You can use online tools like “What WordPress Theme Is That?” or “WPThemeDetector” to identify the theme and plugins used by a WordPress site.
Can I use multiple themes on my WordPress site?
A: Typically, you can only activate one theme at a time for your entire WordPress site. However, you can use different themes for different sections of your site with plugins or custom coding.
Guest Author: Syed Balkhi is the founder of WPBeginner, the largest free WordPress resource site. With over 10 years of experience, he’s the leading WordPress expert in the industry. You can learn more about Syed and his portfolio of companies by following him on his social media networks.
-
WORDPRESS5 days ago
Host Your WordPress Meetup Site for Free on WordPress.com – WordPress.com News
-
SEARCHENGINES6 days ago
Daily Search Forum Recap: June 14, 2024
-
AFFILIATE MARKETING7 days ago
ChatGPT is Becoming More Human-Like. Here’s How The Tool is Getting Smarter at Replicating Your Voice, Brand and Personality.
-
SEO7 days ago
The Complete Guide to Google My Business for Local SEO
-
WORDPRESS7 days ago
Do the Woo 4.0 – WordPress.com News
-
SEARCHENGINES5 days ago
Google Weekend Volatility, Google On Search Leak, Elizabeth Tucker Interview, Apple Intelligence & More
-
SEO4 days ago
Google Answers Question About Toxic Link Sabotage
-
SEO7 days ago
LinkedIn Rolls Out New Newsletter Tools