Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,22 @@ This is an example plugin to demonstrate how we at WPify create plugins.
The aim is to create simple plugin that stores information about books and their authors. On this, we demonstrate
the advanced techniques of creating a plugin.

## Steps:

[Next step >>>](https://github.com/wpify/plugin-tutorial/tree/01-basics-php-di)
### 01 - Basic concepts - OOP, Namespaces, Composer, Dependency Injection

Let's start with building the basic plugin structure using OOP, Namespaces, Composer and Dependency Injection.

Links:

* [Object oriented programming - OOP](https://www.phptutorial.net/php-oop/)
* [Namespaces](https://www.phptutorial.net/php-oop/php-namespace/)
* [Composer](https://getcomposer.org/doc/01-basic-usage.md)
* [Understanding Dependency Injection](https://php-di.org/doc/understanding-di.html)
* DI Containers - [PHP/DI](https://php-di.org/), [Symfony DI](https://symfony.com/doc/current/components/dependency_injection.html), [League](https://container.thephpleague.com/), [Nette](https://doc.nette.org/en/dependency-injection/container), [Dice](https://github.com/Level-2/Dice)

```bash
composer require php-di/php-di
```

[Next step >>>](https://github.com/wpify/plugin-tutorial/tree/02-scoper)
95 changes: 95 additions & 0 deletions bootstrap.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
<?php
/*
* Plugin Name: WPify Plugin Tutorial
* Description: Plugin that was made during the tutorial by WPify
* Version: 0.1.0
* Requires PHP: 8.0.0
* Requires at least: 6.2.0
* Author: WPify
* Author URI: https://wpify.io/
* License: GPL v2 or later
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
* Text Domain: wpifypt
* Domain Path: /languages
*/

use DI\Container;
use DI\ContainerBuilder;
use DI\DependencyException;
use DI\NotFoundException;
use WpifyPluginTutorial\Plugin;

require 'vendor/autoload.php';

/**
* Creates and returns DI container.
* If DI container is already created, returns it.
*
* @return Container
* @throws Exception
*/
function wpifypt_container(): Container {
static $container;

if ( empty( $container ) ) {
$containerBuilder = new ContainerBuilder();
$containerBuilder->addDefinitions( array() );
$container = $containerBuilder->build();
}

return $container;
}

/**
* Returns the main plugin class from DI container.
*
* @return Plugin
* @throws DependencyException
* @throws NotFoundException
*/
function wpifypt(): Plugin {
return wpifypt_container()->get( Plugin::class );
}

/**
* Method called on plugin activation.
*
* @param $network_wide Plugin Activated network wide.
*
* @return void
* @throws DependencyException
* @throws NotFoundException
*/
function wpifypt_activate( $network_wide ): void {
wpifypt()->activate( $network_wide );
}

/**
* Method called on plugin deactivation.
*
* @param $network_wide Plugin Deactivated network wide.
*
* @return void
* @throws DependencyException
* @throws NotFoundException
*/
function wpifypt_deactivate( $network_wide ): void {
wpifypt()->deactivate( $network_wide );
}

/**
* Method called on plugin uninstall.
*
* @return void
* @throws DependencyException
* @throws NotFoundException
*/
function wpifypt_uninstall(): void {
wpifypt()->uninstall();
}

add_action( 'plugins_loaded', 'wpifypt' );

register_activation_hook( __FILE__, 'wpifypt_activate' );
register_deactivation_hook( __FILE__, 'wpifypt_deactivate' );
register_uninstall_hook( __FILE__, 'wpifypt_uninstall' );
20 changes: 20 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "wpify/plugin-tutorial",
"type": "project",
"license": "MIT",
"autoload": {
"psr-4": {
"WpifyPluginTutorial\\": "src/"
}
},
"authors": [
{
"name": "WPify",
"email": "info@wpify.io"
}
],
"require": {
"php": "^8.0",
"php-di/php-di": "^7.0"
}
}
13 changes: 13 additions & 0 deletions src/Managers/PostTypesManager.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace WpifyPluginTutorial\Managers;


use WpifyPluginTutorial\PostTypes\BookPostType;

class PostTypesManager {
public function __construct(
BookPostType $book_post_type,
) {
}
}
12 changes: 12 additions & 0 deletions src/Managers/TaxonomiesManager.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

namespace WpifyPluginTutorial\Managers;

use WpifyPluginTutorial\Taxonomies\BookAuthorTaxonomy;

class TaxonomiesManager {
public function __construct(
BookAuthorTaxonomy $book_author_taxonomy,
) {
}
}
53 changes: 53 additions & 0 deletions src/Plugin.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php

namespace WpifyPluginTutorial;

use WpifyPluginTutorial\Managers\PostTypesManager;
use WpifyPluginTutorial\Managers\TaxonomiesManager;

/**
* Main plugin class that initializes all plugin components.
*/
class Plugin {
/**
* Plugin constructor.
* All dependencies are injected via DI container.
*/
public function __construct(
PostTypesManager $post_types_manager,
TaxonomiesManager $taxonomies_manager,
) {
// stuff to do on plugin load
}

/**
* Method called on plugin activation.
*
* @param $network_wide Plugin activated network wide.
*
* @return void
*/
public function activate( $network_wide ): void {
// stuff to do on activation
}

/**
* Method called on plugin deactivation.
*
* @param $network_wide Plugin deactivated network wide.
*
* @return void
*/
public function deactivate( $network_wide ): void {
// stuff to do on deactivation
}

/**
* Method called on plugin uninstall.
*
* @return void
*/
public function uninstall(): void {
// stuff to do on uninstall
}
}
69 changes: 69 additions & 0 deletions src/PostTypes/BookPostType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php

namespace WpifyPluginTutorial\PostTypes;

use WpifyPluginTutorial\Taxonomies\BookAuthorTaxonomy;

class BookPostType {
const KEY = 'book';

public function __construct() {
add_action( 'init', array( $this, 'register' ), 0 );
}

public function register() {
$labels = array(
'name' => _x( 'Books', 'Post Type General Name', 'wpifypt' ),
'singular_name' => _x( 'Book', 'Post Type Singular Name', 'wpifypt' ),
'menu_name' => __( 'Books', 'wpifypt' ),
'name_admin_bar' => __( 'Book', 'wpifypt' ),
'archives' => __( 'Book Archives', 'wpifypt' ),
'attributes' => __( 'Book Attributes', 'wpifypt' ),
'parent_item_colon' => __( 'Parent Book:', 'wpifypt' ),
'all_items' => __( 'All Books', 'wpifypt' ),
'add_new_item' => __( 'Add New Book', 'wpifypt' ),
'add_new' => __( 'Add New', 'wpifypt' ),
'new_item' => __( 'New Book', 'wpifypt' ),
'edit_item' => __( 'Edit Book', 'wpifypt' ),
'update_item' => __( 'Update Book', 'wpifypt' ),
'view_item' => __( 'View Book', 'wpifypt' ),
'view_items' => __( 'View Books', 'wpifypt' ),
'search_items' => __( 'Search Book', 'wpifypt' ),
'not_found' => __( 'Not found', 'wpifypt' ),
'not_found_in_trash' => __( 'Not found in Trash', 'wpifypt' ),
'featured_image' => __( 'Featured Image', 'wpifypt' ),
'set_featured_image' => __( 'Set featured image', 'wpifypt' ),
'remove_featured_image' => __( 'Remove featured image', 'wpifypt' ),
'use_featured_image' => __( 'Use as featured image', 'wpifypt' ),
'insert_into_item' => __( 'Insert into book', 'wpifypt' ),
'uploaded_to_this_item' => __( 'Uploaded to this book', 'wpifypt' ),
'items_list' => __( 'Books list', 'wpifypt' ),
'items_list_navigation' => __( 'Books list navigation', 'wpifypt' ),
'filter_items_list' => __( 'Filter books list', 'wpifypt' ),
);

$args = array(
'label' => __( 'Book', 'wpifypt' ),
'description' => __( 'Example post type Book', 'wpifypt' ),
'labels' => $labels,
'supports' => array( 'title', 'editor', 'thumbnail', 'custom-fields' ),
'taxonomies' => array( BookAuthorTaxonomy::KEY ),
'hierarchical' => false,
'public' => true,
'show_ui' => true,
'show_in_menu' => true,
'menu_position' => 25,
'menu_icon' => 'dashicons-book',
'show_in_admin_bar' => true,
'show_in_nav_menus' => true,
'can_export' => true,
'has_archive' => true,
'exclude_from_search' => false,
'publicly_queryable' => true,
'capability_type' => 'page',
'show_in_rest' => false,
);

register_post_type( self::KEY, $args );
}
}
57 changes: 57 additions & 0 deletions src/Taxonomies/BookAuthorTaxonomy.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

namespace WpifyPluginTutorial\Taxonomies;

use WpifyPluginTutorial\PostTypes\BookPostType;

class BookAuthorTaxonomy {
const KEY = 'book_author';

public function __construct() {
add_action( 'init', array( $this, 'register' ) );
}

public function register() {
$labels = array(
'name' => _x( 'Book Authors', 'Taxonomy General Name', 'wpifypt' ),
'singular_name' => _x( 'Book Author', 'Taxonomy Singular Name', 'wpifypt' ),
'menu_name' => __( 'Book Author', 'wpifypt' ),
'all_items' => __( 'All Book Authors', 'wpifypt' ),
'parent_item' => __( 'Parent Book Author', 'wpifypt' ),
'parent_item_colon' => __( 'Parent Book Author:', 'wpifypt' ),
'new_item_name' => __( 'New Book Author', 'wpifypt' ),
'add_new_item' => __( 'Add Book Author', 'wpifypt' ),
'edit_item' => __( 'Edit Book Author', 'wpifypt' ),
'update_item' => __( 'Update Book Author', 'wpifypt' ),
'view_item' => __( 'View Book Author', 'wpifypt' ),
'separate_items_with_commas' => __( 'Separate items with commas', 'wpifypt' ),
'add_or_remove_items' => __( 'Add or remove book authors', 'wpifypt' ),
'choose_from_most_used' => __( 'Choose from the most used', 'wpifypt' ),
'popular_items' => __( 'Popular Book Authors', 'wpifypt' ),
'search_items' => __( 'Search Book Authors', 'wpifypt' ),
'not_found' => __( 'Not Found', 'wpifypt' ),
'no_terms' => __( 'No Book Authors', 'wpifypt' ),
'items_list' => __( 'Book Authors list', 'wpifypt' ),
'items_list_navigation' => __( 'Book Authors list navigation', 'wpifypt' ),
);

$rewrite = array(
'slug' => 'book-author',
'with_front' => true,
'hierarchical' => false,
);

$args = array(
'labels' => $labels,
'hierarchical' => false,
'public' => true,
'show_ui' => true,
'show_admin_column' => true,
'show_in_nav_menus' => true,
'show_tagcloud' => true,
'rewrite' => $rewrite,
);

register_taxonomy( self::KEY, array( BookPostType::KEY ), $args );
}
}