Skip to content
Snippets Groups Projects
Commit 2109111b authored by Dyszczo's avatar Dyszczo
Browse files

Merge branch 'feature/activation' into 'master'

SlimPlugin, some interfaces, filter storage and more

See merge request !24
parents 31fb6a6c 782127d8
No related branches found
Tags 1.4
1 merge request!24SlimPlugin, some interfaces, filter storage and more
Pipeline #8485 passed with stages
in 4 minutes and 4 seconds
## [1.4.0] - 2019-09-26
### Added
- SlimPlugin - abstract class with only most important plugin elements
- AbstractPlugin - docs and cleaning
- Activateable - interface to tag plugin to hook into activation hook
- Deactivateable - interface to tag plugin to hook into deactivation hook
- Conditional - interface to tag classes that should be instantiated/hooked only in given state
### Changed
- WordpressFilterStorage - store plugin using WordPress filter system
- target blank in default plugin links
### Fixed
- Fixed assets and plugin url issues
## [1.3.4] - 2019-09-26 ## [1.3.4] - 2019-09-26
### Fixed ### Fixed
- Gitlab.ci - Gitlab.ci
......
...@@ -34,4 +34,4 @@ class LegacyBuildDirector { ...@@ -34,4 +34,4 @@ class LegacyBuildDirector {
public function get_plugin() { public function get_plugin() {
return $this->builder->get_plugin(); return $this->builder->get_plugin();
} }
} }
\ No newline at end of file
...@@ -61,4 +61,4 @@ abstract class AbstractBuilder { ...@@ -61,4 +61,4 @@ abstract class AbstractBuilder {
*/ */
public function set_helper( $helper ) { public function set_helper( $helper ) {
} }
} }
\ No newline at end of file
...@@ -79,4 +79,4 @@ class InfoActivationBuilder extends AbstractBuilder ...@@ -79,4 +79,4 @@ class InfoActivationBuilder extends AbstractBuilder
{ {
return $this->plugin; return $this->plugin;
} }
} }
\ No newline at end of file
...@@ -55,4 +55,4 @@ class InfoBuilder extends AbstractBuilder { ...@@ -55,4 +55,4 @@ class InfoBuilder extends AbstractBuilder {
public function get_plugin() { public function get_plugin() {
return $this->plugin; return $this->plugin;
} }
} }
\ No newline at end of file
...@@ -3,31 +3,50 @@ ...@@ -3,31 +3,50 @@
namespace WPDesk\PluginBuilder\Plugin; namespace WPDesk\PluginBuilder\Plugin;
/** /**
* Base plugin class for WP Desk plugins. * Base plugin with most basic functionalities used by every WPDesk plugin.
* *
* *************************************************************
* * Important! This class should be not modified! *
* * This class is loaded at startup from first loaded plugin! *
* *************************************************************
* *
* @author Grzegorz, Dyszczo * Known issues:
* *
* The class name is too generic but can't be changed as it would introduce a major incompatibility for most of the plugins.
* The $plugin_url, $docs_url and most other fields should be removed as they only litter the place but for compatibility reasons we can't do it right now.
* Hook methods should be moved to external classes but for compatibility reasons we can't do it right now.
*/ */
abstract class AbstractPlugin implements \WPDesk_Translable { abstract class AbstractPlugin extends SlimPlugin {
/** @var \WPDesk_Plugin_Info */ /**
* Most info about plugin internals.
*
* @var \WPDesk_Plugin_Info
*/
protected $plugin_info; protected $plugin_info;
/** @var string */ /**
* Unique string for this plugin in [a-z_]+ format.
*
* @var string
*/
protected $plugin_namespace; protected $plugin_namespace;
/** @var string */ /**
* Absolute URL to the plugin dir.
*
* @var string
*/
protected $plugin_url; protected $plugin_url;
/** @var string */ /**
* Absolute URL to the plugin docs.
*
* @var string
*/
protected $docs_url; protected $docs_url;
/** @var string */ /**
* Absolute URL to the plugin settings url.
*
* @var string
*/
protected $settings_url; protected $settings_url;
/** /**
...@@ -45,34 +64,35 @@ abstract class AbstractPlugin implements \WPDesk_Translable { ...@@ -45,34 +64,35 @@ abstract class AbstractPlugin implements \WPDesk_Translable {
public function __construct( $plugin_info ) { public function __construct( $plugin_info ) {
$this->plugin_info = $plugin_info; $this->plugin_info = $plugin_info;
$this->plugin_namespace = strtolower( $plugin_info->get_plugin_dir() ); $this->plugin_namespace = strtolower( $plugin_info->get_plugin_dir() );
} $this->plugin_url = $this->plugin_info->get_plugin_url();
public function init() {
$this->init_base_variables(); $this->init_base_variables();
$this->hooks();
} }
/**
* Initialize internal state of the plugin.
*
* @return void
* @deprecated Just use __construct to initialize plugin internal state.
*
*/
public function init_base_variables() { public function init_base_variables() {
$this->plugin_url = plugin_dir_url( $this->plugin_info->get_plugin_dir() );
} }
/** /**
* Initializes plugin external state.
*
* The plugin internal state is initialized in the constructor and the plugin should be internally consistent after creation.
* The external state includes hooks execution, communication with other plugins, integration with WC etc.
*
* @return void * @return void
*/ */
protected function hooks() { public function init() {
add_action( 'admin_enqueue_scripts', [ $this, 'admin_enqueue_scripts' ] ); $this->hooks();
add_action( 'wp_enqueue_scripts', [ $this, 'wp_enqueue_scripts' ] );
add_action( 'plugins_loaded', [ $this, 'load_plugin_text_domain' ] );
add_filter( 'plugin_action_links_' . plugin_basename( $this->get_plugin_file_path() ), [
$this,
'links_filter'
] );
} }
/** /**
* Returns absolute path to the plugin dir.
*
* @return string * @return string
*/ */
public function get_plugin_file_path() { public function get_plugin_file_path() {
...@@ -80,82 +100,118 @@ abstract class AbstractPlugin implements \WPDesk_Translable { ...@@ -80,82 +100,118 @@ abstract class AbstractPlugin implements \WPDesk_Translable {
} }
/** /**
* @return $this * Returns plugin text domain.
*
* @return string
*/ */
public function get_plugin() { public function get_text_domain() {
return $this; return $this->plugin_info->get_text_domain();
} }
/** /**
* @return void * Returns unique string for plugin in [a-z_]+ format. Can be used as plugin id in various places like plugin slug etc.
*
* @return string
*/ */
public function load_plugin_text_domain() { public function get_namespace() {
load_plugin_textdomain( $this->get_text_domain(), false, $this->get_namespace() . '/lang/' ); return $this->plugin_namespace;
} }
/** /**
* Returns plugin absolute URL.
*
* @return string * @return string
*/ */
public function get_text_domain() { public function get_plugin_url() {
return $this->plugin_info->get_text_domain(); return esc_url( trailingslashit( $this->plugin_url ) );
} }
/** /**
* Returns plugin absolute URL to dir with front end assets.
*
* @return string * @return string
*/ */
public function get_namespace() {
return $this->plugin_namespace;
}
public function get_plugin_assets_url() { public function get_plugin_assets_url() {
return esc_url( trailingslashit( $this->get_plugin_url() . 'assets' ) ); return esc_url( trailingslashit( $this->get_plugin_url() . 'assets' ) );
} }
/** /**
* @return $this
* @deprecated For backward compatibility.
* *
* @return string
*/ */
public function get_plugin_url() { public function get_plugin() {
return esc_url( trailingslashit( $this->plugin_url ) ); return $this;
}
/**
* Integrate with WordPress and with other plugins using action/filter system.
*
* @return void
*/
protected function hooks() {
add_action( 'admin_enqueue_scripts', [ $this, 'admin_enqueue_scripts' ] );
add_action( 'wp_enqueue_scripts', [ $this, 'wp_enqueue_scripts' ] );
add_action( 'plugins_loaded', [ $this, 'load_plugin_text_domain' ] );
add_filter( 'plugin_action_links_' . plugin_basename( $this->get_plugin_file_path() ), [
$this,
'links_filter'
] );
}
/**
* Initialize plugin test domain. This is a hook function. Do not execute directly.
*
* @return void
*/
public function load_plugin_text_domain() {
load_plugin_textdomain( $this->get_text_domain(), false, $this->get_namespace() . '/lang/' );
} }
/**
* Append JS scripts in the WordPress admin panel. This is a hook function. Do not execute directly.
*
* @return void
*/
public function admin_enqueue_scripts() { public function admin_enqueue_scripts() {
} }
/**
* Append JS scripts in WordPress. This is a hook function. Do not execute directly.
*
* @return void
*/
public function wp_enqueue_scripts() { public function wp_enqueue_scripts() {
} }
/** /**
* action_links function. * Initialize plugin admin links. This is a hook function. Do not execute directly.
*
* @access public
* *
* @param mixed $links * @param string[] $links
* *
* @return array * @return string[]
*/ */
public function links_filter( $links ) { public function links_filter( $links ) {
$support_link = get_locale() === 'pl_PL' ? 'https://www.wpdesk.pl/support/' : 'https://www.wpdesk.net/support'; $support_link = get_locale() === 'pl_PL' ? 'https://www.wpdesk.pl/support/' : 'https://www.wpdesk.net/support';
if( $this->support_url ) { if ( $this->support_url ) {
$support_link = $this->support_url; $support_link = $this->support_url;
} }
$plugin_links = [ $plugin_links = [
'<a href="' . $support_link . '">' . __( 'Support', $this->get_text_domain() ) . '</a>', '<a target="_blank" href="' . $support_link . '">' . __( 'Support', $this->get_text_domain() ) . '</a>',
]; ];
$links = array_merge( $plugin_links, $links ); $links = array_merge( $plugin_links, $links );
if ( $this->docs_url ) { if ( $this->docs_url ) {
$plugin_links = [ $plugin_links = [
'<a href="' . $this->docs_url . '">' . __( 'Docs', $this->get_text_domain() ) . '</a>', '<a target="_blank" href="' . $this->docs_url . '">' . __( 'Docs', $this->get_text_domain() ) . '</a>',
]; ];
$links = array_merge( $plugin_links, $links ); $links = array_merge( $plugin_links, $links );
} }
if ( $this->settings_url ) { if ( $this->settings_url ) {
$plugin_links = [ $plugin_links = [
'<a href="' . $this->settings_url . '">' . __( 'Settings', $this->get_text_domain() ) . '</a>', '<a target="_blank" href="' . $this->settings_url . '">' . __( 'Settings', $this->get_text_domain() ) . '</a>',
]; ];
$links = array_merge( $plugin_links, $links ); $links = array_merge( $plugin_links, $links );
} }
......
<?php
namespace WPDesk\PluginBuilder\Plugin;
/**
* Tag the plugin with this ingterface to hook it to the WordPress activation hook.
*
* Note: works from plugin flow ^2.2.
*
* @package WPDesk\PluginBuilder\Plugin
*/
interface Activateable {
/**
* Plugin activated in WordPress. Do not execute directly.
*
* @return void
*/
public function activate();
}
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
namespace WPDesk\PluginBuilder\Plugin; namespace WPDesk\PluginBuilder\Plugin;
/** /**
* It means that this class is should know about subscription activation * It means that this class is should know about SUBSCRIPTION activation
* *
* @package WPDesk\PluginBuilder\Plugin * @package WPDesk\PluginBuilder\Plugin
*/ */
......
<?php
namespace WPDesk\PluginBuilder\Plugin;
/**
* Something that can be instantiated/hooked conditionally.
*
* @see https://github.com/mwpd/basic-scaffold/blob/master/src/Infrastructure/Conditional.php by Alain Schlesser
*
* @package WPDesk\PluginBuilder\Plugin
*/
interface Conditional {
/**
* Check whether the conditional object is currently needed.
*
* @return bool Whether the conditional object is needed.
*/
public static function is_needed();
}
<?php
namespace WPDesk\PluginBuilder\Plugin;
/**
* Tag the plugin with this ingterface to hook it to the WordPress deactivation hook.
*
* Note: works from plugin flow ^2.2.
*
* @package WPDesk\PluginBuilder\Plugin
*/
interface Deactivateable {
/**
* Plugin deactivate in WordPress. Do not execute directly.
*
* @return void
*/
public function deactivate();
}
...@@ -45,9 +45,15 @@ trait HookableParent { ...@@ -45,9 +45,15 @@ trait HookableParent {
protected function hooks_on_hookable_objects() { protected function hooks_on_hookable_objects() {
/** @var Hookable $hookable_object $hookable_object */ /** @var Hookable $hookable_object $hookable_object */
foreach ( $this->hookable_objects as $hookable_object ) { foreach ( $this->hookable_objects as $hookable_object ) {
$hookable_object->hooks(); if ($hookable_object instanceof Conditional) {
if ($hookable_object::is_needed()) {
$hookable_object->hooks();
}
} else {
$hookable_object->hooks();
}
} }
} }
} }
\ No newline at end of file
...@@ -31,4 +31,4 @@ trait PluginAccess { ...@@ -31,4 +31,4 @@ trait PluginAccess {
return $this->plugin; return $this->plugin;
} }
} }
\ No newline at end of file
<?php
namespace WPDesk\PluginBuilder\Plugin;
/**
* Most clean plugin class with only most important details.
*/
abstract class SlimPlugin implements \WPDesk_Translatable {
/**
* Initializes plugin external state.
*
* The plugin internal state is initialized in the constructor and the plugin should be internally consistent after creation.
* The external state includes hooks execution, communication with other plugins, integration with WC etc.
*
* @return void
*/
abstract public function init();
}
...@@ -8,7 +8,7 @@ class StorageFactory { ...@@ -8,7 +8,7 @@ class StorageFactory {
* @return PluginStorage * @return PluginStorage
*/ */
public function create_storage() { public function create_storage() {
return new StaticStorage(); return new WordpressFilterStorage();
} }
} }
<?php
namespace WPDesk\PluginBuilder\Storage;
use WPDesk\PluginBuilder\Plugin\AbstractPlugin;
/**
* Can store plugin instances in WordPress filter system.
*
* @package WPDesk\PluginBuilder\Storage
*/
class WordpressFilterStorage implements PluginStorage {
const STORAGE_FILTER_NAME = 'wpdesk_plugin_instances';
/**
* @param string $class
* @param AbstractPlugin $object
*/
public function add_to_storage( $class, $object ) {
add_filter( self::STORAGE_FILTER_NAME, function ( $plugins ) use ( $class, $object ) {
if ( isset( $plugins[ $class ] ) ) {
throw new Exception\ClassAlreadyExists( "Class {$class} already exists" );
}
$plugins[ $class ] = $object;
return $plugins;
} );
}
/**
* @param string $class
*
* @return AbstractPlugin
*/
public function get_from_storage( $class ) {
$plugins = apply_filters( self::STORAGE_FILTER_NAME, [] );
if ( isset( $plugins[ $class ] ) ) {
return $plugins[ $class ];
}
throw new Exception\ClassNotExists( "Class {$class} not exists in storage" );
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment