Skip to content
This repository has been archived by the owner on Mar 31, 2022. It is now read-only.

Commit

Permalink
Move the SVG Component back to the plugin (#247)
Browse files Browse the repository at this point in the history
  • Loading branch information
Luehrsen authored Nov 27, 2020
1 parent 1096bd5 commit 603d6b2
Show file tree
Hide file tree
Showing 9 changed files with 312 additions and 12 deletions.
4 changes: 4 additions & 0 deletions build/_lhpbp.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,9 @@
// Load the `wp_lhpbp()` entry point function.
require _LHPBP_PATH . 'inc/functions.php';

if ( wp_get_environment_type() === 'development' ) {
require _LHPBP_PATH . 'inc/test.php';
}

// Initialize the plugin.
call_user_func( 'WpMunich\lhpbp\wp_lhpbp' );
3 changes: 3 additions & 0 deletions build/img/icons/slashes.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 3 additions & 2 deletions build/inc/Plugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class Plugin {
protected $components = array();

/**
* The template tags instance, providing access to all available template tags.
* The template tags instance, providing access to all available plugin functions.
*
* @var Plugin_Functions
*/
Expand Down Expand Up @@ -64,7 +64,7 @@ public function __construct( array $components = array() ) {
array_filter(
$this->components,
function( Component_Interface $component ) {
return $component instanceof Plugin_Component_Interface;
return $component instanceof Plugin_Function_Interface;
}
)
);
Expand Down Expand Up @@ -132,6 +132,7 @@ protected function get_default_components() {
new Blocks\Component(),
new i18n\Component(),
new ACF\Component(),
new SVG\Component(),
);

return $components;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
<?php
/**
* _Lhpbp\Plugin_Component_Interface interface
* _Lhpbp\Plugin_Function_Interface interface
*
* @package lhpbp
*/

namespace WpMunich\lhpbp;

/**
* Interface for a plugin component that exposes template tags.
* Interface for a plugin component that exposes plugin functions.
*/
interface Plugin_Component_Interface {
interface Plugin_Function_Interface {
/**
* Gets template tags to expose as methods on the Plugin_Functions class instance, accessible through `wp_lhpbp()`.
* Gets plugin function to expose as methods on the Plugin_Functions class instance, accessible through `wp_lhpbp()`.
*
* @return array Associative array of $method_name => $callback_info pairs. Each $callback_info must either be
* a callable or an array with key 'callable'. This approach is used to reserve the possibility of
Expand Down
12 changes: 6 additions & 6 deletions build/inc/Plugin_Functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,22 +34,22 @@ class Plugin_Functions {
* Sets the plugin components.
*
* @param array $components Optional. List of plugin function components. Each of these must implement the
* Plugin_Component_Interface interface.
* Plugin_Function_Interface interface.
*
* @throws InvalidArgumentException Thrown if one of the $components does not implement
* Plugin_Component_Interface.
* Plugin_Function_Interface.
*/
public function __construct( array $components = array() ) {
// Set the template tags for the components.
foreach ( $components as $component ) {
// Bail if a templating component is invalid.
if ( ! $component instanceof Plugin_Component_Interface ) {
if ( ! $component instanceof Plugin_Function_Interface ) {
throw new InvalidArgumentException(
sprintf(
/* translators: 1: classname/type of the variable, 2: interface name */
__( 'The plugin functions component %1$s does not implement the %2$s interface.', 'lhpbp' ),
gettype( $component ),
Plugin_Component_Interface::class
Plugin_Function_Interface::class
)
);
}
Expand Down Expand Up @@ -84,12 +84,12 @@ public function __call( $method, $args ) {
/**
* Sets template tags for a given plugin templating component.
*
* @param Plugin_Component_Interface $component plugin templating component.
* @param Plugin_Function_Interface $component plugin templating component.
*
* @throws InvalidArgumentException Thrown when one of the template tags is invalid.
* @throws RuntimeException Thrown when one of the template tags conflicts with an existing one.
*/
protected function set_plugin_functions( Plugin_Component_Interface $component ) {
protected function set_plugin_functions( Plugin_Function_Interface $component ) {
$tags = $component->plugin_functions();
foreach ( $tags as $method_name => $callback ) {
if ( is_callable( $callback ) ) {
Expand Down
111 changes: 111 additions & 0 deletions build/inc/SVG/Component.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
<?php
/**
* Gbplugin\SVG\Component class
*
* @package lhpbp
*/

namespace WpMunich\lhpbp\SVG;
use WpMunich\lhpbp\Component_Interface;
use WpMunich\lhpbp\Plugin_Function_Interface;
use function add_action;
use \WP_Error;

/**
* The Component
*/
class Component implements Component_Interface, Plugin_Function_Interface {

/**
* A storage type for icons we have already used.
*
* @var array
*/
private $images = array();

/**
* Gets the unique identifier for the theme component.
*
* @return string Component slug.
*/
public function get_slug() {
return 'svg';
}

/**
* Gets template tags to expose as methods on the Template_Tags class instance, accessible through `wp_lhpbp()`.
*
* @return array Associative array of $method_name => $callback_info pairs. Each $callback_info must either be
* a callable or an array with key 'callable'. This approach is used to reserve the possibility of
* adding support for further arguments in the future.
*/
public function plugin_functions() {
return array(
'get_svg' => array( $this, 'load' ),
'get_admin_menu_icon' => array( $this, 'get_admin_menu_icon' ),
);
}

/**
* Adds the action and filter hooks to integrate with WordPress.
*/
public function initialize() {}

/**
* Get an SVG from the theme or plugin folder.
*
* @param string $path The SVG path to be loaded.
* @param array $args An array of arguments for the SVG class.
*
* @return string The SVG code.
*/
public function load( $path = null, $args = array() ) {
$final_path = get_template_directory() . $path;

switch ( $path ) {
case ( file_exists( get_template_directory() . $path ) ):
$final_path = get_template_directory() . $path;
break;
case ( file_exists( _LHPBP_PATH . $path ) ):
$final_path = _LHPBP_PATH . $path;
break;
default:
return false;
break;
}

if ( ! file_exists( $final_path ) ) {
return false;
}

if ( mime_content_type( $final_path ) !== 'image/svg' ) {
return false;
}

$args['svg_path'] = $final_path;

$icons[ $path ] = new WPM_Svg_Image( $args );

return $icons[ $path ]->render();
}

/**
* Get an SVG icon for use in WP Admin Menus.
*
* @param string $path The relative path of the image to the plugin / theme root.
*
* @return string The base64 encoded svg.
*/
public function get_admin_menu_icon( $path ) {
$args = array(
'return_type' => 'base64',
'attributes' => array(
'fill' => '#a0a5aa',
'width' => '20',
'height' => '20',
),
);

return $this->load( $path, $args );
}
}
26 changes: 26 additions & 0 deletions build/inc/SVG/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# SVG Component
The SVG component is intended to ease the handling of SVG images in the WordPress
enviroment. It provides two exposed plugin functions, that read, parse and output
the SVG code in the desired manner.

## Relative Paths
The paths passed to the functions are relative paths based on the active theme or
current plugin. The component first looks into the theme folder to find the file
and then in the plugin folder.


## Functions

### get_svg( (sting) $path, (array) $arguments )
The `get_svg` returns the SVG DOM for the file in the given path.

* (string) $path - The given path relative to the current theme or plugin.
* (array) $arguments - An array of arguments to modify the behavior of the function.
- (array) $attributes - An array of HTML attributes applied to the returned SVG tag. Valid array keys are 'class', 'id', 'width', 'height', 'fill'.
- (string) $return_type - The desired return type for the SVG DOM. Valid inputs are 'tag' and 'base64'. Defaults to 'tag'.

## get_admin_menu_icon( (string) $path )
A wrapper for the `get_svg` function that provides the fitting arguments to use
SVGs in admin menu items.

* (string) $path - The given path relative to the current theme or plugin.
147 changes: 147 additions & 0 deletions build/inc/SVG/WPM_Svg_Image.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
<?php
/**
* The class that holds one svg image.
*
* @package lhpbp/SVG
*/

namespace WpMunich\lhpbp\SVG;
use \DOMDocument;

defined( 'ABSPATH' ) || exit;

/**
* Class that handles one svg image.
*/
class WPM_Svg_Image {

/**
* The DOMDocument representation of the SVG.
*
* @var DOMDocument
*/
private $dom_document;

/**
* The SVG DOMElement.
*
* @var DOMElement
*/
private $svg;

/**
* An array of html attributes that are applied to the svg tag.
*
* @var array
*/
private $attributes = array();

/**
* The return type for the render function.
*
* @var string
*/
private $return_type = 'tag';

/**
* The class constructor.
*
* @param array $args An array of arguments for the SVG class.
* [
* 'svg_path' => (string) The absolute path to the svg image file.
* 'attributes' => (array) An array of HTML attributes that are applied to the SVG tag.
* 'return_type' => (string) Can be one of 'tag', 'base64'. Defaults to 'tag'.
* ].
*/
public function __construct( $args = array() ) {
$args = wp_parse_args(
$args,
array(
'svg_path' => false,
'attributes' => array(),
'return_type' => 'tag',
)
);

$this->attributes = $this->parse_attributes( $args['attributes'] );
$this->return_type = $args['return_type'];

if ( $args['svg_path'] ) {
$this->load( $args['svg_path'] );
}
}

/**
* Load the svg and store it as a DOMDocument.
*
* @param string $svg_path The absolute path to the SVG.
*
* @return boolean True on success, false on failure
*/
public function load( $svg_path ) {
if ( ! file_exists( $svg_path ) ) {
return false;
}

if ( mime_content_type( $svg_path ) !== 'image/svg' ) {
return false;
}

$this->dom_document = new DOMDocument();
$this->dom_document->loadXML( file_get_contents( $svg_path ) );
$this->svg = $this->dom_document->getElementsByTagName( 'svg' )->item( 0 );

return true;
}

/**
* Render the SVG tag.
*
* @return string The SVG HTML tag.
*/
public function render() {
if ( ! $this->svg instanceof \DOMElement ) {
return false;
}

$this->apply_attributes();
$html = $this->svg->C14N();

if ( $this->return_type === 'base64' ) {
return 'data:image/svg+xml;base64,' . base64_encode( $html );
}

return $html;
}

/**
* Apply the parsed attributes to the SVG.
*
* @return void
*/
private function apply_attributes() {
foreach ( $this->attributes as $key => $value ) {
$this->svg->setAttribute( $key, $value );
}
}

/**
* Parse attributes, so only valid and allowed attributes get applied.
*
* @param array $attributes An array of HTML attributes.
*
* @return array A parsed array of HTML attributes.
*/
private function parse_attributes( $attributes ) {
$allowed_attributes = array( 'class', 'id', 'width', 'height', 'fill' );

$parsed_attributes = array();
foreach ( $attributes as $key => $value ) {
if ( in_array( $key, $allowed_attributes, true ) ) {
$parsed_attributes[ $key ] = esc_attr( $value );
}
}

return $parsed_attributes;
}
}
Loading

0 comments on commit 603d6b2

Please sign in to comment.