Instantly share code, notes, and snippets.
Last active
October 15, 2024 13:41
-
Star
(6)
6
You must be signed in to star a gist -
Fork
(0)
0
You must be signed in to fork a gist
-
Save mkkeck/84fe5fda939002fcf210d66b99de7c0f to your computer and use it in GitHub Desktop.
Patched WordPress block `core/social-link` to allow theme developers to register own social services
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace PatchBlocks; | |
use WP_Block; | |
/** | |
* Class Editor_Social_Link. | |
* | |
* Patch and register the `core/social-link` block if WordPress Gutenberg | |
* is supported and enabled. | |
* | |
* @package PatchBlocks | |
* @author Michael Keck, [email protected] | |
* | |
* ----------------------------------------------------------------------------- | |
* MIT License | |
* | |
* Copyright (c) 2024 Michael Keck < [email protected] > | |
* | |
* Permission is hereby granted, free of charge, to any person obtaining a copy | |
* of this software and associated documentation files (the "Software"), to deal | |
* in the Software without restriction, including without limitation the rights | |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
* copies of the Software, and to permit persons to whom the Software is | |
* furnished to do so, subject to the following conditions: | |
* | |
* The above copyright notice and this permission notice shall be included in all | |
* copies or substantial portions of the Software. | |
* | |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
* SOFTWARE. | |
* ----------------------------------------------------------------------------- | |
*/ | |
class Editor_Social_Link { | |
/** | |
* The current class instance. | |
* | |
* @var self | |
* @see instance() | |
*/ | |
private static $_instance; | |
/** | |
* @var array Fallback service for unknown social services. | |
*/ | |
private $fallback; | |
/** | |
* @var array Social media services | |
*/ | |
private $services; | |
/** | |
* Load social services | |
*/ | |
private function load_services() { | |
// Base SVG-Element | |
$svg_element = '<svg' | |
. ' xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"' | |
. ' width="24" height="24"' | |
. ' role="img" aria-hidden="true" focusable="false">%s</svg>'; | |
// Fallback social service is unknown, or no service was defined | |
$this->fallback = [ | |
'link' => [ | |
'name' => 'Share', | |
'keywords' => ['link', 'share'], | |
'icon' => sprintf( | |
$svg_element, | |
'<path d="M9 11.8l6.1-4.5c.1.4.4.7.9.7h2c.6 0 1-.4 1-1V5c0-.6-.4-1-1-1h-2c-.6 0-1 .4-1 1v.4l-6.4 4.8c-.2-.1-.4-.2-.6-.2H6c-.6 0-1 .4-1 1v2c0 .6.4 1 1 1h2c.2 0 .4-.1.6-.2l6.4 4.8v.4c0 .6.4 1 1 1h2c.6 0 1-.4 1-1v-2c0-.6-.4-1-1-1h-2c-.5 0-.8.3-.9.7L9 12.2v-.4z"/>' | |
) | |
], | |
'feed' => [ | |
'name' => 'RSS Feed', | |
'icon' => sprintf( | |
$svg_element, | |
'<path d="M2,8.667V12c5.515,0,10,4.485,10,10h3.333C15.333,14.637,9.363,8.667,2,8.667z M2,2v3.333 c9.19,0,16.667,7.477,16.667,16.667H22C22,10.955,13.045,2,2,2z M4.5,17C3.118,17,2,18.12,2,19.5S3.118,22,4.5,22S7,20.88,7,19.5 S5.882,17,4.5,17z"/>' | |
), | |
'keywords' => ['feed', 'rss', 'atom', 'rss-feed'], | |
], | |
'mail' => [ | |
'name' => 'Mail', | |
'icon' => sprintf( | |
$svg_element, | |
'<path d="M20,4H4C2.895,4,2,4.895,2,6v12c0,1.105,0.895,2,2,2h16c1.105,0,2-0.895,2-2V6C22,4.895,21.105,4,20,4z M20,8.236l-8,4.882 L4,8.236V6h16V8.236z" />' | |
), | |
'keywords' => ['email', 'e-mail'], | |
], | |
]; | |
/** | |
* Filters the json file path. | |
* | |
* Example: | |
* | |
* add_filter( | |
* 'social_services_json', function() { | |
* return get_stylesheet_directory() . 'social-services.json'; | |
* }); | |
* | |
* @param string $file Absolute path to the json file with services. | |
*/ | |
$json_file = apply_filters( | |
'social_services_json', | |
rtrim(get_stylesheet_directory(), '/\\') . '/social-services.json' | |
); | |
/** | |
* Load data from JSON-file if it exists and is readable. | |
* | |
* The json-data must include the root key `socialServices`. | |
* Example JSON-Data (in JSON-File): | |
* | |
* { | |
* "socialServices": [ | |
* "share": { | |
* "name": "Share" | |
* "icon": "<svg ...><path d='...' /></svg>", | |
* "keywords": ["optional", "key", "words"] | |
* } | |
* ] | |
* } | |
*/ | |
if (!empty($json_file) && file_exists($json_file)) { | |
$json_data = file_get_contents($json_file); | |
if (!empty($json_data)) { | |
$json_data = json_decode($json_data, true); | |
if (is_array($json_data) && !empty($json_data['socialServices'])) { | |
$this->services = array_merge( | |
$this->fallback, | |
$json_data['socialServices'] | |
); | |
return; | |
} | |
} | |
} | |
// Default social services, if no json file was found. | |
// These services are filterable with 'social_services_data' - hook. | |
$this->services = [ | |
'facebook' => [ | |
'name' => 'Facebook', | |
'icon' => sprintf( | |
$svg_element, | |
'<path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"/>' | |
) | |
], | |
'instagram' => [ | |
'name' => 'Instagram', | |
'icon' => sprintf( | |
$svg_element, | |
'<path d="M12,4.622c2.403,0,2.688,0.009,3.637,0.052c0.877,0.04,1.354,0.187,1.671,0.31c0.42,0.163,0.72,0.358,1.035,0.673 c0.315,0.315,0.51,0.615,0.673,1.035c0.123,0.317,0.27,0.794,0.31,1.671c0.043,0.949,0.052,1.234,0.052,3.637 s-0.009,2.688-0.052,3.637c-0.04,0.877-0.187,1.354-0.31,1.671c-0.163,0.42-0.358,0.72-0.673,1.035 c-0.315,0.315-0.615,0.51-1.035,0.673c-0.317,0.123-0.794,0.27-1.671,0.31c-0.949,0.043-1.233,0.052-3.637,0.052 s-2.688-0.009-3.637-0.052c-0.877-0.04-1.354-0.187-1.671-0.31c-0.42-0.163-0.72-0.358-1.035-0.673 c-0.315-0.315-0.51-0.615-0.673-1.035c-0.123-0.317-0.27-0.794-0.31-1.671C4.631,14.688,4.622,14.403,4.622,12 s0.009-2.688,0.052-3.637c0.04-0.877,0.187-1.354,0.31-1.671c0.163-0.42,0.358-0.72,0.673-1.035 c0.315-0.315,0.615-0.51,1.035-0.673c0.317-0.123,0.794-0.27,1.671-0.31C9.312,4.631,9.597,4.622,12,4.622 M12,3 C9.556,3,9.249,3.01,8.289,3.054C7.331,3.098,6.677,3.25,6.105,3.472C5.513,3.702,5.011,4.01,4.511,4.511 c-0.5,0.5-0.808,1.002-1.038,1.594C3.25,6.677,3.098,7.331,3.054,8.289C3.01,9.249,3,9.556,3,12c0,2.444,0.01,2.751,0.054,3.711 c0.044,0.958,0.196,1.612,0.418,2.185c0.23,0.592,0.538,1.094,1.038,1.594c0.5,0.5,1.002,0.808,1.594,1.038 c0.572,0.222,1.227,0.375,2.185,0.418C9.249,20.99,9.556,21,12,21s2.751-0.01,3.711-0.054c0.958-0.044,1.612-0.196,2.185-0.418 c0.592-0.23,1.094-0.538,1.594-1.038c0.5-0.5,0.808-1.002,1.038-1.594c0.222-0.572,0.375-1.227,0.418-2.185 C20.99,14.751,21,14.444,21,12s-0.01-2.751-0.054-3.711c-0.044-0.958-0.196-1.612-0.418-2.185c-0.23-0.592-0.538-1.094-1.038-1.594 c-0.5-0.5-1.002-0.808-1.594-1.038c-0.572-0.222-1.227-0.375-2.185-0.418C14.751,3.01,14.444,3,12,3L12,3z M12,7.378 c-2.552,0-4.622,2.069-4.622,4.622S9.448,16.622,12,16.622s4.622-2.069,4.622-4.622S14.552,7.378,12,7.378z M12,15 c-1.657,0-3-1.343-3-3s1.343-3,3-3s3,1.343,3,3S13.657,15,12,15z M16.804,6.116c-0.596,0-1.08,0.484-1.08,1.08 s0.484,1.08,1.08,1.08c0.596,0,1.08-0.484,1.08-1.08S17.401,6.116,16.804,6.116z"/>' | |
) | |
], | |
'pinterest' => [ | |
'name' => 'Pinterest', | |
'icon' => sprintf( | |
$svg_element, | |
'<path d="M12.289,2C6.617,2,3.606,5.648,3.606,9.622c0,1.846,1.025,4.146,2.666,4.878c0.25,0.111,0.381,0.063,0.439-0.169 c0.044-0.175,0.267-1.029,0.365-1.428c0.032-0.128,0.017-0.237-0.091-0.362C6.445,11.911,6.01,10.75,6.01,9.668 c0-2.777,2.194-5.464,5.933-5.464c3.23,0,5.49,2.108,5.49,5.122c0,3.407-1.794,5.768-4.13,5.768c-1.291,0-2.257-1.021-1.948-2.277 c0.372-1.495,1.089-3.112,1.089-4.191c0-0.967-0.542-1.775-1.663-1.775c-1.319,0-2.379,1.309-2.379,3.059 c0,1.115,0.394,1.869,0.394,1.869s-1.302,5.279-1.54,6.261c-0.405,1.666,0.053,4.368,0.094,4.604 c0.021,0.126,0.167,0.169,0.25,0.063c0.129-0.165,1.699-2.419,2.142-4.051c0.158-0.59,0.817-2.995,0.817-2.995 c0.43,0.784,1.681,1.446,3.013,1.446c3.963,0,6.822-3.494,6.822-7.833C20.394,5.112,16.849,2,12.289,2"/>' | |
) | |
], | |
/* Twitter is now X * | |
'twitter' => [ | |
'name' => 'Twitter', | |
'icon' => sprintf( | |
$svg_element, | |
'<path d="M22.23,5.924c-0.736,0.326-1.527,0.547-2.357,0.646c0.847-0.508,1.498-1.312,1.804-2.27 c-0.793,0.47-1.671,0.812-2.606,0.996C18.324,4.498,17.257,4,16.077,4c-2.266,0-4.103,1.837-4.103,4.103 c0,0.322,0.036,0.635,0.106,0.935C8.67,8.867,5.647,7.234,3.623,4.751C3.27,5.357,3.067,6.062,3.067,6.814 c0,1.424,0.724,2.679,1.825,3.415c-0.673-0.021-1.305-0.206-1.859-0.513c0,0.017,0,0.034,0,0.052c0,1.988,1.414,3.647,3.292,4.023 c-0.344,0.094-0.707,0.144-1.081,0.144c-0.264,0-0.521-0.026-0.772-0.074c0.522,1.63,2.038,2.816,3.833,2.85 c-1.404,1.1-3.174,1.756-5.096,1.756c-0.331,0-0.658-0.019-0.979-0.057c1.816,1.164,3.973,1.843,6.29,1.843 c7.547,0,11.675-6.252,11.675-11.675c0-0.178-0.004-0.355-0.012-0.531C20.985,7.47,21.68,6.747,22.23,5.924z" />' | |
) | |
], | |
**/ | |
'x' => [ | |
'name' => 'X', | |
'icon' => sprintf( | |
$svg_element, | |
'<path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" />' | |
) | |
], | |
'youtube' => [ | |
'name' => 'YouTube', | |
'icon' => sprintf( | |
$svg_element, | |
'<path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z" />' | |
) | |
], | |
'linkedin' => [ | |
'name' => 'LinkedIn', | |
'icon' => sprintf( | |
$svg_element, | |
'<path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"/>' | |
) | |
], | |
'xing' => [ | |
'name' => 'XING', | |
'icon' => sprintf( | |
$svg_element, | |
'<path d="m10.7 9.9-3.1 5.5c-.2.4-.5.6-.8.6h-2.9c-.3 0-.6-.4-.4-.7l3.1-5.4-2-3.3c-.2-.3.1-.7.5-.7h2.9c.3 0 .5.2.7.6zm3.4 4 4.1 7.5c.2.3.1.6-.3.6h-3c-.3 0-.6-.2-.8-.6l-4.1-7.5 6.5-11.4c.2-.4.4-.5.7-.5h2.9c.4 0 .6.3.5.5z"/>' | |
) | |
] | |
]; | |
/** | |
* Filters the social services. | |
* | |
* Example: | |
* | |
* add_filter( | |
* 'social_services_data', function($social_services) { | |
* return array_merge($social_services, array( | |
* 'facebook' => array( | |
* 'name' => 'Facebook', | |
* 'icon' => '<svg><path ...></svg>', | |
* 'keywords' => ['fb', 'facebook'] // <- optional | |
* ), | |
* // ... | |
* )); | |
* }); | |
* | |
* @param array $services Social services. | |
*/ | |
$this->services = apply_filters( | |
'social_services_data', | |
$this->services | |
); | |
// Add fallback to services | |
$this->services = array_merge( | |
$this->fallback, | |
$this->services | |
); | |
} | |
/** | |
* Prepare the inline script for registering social link services | |
* (variations) for the `core/social-links`. | |
* | |
* @return string For printing the inline script at footer on admin pages | |
*/ | |
private function prepare_inline_script() { | |
$services = []; | |
foreach ($this->services as $service => $data) { | |
$item = [ | |
'name' => $service, | |
'attributes' => [ | |
'service' => $service | |
], | |
'title' => $data['name'], | |
'icon' => $data['icon'] | |
]; | |
if (!empty($date['keywords'])) { | |
$item['keywords'] = $data['keywords']; | |
} | |
if ($service === 'link') { | |
$item['icon'] = sprintf( | |
'<svg' | |
. ' xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"' | |
. ' width="24" height="24"' | |
. ' role="img" aria-hidden="true" focusable="false">%s</svg>', | |
'<path d="M19.647,16.706a1.134,1.134,0,0,0-.343-.833l-2.549-2.549a1.134,1.134,0,0,0-.833-.343,1.168,1.168,0,0,0-.883.392l.233.226q.2.189.264.264a2.922,2.922,0,0,1,.184.233.986.986,0,0,1,.159.312,1.242,1.242,0,0,1,.043.337,1.172,1.172,0,0,1-1.176,1.176,1.237,1.237,0,0,1-.337-.043,1,1,0,0,1-.312-.159,2.76,2.76,0,0,1-.233-.184q-.073-.068-.264-.264l-.226-.233a1.19,1.19,0,0,0-.4.895,1.134,1.134,0,0,0,.343.833L15.837,19.3a1.13,1.13,0,0,0,.833.331,1.18,1.18,0,0,0,.833-.318l1.8-1.789a1.12,1.12,0,0,0,.343-.821Zm-8.615-8.64a1.134,1.134,0,0,0-.343-.833L8.163,4.7a1.134,1.134,0,0,0-.833-.343,1.184,1.184,0,0,0-.833.331L4.7,6.473a1.12,1.12,0,0,0-.343.821,1.134,1.134,0,0,0,.343.833l2.549,2.549a1.13,1.13,0,0,0,.833.331,1.184,1.184,0,0,0,.883-.38L8.728,10.4q-.2-.189-.264-.264A2.922,2.922,0,0,1,8.28,9.9a.986.986,0,0,1-.159-.312,1.242,1.242,0,0,1-.043-.337A1.172,1.172,0,0,1,9.254,8.079a1.237,1.237,0,0,1,.337.043,1,1,0,0,1,.312.159,2.761,2.761,0,0,1,.233.184q.073.068.264.264l.226.233a1.19,1.19,0,0,0,.4-.895ZM22,16.706a3.343,3.343,0,0,1-1.042,2.488l-1.8,1.789a3.536,3.536,0,0,1-4.988-.025l-2.525-2.537a3.384,3.384,0,0,1-1.017-2.488,3.448,3.448,0,0,1,1.078-2.561l-1.078-1.078a3.434,3.434,0,0,1-2.549,1.078,3.4,3.4,0,0,1-2.5-1.029L3.029,9.794A3.4,3.4,0,0,1,2,7.294,3.343,3.343,0,0,1,3.042,4.806l1.8-1.789A3.384,3.384,0,0,1,7.331,2a3.357,3.357,0,0,1,2.5,1.042l2.525,2.537a3.384,3.384,0,0,1,1.017,2.488,3.448,3.448,0,0,1-1.078,2.561l1.078,1.078a3.551,3.551,0,0,1,5.049-.049l2.549,2.549A3.4,3.4,0,0,1,22,16.706Z"/>' | |
) | |
; | |
} | |
$services[] = $item; | |
} | |
ob_start(); | |
?> | |
<script> | |
(function(blocks, createElem, domReady) { | |
if (typeof domReady !== "function") { | |
console.error("Really strange and mysterious: `wp.domReady` is not a function or undefined."); | |
return; | |
} | |
/** | |
* Create an SVG-Element from previously parsed SVG-String | |
* @return {NodeListOf<ChildNode>} | |
* @return {*} | |
*/ | |
function createSvgElem(parsedNodes, svgIndex) { | |
svgIndex = !svgIndex ? 'svgiconelem_' + index++ : svgIndex; | |
return parsedNodes.map(function(elem) { | |
let | |
attributes = elem.attributes, | |
children = elem.childNodes, | |
name = elem.nodeName, | |
value = elem.nodeValue; | |
let attr = {}; | |
if (svgIndex) { | |
attr.key = svgIndex; | |
} | |
if (attributes) { | |
Array.from(attributes).forEach(function(attribute) { | |
if (attribute.name === "style") { | |
let items = attribute.nodeValue.split(";"); | |
let styles = {}; | |
items.forEach(function(item) { | |
let attr = item.split(":"); | |
if (attr[0] && attr[1]) { | |
styles[attr[0]] = attr[1]; | |
} | |
}); | |
attr[attribute.name] = styles; | |
} | |
else { | |
attr[attribute.name] = attribute.nodeValue; | |
} | |
}); | |
} | |
if (name) { | |
let childs = []; | |
if (children && Array.isArray(Array.from(children))) { | |
childs = createSvgElem(Array.from(children), 'socialsvgelem_' + index + '_inner'); | |
} | |
return createElem(name, attr, childs); | |
} | |
return value; | |
}); | |
} | |
/** | |
* Create the SVG icon to usable as component for the block | |
* @param {string} rawSvgStr for example '<svg ...><path d"=..."/></svg>' | |
* @param {string} svgId Unique ID for the SVG file, could be the service.name | |
* @return {*} | |
*/ | |
function createSvgIcon(rawSvgStr, svgId) { | |
let nodes = new DOMParser().parseFromString(rawSvgStr, "text/html").body.childNodes; | |
return createSvgElem(Array.from(nodes), !!svgId ? svgId : 'socialsvgelem_' + (index++)); | |
} | |
let blockName = "core/social-link", | |
index = 0, | |
services = <?php echo json_encode($services); ?>; | |
/** | |
* Unregister WordPress predefined variations and register variations | |
* based on user defined social services | |
*/ | |
domReady(function() { | |
// unregister WordPress/Gutenberg core variations | |
let coreVariations = blocks.getBlockVariations(blockName, "block"); | |
if (coreVariations) { | |
Array.from(coreVariations).forEach(function(variation) { | |
blocks.unregisterBlockVariation(blockName, variation); | |
}); | |
} | |
// register our own variations | |
services.forEach(function(service) { | |
blocks.registerBlockVariation(blockName, { | |
name: service.name, | |
title: service.title, | |
attributes: service.attributes, | |
keywords: !!service.keywords ? service.keywords : [service.name], | |
icon: function() { | |
return createSvgIcon(service.icon, service.name); | |
} | |
}); | |
}); | |
// show correct icon in toolbar if selected | |
blocks.getBlockVariations(blockName, "block").forEach(function(variation) { | |
if (variation.isActive) { | |
return; | |
} | |
variation.isActive = function(bockAttr, variationAttr) { | |
return bockAttr.service === variationAttr.service; | |
}; | |
}); | |
}); | |
})(wp.blocks, wp.element.createElement, wp.domReady); | |
</script> | |
<?php | |
$script = ob_get_contents(); | |
ob_end_clean(); | |
return $script; | |
} | |
/** | |
* Get color styles | |
* | |
* @param array $context | |
* @return string | |
*/ | |
private function color_styles($context) { | |
$styles = []; | |
if (array_key_exists('iconColorValue', $context)) { | |
$styles[] = 'color: ' . $context['iconColorValue'] . '; '; | |
} | |
if (array_key_exists('iconBackgroundColorValue', $context)) { | |
$styles[] = 'background-color: ' . $context['iconBackgroundColorValue'] . '; '; | |
} | |
return implode('', $styles); | |
} | |
/** | |
* Get color class names | |
* | |
* @param array $context | |
* @return string | |
*/ | |
private function color_classes($context) { | |
$classes = array(); | |
if (array_key_exists('iconColor', $context)) { | |
$classes[] = 'has-' . $context['iconColor'] . '-color'; | |
} | |
if (array_key_exists('iconBackgroundColor', $context)) { | |
$classes[] = 'has-' . $context['iconBackgroundColor'] . '-background-color'; | |
} | |
return implode( ' ', $classes ); | |
} | |
/** | |
* Get specific service | |
* | |
* @param string $service | |
* @param string $field | |
* @return array|string | |
*/ | |
private function get_services($service = '', $field = '') { | |
$field = (!empty($field) && ($field === 'icon' || $field === 'name') ? $field : ''); | |
if (!empty($service)) { | |
$service = !empty($this->services[$service]) ? $this->services[$service] : $this->fallback; | |
return !empty($field) ? $service[$field] : $service; | |
} | |
return $this->services; | |
} | |
/** | |
* Print the inline script for registering social link services | |
* (variations) for the `core/social-links` on pages which use | |
* the block editor. | |
*/ | |
public function print_inline_script() { | |
$current_screen = get_current_screen(); | |
if ( | |
!wp_doing_ajax() && | |
!empty($current_screen) && | |
method_exists($current_screen, 'is_block_editor') && | |
$current_screen->is_block_editor() | |
) { | |
echo $this->prepare_inline_script(); | |
} | |
} | |
/** | |
* Render the `core/social-link` block on server side. | |
* | |
* @param array $attributes The block attributes. | |
* @param string $content InnerBlocks content of the Block. | |
* @param WP_Block $block Block object. | |
* @return string Rendered HTML of the referenced block. | |
*/ | |
public function render_block($attributes, $content, $block) { | |
$url = isset($attributes['url']) ? $attributes['url'] : false; | |
// Don't render a link if there is no URL set. | |
if (empty($url)) { | |
return ''; | |
} | |
if (is_email($url) && !str_starts_with($url, 'mailto:')) { | |
$url = 'mailto:' . $url; | |
} else if (!parse_url($url, PHP_URL_SCHEME) && !str_starts_with($url, '//')) { | |
$url = 'https://' . $url; | |
} | |
$rel = isset($attributes['rel']) ? $attributes['rel'] : ''; | |
$service = isset($attributes['service']) ? $attributes['service'] : 'share'; | |
$label = isset($attributes['label']) ? $attributes['label'] : sprintf( | |
/* translators: %1$s: Social-network name. %2$s: URL. */ | |
__( '%1$s: %2$s' ), | |
$this->get_services($service, 'name'), | |
$url | |
); | |
$class_names = [ | |
'wp-social-link', | |
'wp-social-link-' . $service, | |
]; | |
if (isset($attributes['className'])) { | |
$class_names[] = $attributes['className']; | |
} | |
$color_classes = $this->color_classes($block->context); | |
if (!empty($color_classes)) { | |
$class_names[] = $color_classes; | |
} | |
$new_tab = ( | |
isset($block->context['openInNewTab']) && | |
$block->context['openInNewTab'] | |
); | |
$show_labels = ( | |
isset($block->context['showLabels']) && | |
$block->context['showLabels'] | |
); | |
$link_icon = $this->get_services($service, 'icon'); | |
$link_attributes = [ | |
'href="' . esc_url($url). '"', | |
'aria-label="' . esc_attr($label) . '"', | |
'class="wp-block-social-link-anchor"' | |
]; | |
$link_rel = []; | |
if (!empty($rel)) { | |
$link_rel[] = esc_attr($rel); | |
} | |
if ($new_tab) { | |
$link_attributes[] = 'target="_blank"'; | |
array_push($link_rel, 'noopener', 'nofollow'); | |
} | |
if (!empty($link_rel)) { | |
$link_attributes[] = 'rel="' . join(' ', $link_rel) . '"'; | |
} | |
$item_attributes = get_block_wrapper_attributes([ | |
'class' => join(' ', $class_names), | |
'style' => $this->color_styles($block->context) | |
]); | |
$link_label = sprintf( | |
'<span class="wp-block-social-link-label%1$s">%2$s</span>', | |
($show_labels ? '' : ' screen-reader-text'), | |
esc_html($label) | |
); | |
return sprintf( | |
/** @lang: text */ | |
'<li %1$s><a %2$s>%3$s%4$s</a></li>', | |
$item_attributes, join(' ', $link_attributes), $link_icon, $link_label | |
); | |
} | |
/** | |
* Register render callback for the patched block. | |
* | |
* @param array $args | |
* @param string $blockname | |
* @return array New block arguments | |
*/ | |
public function register_block_args($args, $blockname) { | |
if ($blockname === 'core/social-link') { | |
$args['render_callback'] = [$this, 'render_block']; | |
} | |
return $args; | |
} | |
/** | |
* Constructor. | |
* | |
* Adds actions and filters for the patched block. | |
* | |
* @global string $pagenow The filename of the current screen. | |
*/ | |
private function __construct() { | |
global $pagenow; | |
// Load social services | |
$this->load_services(); | |
// Filter block arguments | |
add_filter( | |
'register_block_type_args', | |
[$this, 'register_block_args'], 10, 3 | |
); | |
// add hook for printing the required editor inline script | |
if ( | |
!wp_doing_ajax() && is_admin() && | |
($pagenow === 'post.php' || $pagenow === 'post-new.php') | |
) { | |
add_action( | |
'admin_print_footer_scripts', | |
[$this, 'print_inline_script'] | |
); | |
} | |
} | |
/** | |
* Get class instance | |
* @return self | |
*/ | |
public static function instance() { | |
if (!isset(self::$_instance)) { | |
self::$_instance = new self(); | |
} | |
return self::$_instance; | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment