Revert "Update code to comply with WP Coding Standards (#38)"

This reverts commit 02c6c1c362.
This commit is contained in:
Ben Goldsworthy 2021-02-26 08:07:03 +00:00 committed by GitHub
parent 02c6c1c362
commit 5982f12bd5
30 changed files with 3935 additions and 4328 deletions

3
.gitignore vendored
View file

@ -1,4 +1 @@
.phpdoc/
vendor/
*.bak

View file

@ -14,7 +14,6 @@ Featured on [wpmudev](http://premium.wpmudev.org/blog/12-surprisingly-useful-wor
1. Read the contributing guidelines
1. Clone this repository (`git clone git@github.com:markcheret/footnotes.git`)
- We recommend that you use [VVV](https://varyingvagrantvagrants.org/) for your development environment
1. Install [Composer](https://getcomposer.org/download/), if you don't have it already
1. Install dependencies (`composer install`)
1. Create a new branch from `main` (`git checkout -b <your-descriptive-branch-name>`)
@ -26,9 +25,8 @@ Featured on [wpmudev](http://premium.wpmudev.org/blog/12-surprisingly-useful-wor
1. Run PHP_CodeSniffer on the file(s) you want to check (`./vendor/bin/phpcs --standard="WordPress" --colors --encoding=utf-8 -n -p <file(s)>`)
1. (If applicable) run the PHP Code Beautifier and Formatter to attempt to automatically fix any errors (`./vendor/bin/phpcbf --standard="WordPress" --encoding=utf-8 -p <file(s)>`)
- Add the `-n` flag to ignore warnings (i.e., show only errors)
- Add the `-s` flag to show sniff codes (used for disabling errors in the code with `phpcs disable:<sniff code>` — MAKE SURE THAT YOU HAVE `phpcs enable` AT THE EARLIEST POINT POSSIBLE, and provide a justification for disabling the sniff code)
- You can run either across the entire project by adding the argument `--ignore=*/vendor/*` and targetting the file `./**/*.php`
- You may have to enable double-wildcards in your console first (`shopt -s globstar`)
- Add the `-s` flag to show sniff codes (used for disabling errors in the code with `phpcs disable:<sniff code>` — MAKE SURE THAT YOU HAVE `phpcs enable` AT THE EARLIEST POINT POSSIBLE, and provide a justification for disabling the sniff code)
- You can run either across the entire project by adding the argument `--ignore=*/vendor/*` and targetting the file `./*.php ./**/*.php`
## Updating Documentation

View file

@ -1,4 +0,0 @@
#!/bin/sh
cp contrib/pre-commit .git/hooks/pre-commit
chmod +x .git/hooks/pre-commit

View file

@ -1,32 +1,39 @@
<?php // phpcs:disable WordPress.Files.FileName.InvalidClassFileName
<?php
/**
* Includes the Plugin Constants class to load all Plugin constant vars like Plugin name, etc.
*
* @filesource
* @package footnotes
* @since 1.5.0
* @date 12.09.14 10:56
* @author Stefan Herndler
* @since 1.5.0 12.09.14 10:56
*
* @since 2.0.4 add Public Plugin name for dashboard heading 2020-11-01T0452+0100
* Edited for:
* 2.0.4 add Public Plugin name for dashboard heading 2020-11-01T0452+0100
*
* Last modified: 2021-02-18T2027+0100
*/
/**
* Contains all Plugin Constants. Contains no Method or Property.
*
* @author Stefan Herndler
* @since 1.5.0
*/
class MCI_Footnotes_Config {
/**
* Internal Plugin name.
*
* @author Stefan Herndler
* @since 1.5.0
* @var string
*/
const C_STR_PLUGIN_NAME = 'footnotes';
const C_STR_PLUGIN_NAME = "footnotes";
/**
* Public Plugin name.
*
* @author Stefan Herndler
* @since 1.5.0
* @var string
*
@ -51,6 +58,7 @@ class MCI_Footnotes_Config {
/**
* Html tag for the LOVE symbol.
*
* @author Stefan Herndler
* @since 1.5.0
* @var string
*/
@ -67,6 +75,7 @@ class MCI_Footnotes_Config {
/**
* Short code to DON'T display the 'LOVE ME' slug on certain pages.
*
* @author Stefan Herndler
* @since 1.5.0
* @var string
*/

View file

@ -3,16 +3,20 @@
* Includes the Convert Class.
*
* @filesource
* @package footnotes
* @since 1.5.0
* @date 12.09.14 10:56
* @author Stefan Herndler
* @since 1.5.0 12.09.14 10:56
*
* Edited:
* @since 2.2.0 add lowercase Roman 2020-12-12T1540+0100
*
* Last modified: 2020-12-12T1541+0100
*/
/**
* Converts data types and Footnotes specific values.
*
* @author Stefan Herndler
* @since 1.5.0
*/
class MCI_Footnotes_Convert {
@ -20,29 +24,30 @@ class MCI_Footnotes_Convert {
/**
* Converts a integer into the user-defined counter style for the footnotes.
*
* @author Stefan Herndler
* @since 1.5.0
* @param int $p_int_index Index to be converted.
* @param string $p_str_convert_style Style of the new/converted Index.
* @param int $p_int_Index Index to be converted.
* @param string $p_str_ConvertStyle Style of the new/converted Index.
* @return string Converted Index as string in the defined counter style.
*
* Edited:
* @since 2.2.0 lowercase Roman numerals supported
*/
public static function index( $p_int_index, $p_str_convert_style = 'arabic_plain' ) {
switch ( $p_str_convert_style ) {
case 'romanic':
return self::to_romanic( $p_int_index, true );
case 'roman_low':
return self::to_romanic( $p_int_index, false );
case 'latin_high':
return self::to_latin( $p_int_index, true );
case 'latin_low':
return self::to_latin( $p_int_index, false );
case 'arabic_leading':
return self::to_arabic_leading( $p_int_index );
case 'arabic_plain':
public static function Index($p_int_Index, $p_str_ConvertStyle = "arabic_plain") {
switch ($p_str_ConvertStyle) {
case "romanic":
return self::toRomanic($p_int_Index, true);
case "roman_low":
return self::toRomanic($p_int_Index, false);
case "latin_high":
return self::toLatin($p_int_Index, true);
case "latin_low":
return self::toLatin($p_int_Index, false);
case "arabic_leading":
return self::toArabicLeading($p_int_Index);
case "arabic_plain":
default:
return $p_int_index;
return $p_int_Index;
}
}
@ -50,174 +55,175 @@ class MCI_Footnotes_Convert {
* Converts an integer into latin ascii characters, either lower or upper-case.
* Function available from A to ZZ ( means 676 footnotes at 1 page possible).
*
* @author Stefan Herndler
* @since 1.0-gamma
* @param int $p_int_value Value/Index to be converted.
* @param bool $p_bool_upper_case True to convert the value to upper case letter, otherwise to lower case.
* @param int $p_int_Value Value/Index to be converted.
* @param bool $p_bool_UpperCase True to convert the value to upper case letter, otherwise to lower case.
* @return string
*/
private static function to_latin( $p_int_value, $p_bool_upper_case ) {
// Output string.
$l_str_return = '';
$l_int_offset = 0;
// Check if the value is higher then 26 = Z.
while ( $p_int_value > 26 ) {
// Increase offset and reduce counter.
$l_int_offset++;
$p_int_value -= 26;
private static function toLatin($p_int_Value, $p_bool_UpperCase) {
// output string
$l_str_Return = "";
$l_int_Offset = 0;
// check if the value is higher then 26 = Z
while ($p_int_Value > 26) {
// increase offset and reduce counter
$l_int_Offset++;
$p_int_Value -= 26;
}
// If offset set (more then Z), then add a new letter in front.
if ( $l_int_offset > 0 ) {
$l_str_return = chr( $l_int_offset + 64 );
// if offset set (more then Z), then add a new letter in front
if ($l_int_Offset > 0) {
$l_str_Return = chr($l_int_Offset + 64);
}
// Add the origin letter.
$l_str_return .= chr( $p_int_value + 64 );
// Return the latin character representing the integer.
if ( $p_bool_upper_case ) {
return strtoupper( $l_str_return );
// add the origin letter
$l_str_Return .= chr($p_int_Value + 64);
// return the latin character representing the integer
if ($p_bool_UpperCase) {
return strtoupper($l_str_Return);
}
return strtolower( $l_str_return );
return strtolower($l_str_Return);
}
/**
* Converts an integer to a leading-0 integer.
*
* @author Stefan Herndler
* @since 1.0-gamma
* @param int $p_int_value Value/Index to be converted.
* @param int $p_int_Value Value/Index to be converted.
* @return string Value with a leading zero.
*/
private static function to_arabic_leading( $p_int_value ) {
// Add a leading 0 if number lower then 10.
if ( $p_int_value < 10 ) {
return '0' . $p_int_value;
private static function toArabicLeading($p_int_Value) {
// add a leading 0 if number lower then 10
if ($p_int_Value < 10) {
return "0" . $p_int_Value;
}
return $p_int_value;
return $p_int_Value;
}
/**
* Converts an integer to a romanic letter.
*
* @author Stefan Herndler
* @since 1.0-gamma
* @param int $p_int_value Value/Index to be converted.
* @param bool $p_bool_upper_case Whether to uppercase.
* @param int $p_int_Value Value/Index to be converted.
* @return string
*
* Edited:
* @since 2.2.0 optionally lowercase (code from Latin) 2020-12-12T1538+0100
*/
private static function to_romanic( $p_int_value, $p_bool_upper_case ) {
// Table containing all necessary romanic letters.
$l_arr_romanic_letters = array(
'M' => 1000,
private static function toRomanic($p_int_Value, $p_bool_UpperCase) {
// table containing all necessary romanic letters
$l_arr_RomanicLetters = array(
'M' => 1000,
'CM' => 900,
'D' => 500,
'D' => 500,
'CD' => 400,
'C' => 100,
'C' => 100,
'XC' => 90,
'L' => 50,
'L' => 50,
'XL' => 40,
'X' => 10,
'X' => 10,
'IX' => 9,
'V' => 5,
'V' => 5,
'IV' => 4,
'I' => 1,
'I' => 1
);
// Return value.
$l_str_return = '';
// Iterate through integer value until it is reduced to 0.
while ( $p_int_value > 0 ) {
foreach ( $l_arr_romanic_letters as $l_str_romanic => $l_int_arabic ) {
if ( $p_int_value >= $l_int_arabic ) {
$p_int_value -= $l_int_arabic;
$l_str_return .= $l_str_romanic;
// return value
$l_str_Return = '';
// iterate through integer value until it is reduced to 0
while ($p_int_Value > 0) {
foreach ($l_arr_RomanicLetters as $l_str_Romanic => $l_int_Arabic) {
if ($p_int_Value >= $l_int_Arabic) {
$p_int_Value -= $l_int_Arabic;
$l_str_Return .= $l_str_Romanic;
break;
}
}
}
// Return romanic letters as string.
if ( $p_bool_upper_case ) {
return strtoupper( $l_str_return );
// return romanic letters as string
if ($p_bool_UpperCase) {
return strtoupper($l_str_Return);
}
return strtolower( $l_str_return );
return strtolower($l_str_Return);
}
/**
* Converts a string depending on its value to a boolean.
*
* @author Stefan Herndler
* @since 1.0-beta
* @param string $p_str_value String to be converted to boolean.
* @param string $p_str_Value String to be converted to boolean.
* @return bool Boolean representing the string.
*/
public static function to_bool( $p_str_value ) {
// Convert string to lower-case to make it easier.
$p_str_value = strtolower( $p_str_value );
// Check if string seems to contain a "true" value.
switch ( $p_str_value ) {
case 'checked':
case 'yes':
case 'true':
case 'on':
case '1':
public static function toBool($p_str_Value) {
// convert string to lower-case to make it easier
$p_str_Value = strtolower($p_str_Value);
// check if string seems to contain a "true" value
switch ($p_str_Value) {
case "checked":
case "yes":
case "true":
case "on":
case "1":
return true;
}
// Nothing found that says "true", so we return false.
// nothing found that says "true", so we return false
return false;
}
/**
* Get a html Array short code depending on Arrow-Array key index.
*
* @author Stefan Herndler
* @since 1.3.2
* @param int $p_int_index Index representing the Arrow. If empty all Arrows are specified.
* @param int $p_int_Index Index representing the Arrow. If empty all Arrows are specified.
* @return array|string Array of all Arrows if Index is empty otherwise html tag of a specific arrow.
*/
public static function get_arrow( $p_int_index = -1 ) {
// Define all possible arrows.
$l_arr_arrows = array( '&#8593;', '&#8613;', '&#8607;', '&#8617;', '&#8626;', '&#8629;', '&#8657;', '&#8673;', '&#8679;', '&#65514;' );
// Convert index to an integer.
if ( ! is_int( $p_int_index ) ) {
$p_int_index = intval( $p_int_index );
public static function getArrow($p_int_Index = -1) {
// define all possible arrows
$l_arr_Arrows = array("&#8593;", "&#8613;", "&#8607;", "&#8617;", "&#8626;", "&#8629;", "&#8657;", "&#8673;", "&#8679;", "&#65514;");
// convert index to an integer
if (!is_int($p_int_Index)) {
$p_int_Index = intval($p_int_Index);
}
// Return the whole arrow array.
if ( $p_int_index < 0 || $p_int_index > count( $l_arr_arrows ) ) {
return $l_arr_arrows;
// return the whole arrow array
if ($p_int_Index < 0 || $p_int_Index > count($l_arr_Arrows)) {
return $l_arr_Arrows;
}
// Return a single arrow.
return $l_arr_arrows[ $p_int_index ];
// return a single arrow
return $l_arr_Arrows[$p_int_Index];
}
// phpcs:disable WordPress.PHP.DevelopmentFunctions.error_log_var_dump
// phpcs:disable WordPress.PHP.DevelopmentFunctions.error_log_print_r
/**
* Displays a Variable.
*
* @author Stefan Herndler
* @since 1.5.0
* @param mixed $p_mixed_value The variable to display.
* @return void
* @param mixed $p_mixed_Value
*/
public static function debug( $p_mixed_value ) {
if ( empty( $p_mixed_value ) ) {
var_dump( $p_mixed_value );
public static function debug($p_mixed_Value) {
if (empty($p_mixed_Value)) {
var_dump($p_mixed_Value);
} elseif ( is_array( $p_mixed_value ) ) {
printf( '<pre>' );
print_r( $p_mixed_value );
printf( '</pre>' );
} else if (is_array($p_mixed_Value)) {
printf("<pre>");
print_r($p_mixed_Value);
printf("</pre>");
} elseif ( is_object( $p_mixed_value ) ) {
printf( '<pre>' );
print_r( $p_mixed_value );
printf( '</pre>' );
} else if (is_object($p_mixed_Value)) {
printf("<pre>");
print_r($p_mixed_Value);
printf("</pre>");
} elseif ( is_numeric( $p_mixed_value ) || is_int( $p_mixed_value ) ) {
var_dump( $p_mixed_value );
} else if (is_numeric($p_mixed_Value) || is_int($p_mixed_Value)) {
var_dump($p_mixed_Value);
} elseif ( is_date( $p_mixed_value ) ) {
var_dump( $p_mixed_value );
} else if (is_date($p_mixed_Value)) {
var_dump($p_mixed_Value);
} else {
var_dump( $p_mixed_value );
var_dump($p_mixed_Value);
}
echo '<br/>';
echo "<br/>";
}
// phpcs:disable
}

212
class/dashboard/init.php Normal file
View file

@ -0,0 +1,212 @@
<?php
/**
* Includes the Plugin settings menu.
*
* @filesource
* @author Stefan Herndler
* @since 1.5.0 12.09.14 10:26
*/
/**
* Handles the Settings interface of the Plugin.
*
* @author Stefan Herndler
* @since 1.5.0
*/
class MCI_Footnotes_Layout_Init {
/**
* Slug for the Plugin main menu.
*
* @author Stefan Herndler
* @since 1.5.0
* @var string
*/
const C_STR_MAIN_MENU_SLUG = "mfmmf";
/**
* Plugin main menu name.
*
* @author Stefan Herndler
* @since 1.5.0
* @var string
*/
const C_STR_MAIN_MENU_TITLE = "ManFisher";
/**
*
* @author Stefan Herndler
* @since 1.5.0
* @var array
*/
private $a_arr_SubPageClasses = array();
/**
* Class Constructor. Initializes all WordPress hooks for the Plugin Settings.
*
* @author Stefan Herndler
* @since 1.5.0
*/
public function __construct() {
// iterate through each class define in the current script
foreach(get_declared_classes() as $l_str_ClassName) {
// accept only child classes of the layout engine
if(is_subclass_of($l_str_ClassName, 'MCI_Footnotes_LayoutEngine')) {
/** @var MCI_Footnotes_LayoutEngine $l_obj_Class */
$l_obj_Class = new $l_str_ClassName();
// append new instance of the layout engine sub class
$this->a_arr_SubPageClasses[$l_obj_Class->getPriority()] = $l_obj_Class;
}
}
ksort($this->a_arr_SubPageClasses);
// register hooks/actions
add_action('admin_init', array($this, 'initializeSettings'));
add_action('admin_menu', array($this, 'registerMainMenu'));
// register AJAX callbacks for Plugin information
add_action("wp_ajax_nopriv_footnotes_getPluginInfo", array($this, "getPluginMetaInformation"));
add_action("wp_ajax_footnotes_getPluginInfo", array($this, "getPluginMetaInformation"));
}
/**
* Initializes all sub pages and registers the settings.
*
* @author Stefan Herndler
* @since 1.5.0
*/
public function initializeSettings() {
MCI_Footnotes_Settings::instance()->RegisterSettings();
// iterate though each sub class of the layout engine and register their sections
/** @var MCI_Footnotes_LayoutEngine $l_obj_LayoutEngineSubClass */
foreach($this->a_arr_SubPageClasses as $l_obj_LayoutEngineSubClass) {
$l_obj_LayoutEngineSubClass->registerSections();
}
}
/**
* Registers the new main menu for the WordPress dashboard.
* Registers all sub menu pages for the new main menu.
*
* @author Stefan Herndler
* @since 1.5.0
* @see http://codex.wordpress.org/Function_Reference/add_menu_page
*/
public function registerMainMenu() {
global $menu;
// iterate through each main menu
foreach($menu as $l_arr_MainMenu) {
// iterate through each main menu attribute
foreach($l_arr_MainMenu as $l_str_Attribute) {
// main menu already added, append sub pages and stop
if ($l_str_Attribute == self::C_STR_MAIN_MENU_SLUG) {
$this->registerSubPages();
return;
}
}
}
// add a new main menu page to the WordPress dashboard
add_menu_page(
self::C_STR_MAIN_MENU_TITLE, // page title
self::C_STR_MAIN_MENU_TITLE, // menu title
'manage_options', // capability
self::C_STR_MAIN_MENU_SLUG, // menu slug
array($this, "displayOtherPlugins"), // function
plugins_url('footnotes/img/main-menu.png'), // icon url
null // position
);
$this->registerSubPages();
}
/**
* Registers all SubPages for this Plugin.
*
* @author Stefan Herndler
* @since 1.5.0
*/
private function registerSubPages() {
// first registered sub menu page MUST NOT contain a unique slug suffix
// iterate though each sub class of the layout engine and register their sub page
/** @var MCI_Footnotes_LayoutEngine $l_obj_LayoutEngineSubClass */
foreach($this->a_arr_SubPageClasses as $l_obj_LayoutEngineSubClass) {
$l_obj_LayoutEngineSubClass->registerSubPage();
}
}
/**
* Displays other Plugins from the developers.
*
* @author Stefan Herndler
* @since 1.5.0
*/
public function displayOtherPlugins() {
printf("<br/><br/>");
// load template file
$l_obj_Template = new MCI_Footnotes_Template(MCI_Footnotes_Template::C_STR_DASHBOARD, "manfisher");
echo $l_obj_Template->getContent();
printf('<em>visit <a href="https://cheret.de/plugins/footnotes-2/" target="_blank">Mark Cheret</a></em>');
printf("<br/><br/>");
printf('</div>');
}
/**
* AJAX call. returns a JSON string containing meta information about a specific WordPress Plugin.
*
* @author Stefan Herndler
* @since 1.5.0
*/
public function getPluginMetaInformation() {
// get plugin internal name from POST data
$l_str_PluginName = array_key_exists("plugin", $_POST) ? $_POST["plugin"] : null;
if (empty($l_str_PluginName)) {
echo json_encode(array("error" => "Plugin name invalid."));
exit;
}
$l_str_Url = "https://api.wordpress.org/plugins/info/1.0/".$l_str_PluginName.".json";
// call URL and collect data
$l_arr_Response = wp_remote_get($l_str_Url);
// check if response is valid
if (is_wp_error($l_arr_Response)) {
echo json_encode(array("error" => "Error receiving Plugin Information from WordPress."));
exit;
}
if (!array_key_exists("body", $l_arr_Response)) {
echo json_encode(array("error" => "Error reading WordPress API response message."));
exit;
}
// get the body of the response
$l_str_Response = $l_arr_Response["body"];
// get plugin object
$l_arr_Plugin = json_decode($l_str_Response, true);
if (empty($l_arr_Plugin)) {
echo json_encode(array("error" => "Error reading Plugin meta information.<br/>URL: " . $l_str_Url . "<br/>Response: " . $l_str_Response));
exit;
}
$l_int_NumRatings = array_key_exists("num_ratings", $l_arr_Plugin) ? intval($l_arr_Plugin["num_ratings"]) : 0;
$l_int_Rating = array_key_exists("rating", $l_arr_Plugin) ? floatval($l_arr_Plugin["rating"]) : 0.0;
$l_int_Stars = round(5 * $l_int_Rating / 100.0, 1);
// return Plugin information as JSON encoded string
echo json_encode(
array(
"error" => "",
"PluginDescription" => array_key_exists("short_description", $l_arr_Plugin) ? html_entity_decode($l_arr_Plugin["short_description"]) : "Error reading Plugin information",
"PluginAuthor" => array_key_exists("author", $l_arr_Plugin) ? html_entity_decode($l_arr_Plugin["author"]) : "unknown",
"PluginRatingText" => $l_int_Stars . " " . __("rating based on", MCI_Footnotes_Config::C_STR_PLUGIN_NAME) . " " . $l_int_NumRatings . " " . __("ratings", MCI_Footnotes_Config::C_STR_PLUGIN_NAME),
"PluginRating1" => $l_int_Stars >= 0.5 ? "star-full" : "star-empty",
"PluginRating2" => $l_int_Stars >= 1.5 ? "star-full" : "star-empty",
"PluginRating3" => $l_int_Stars >= 2.5 ? "star-full" : "star-empty",
"PluginRating4" => $l_int_Stars >= 3.5 ? "star-full" : "star-empty",
"PluginRating5" => $l_int_Stars >= 4.5 ? "star-full" : "star-empty",
"PluginRating" => $l_int_NumRatings,
"PluginLastUpdated" => array_key_exists("last_updated", $l_arr_Plugin) ? $l_arr_Plugin["last_updated"] : "unknown",
"PluginDownloads" => array_key_exists("downloaded", $l_arr_Plugin) ? $l_arr_Plugin["downloaded"] : "---"
)
);
exit;
}
}

552
class/dashboard/layout.php Normal file
View file

@ -0,0 +1,552 @@
<?php
/**
* Includes Layout Engine for the admin dashboard.
*
* @filesource
* @author Stefan Herndler
* @since 1.5.0 12.09.14 10:56
*
* @lastmodified 2021-02-18T2021+0100
*
* @since 2.1.2 add versioning of settings.css for cache busting 2020-11-19T1456+0100
* @since 2.1.4 automate passing version number for cache busting 2020-11-30T0648+0100
* @since 2.1.4 optional step argument and support for floating in numbox 2020-12-05T0540+0100
* @since 2.1.6 fix punctuation-related localization issue in dashboard labels 2020-12-08T1547+0100
*
* @since 2.5.5 Bugfix: Stylesheets: minify to shrink the carbon footprint, increase speed and implement best practice, thanks to @docteurfitness issue report.
*/
/**
* Layout Engine for the administration dashboard.
*
* @author Stefan Herndler
* @since 1.5.0
*/
abstract class MCI_Footnotes_LayoutEngine {
/**
* Stores the Hook connection string for the child sub page.
*
* @author Stefan Herndler
* @since 1.5.0
* @var null|string
*/
protected $a_str_SubPageHook = null;
/**
* Stores all Sections for the child sub page.
*
* @author Stefan Herndler
* @since 1.5.0
* @var array
*/
protected $a_arr_Sections = array();
/**
* Returns a Priority index. Lower numbers have a higher Priority.
*
* @author Stefan Herndler
* @since 1.5.0
* @return int
*/
abstract public function getPriority();
/**
* Returns the unique slug of the child sub page.
*
* @author Stefan Herndler
* @since 1.5.0
* @return string
*/
abstract protected function getSubPageSlug();
/**
* Returns the title of the child sub page.
*
* @author Stefan Herndler
* @since 1.5.0
* @return string
*/
abstract protected function getSubPageTitle();
/**
* Returns an array of all registered sections for a sub page.
*
* @author Stefan Herndler
* @since 1.5.0
* @return array
*/
abstract protected function getSections();
/**
* Returns an array of all registered meta boxes.
*
* @author Stefan Herndler
* @since 1.5.0
* @return array
*/
abstract protected function getMetaBoxes();
/**
* Returns an array describing a sub page section.
*
* @author Stefan Herndler
* @since 1.5.0
* @param string $p_str_ID Unique ID suffix.
* @param string $p_str_Title Title of the section.
* @param int $p_int_SettingsContainerIndex Settings Container Index.
* @param bool $p_bool_hasSubmitButton Should a Submit Button be displayed for this section, default: true.
* @return array Array describing the section.
*/
protected function addSection($p_str_ID, $p_str_Title, $p_int_SettingsContainerIndex, $p_bool_hasSubmitButton = true) {
return array("id" => MCI_Footnotes_Config::C_STR_PLUGIN_NAME . "-" . $p_str_ID, "title" => $p_str_Title, "submit" => $p_bool_hasSubmitButton, "container" => $p_int_SettingsContainerIndex);
}
/**
* Returns an array describing a meta box.
*
* @author Stefan Herndler
* @since 1.5.0
* @param string $p_str_SectionID Parent Section ID.
* @param string $p_str_ID Unique ID suffix.
* @param string $p_str_Title Title for the meta box.
* @param string $p_str_CallbackFunctionName Class method name for callback.
* @return array meta box description to be able to append a meta box to the output.
*/
protected function addMetaBox($p_str_SectionID, $p_str_ID, $p_str_Title, $p_str_CallbackFunctionName) {
return array(
"parent" => MCI_Footnotes_Config::C_STR_PLUGIN_NAME . "-" . $p_str_SectionID,
"id" => $p_str_ID,
"title" => $p_str_Title,
"callback" => $p_str_CallbackFunctionName
);
}
/**
* Registers a sub page.
*
* @author Stefan Herndler
* @since 1.5.0
*/
public function registerSubPage() {
global $submenu;
// any sub menu for our main menu exists
if (array_key_exists(plugin_basename(MCI_Footnotes_Layout_Init::C_STR_MAIN_MENU_SLUG), $submenu)) {
// iterate through all sub menu entries of the ManFisher main menu
foreach($submenu[plugin_basename(MCI_Footnotes_Layout_Init::C_STR_MAIN_MENU_SLUG)] as $l_arr_SubMenu) {
if ($l_arr_SubMenu[2] == plugin_basename(MCI_Footnotes_Layout_Init::C_STR_MAIN_MENU_SLUG . $this->getSubPageSlug())) {
// remove that sub menu and add it again to move it to the bottom
remove_submenu_page(MCI_Footnotes_Layout_Init::C_STR_MAIN_MENU_SLUG, MCI_Footnotes_Layout_Init::C_STR_MAIN_MENU_SLUG .$this->getSubPageSlug());
}
}
}
$this->a_str_SubPageHook = add_submenu_page(
MCI_Footnotes_Layout_Init::C_STR_MAIN_MENU_SLUG, // parent slug
$this->getSubPageTitle(), // page title
$this->getSubPageTitle(), // menu title
'manage_options', // capability
MCI_Footnotes_Layout_Init::C_STR_MAIN_MENU_SLUG . $this->getSubPageSlug(), // menu slug
array($this, 'displayContent') // function
);
}
/**
* Registers all sections for a sub page.
*
* @author Stefan Herndler
* @since 1.5.0
*/
public function registerSections() {
// iterate through each section
foreach($this->getSections() as $l_arr_Section) {
// append tab to the tab-array
$this->a_arr_Sections[$l_arr_Section["id"]] = $l_arr_Section;
add_settings_section(
$l_arr_Section["id"], // unique id
"", //$l_arr_Section["title"], // title
array($this, 'Description'), // callback function for the description
$l_arr_Section["id"] // parent sub page slug
);
$this->registerMetaBoxes($l_arr_Section["id"]);
}
}
/**
* Registers all Meta boxes for a sub page.
*
* @author Stefan Herndler
* @since 1.5.0
* @param string $p_str_ParentID Parent section unique id.
*/
private function registerMetaBoxes($p_str_ParentID) {
// iterate through each meta box
foreach($this->getMetaBoxes() as $l_arr_MetaBox) {
if ($l_arr_MetaBox["parent"] != $p_str_ParentID) {
continue;
}
add_meta_box(
$p_str_ParentID. "-" . $l_arr_MetaBox["id"], // unique id
$l_arr_MetaBox["title"], // meta box title
array($this, $l_arr_MetaBox["callback"]), // callback function to display (echo) the content
$p_str_ParentID, // post type = parent section id
'main' // context
);
}
}
/**
* Append javascript and css files for specific sub page.
*
* @author Stefan Herndler
* @since 1.5.0
*/
private function appendScripts() {
// enable meta boxes layout and close functionality
wp_enqueue_script('postbox');
// add WordPress color picker layout
wp_enqueue_style('wp-color-picker');
// add WordPress color picker function
wp_enqueue_script('wp-color-picker');
/**
* Registers and enqueues the dashboard stylesheet.
*
* - Bugfix: Stylesheets: minify to shrink the carbon footprint, increase speed and implement best practice, thanks to @docteurfitness issue report.
*
* @since 2.5.5
* @date 2021-02-14T1928+0100
*
* @reporter @docteurfitness
* @link https://wordpress.org/support/topic/simply-speed-optimisation/
*
* See the public stylesheet enqueuing:
* @see class/init.php
*
* added version # after changes started to settings.css from 2.1.2 on.
* automated update of version number for cache busting.
* No need to use '-styles' in the handle, as '-css' is appended automatically.
*/
if ( C_BOOL_CSS_PRODUCTION_MODE === true ) {
wp_register_style( 'mci-footnotes-admin', plugins_url( 'footnotes/css/settings.min.css' ), array(), C_STR_FOOTNOTES_VERSION );
} else {
wp_register_style( 'mci-footnotes-admin', plugins_url( 'footnotes/css/settings.css' ), array(), C_STR_FOOTNOTES_VERSION );
}
wp_enqueue_style('mci-footnotes-admin');
}
/**
* Displays the content of specific sub page.
*
* @author Stefan Herndler
* @since 1.5.0
*/
public function displayContent() {
// register and enqueue scripts and styling
$this->appendScripts();
// get current section
reset($this->a_arr_Sections);
$l_str_ActiveSectionID = isset($_GET['t']) ? $_GET['t'] : key($this->a_arr_Sections);
$l_arr_ActiveSection = $this->a_arr_Sections[$l_str_ActiveSectionID];
// store settings
$l_bool_SettingsUpdated = false;
if (array_key_exists("save-settings", $_POST)) {
if ($_POST["save-settings"] == "save") {
unset($_POST["save-settings"]);
unset($_POST["submit"]);
$l_bool_SettingsUpdated = $this->saveSettings();
}
}
// display all sections and highlight the active section
echo '<div class="wrap">';
echo '<h2 class="nav-tab-wrapper">';
// iterate through all register sections
foreach ($this->a_arr_Sections as $l_str_ID => $l_arr_Description) {
echo sprintf(
'<a class="nav-tab%s" href="?page=%s&t=%s">%s</a>',
$l_arr_ActiveSection["id"] == $l_str_ID ? ' nav-tab-active' : '',
MCI_Footnotes_Layout_Init::C_STR_MAIN_MENU_SLUG . $this->getSubPageSlug(), $l_str_ID, $l_arr_Description["title"]
);
}
echo '</h2><br/>';
if ($l_bool_SettingsUpdated) {
echo sprintf('<div id="message" class="updated">%s</div>', __("Settings saved", MCI_Footnotes_Config::C_STR_PLUGIN_NAME));
}
// form to submit the active section
echo '<!--suppress HtmlUnknownTarget --><form method="post" action="">';
//settings_fields($l_arr_ActiveSection["container"]);
echo '<input type="hidden" name="save-settings" value="save" />';
// outputs the settings field of the active section
do_settings_sections($l_arr_ActiveSection["id"]);
do_meta_boxes($l_arr_ActiveSection["id"], 'main', NULL);
// add submit button to active section if defined
if ($l_arr_ActiveSection["submit"]) {
submit_button();
}
// close the form to submit data
echo '</form>';
// close container for the settings page
echo '</div>';
// output special javascript for the expand/collapse function of the meta boxes
echo '<script type="text/javascript">';
echo "jQuery(document).ready(function ($) {";
echo 'jQuery(".mfmmf-color-picker").wpColorPicker();';
echo "jQuery('.if-js-closed').removeClass('if-js-closed').addClass('closed');";
echo "postboxes.add_postbox_toggles('" . $this->a_str_SubPageHook . "');";
echo "});";
echo '</script>';
}
/**
* Save all Plugin settings.
*
* @author Stefan Herndler
* @since 1.5.0
* @return bool
*/
private function saveSettings() {
$l_arr_newSettings = array();
// get current section
reset($this->a_arr_Sections);
$l_str_ActiveSectionID = isset($_GET['t']) ? $_GET['t'] : key($this->a_arr_Sections);
$l_arr_ActiveSection = $this->a_arr_Sections[$l_str_ActiveSectionID];
// iterate through each value that has to be in the specific container
foreach(MCI_Footnotes_Settings::instance()->getDefaults($l_arr_ActiveSection["container"]) as $l_str_Key => $l_mixed_Value) {
// setting is available in the POST array, use it
if (array_key_exists($l_str_Key, $_POST)) {
$l_arr_newSettings[$l_str_Key] = $_POST[$l_str_Key];
} else {
// setting is not defined in the POST array, define it to avoid the Default value
$l_arr_newSettings[$l_str_Key] = "";
}
}
// update settings
return MCI_Footnotes_Settings::instance()->saveOptions($l_arr_ActiveSection["container"], $l_arr_newSettings);
}
/**
* Output the Description of a section. May be overwritten in any section.
*
* @author Stefan Herndler
* @since 1.5.0
*/
public function Description() {
// default no description will be displayed
}
/**
* Loads specific setting and returns an array with the keys [id, name, value].
*
* @author Stefan Herndler
* @since 1.5.0
* @param string $p_str_SettingKeyName Settings Array key name.
* @return array Contains Settings ID, Settings Name and Settings Value.
*/
protected function LoadSetting($p_str_SettingKeyName) {
// get current section
reset($this->a_arr_Sections);
$p_arr_Return = array();
$p_arr_Return["id"] = sprintf('%s', $p_str_SettingKeyName);
$p_arr_Return["name"] = sprintf('%s', $p_str_SettingKeyName);
$p_arr_Return["value"] = esc_attr(MCI_Footnotes_Settings::instance()->get($p_str_SettingKeyName));
return $p_arr_Return;
}
/**
* Returns a line break to start a new line.
*
* @author Stefan Herndler
* @since 1.5.0
* @return string
*/
protected function addNewline() {
return '<br/>';
}
/**
* Returns a line break to have a space between two lines.
*
* @author Stefan Herndler
* @since 1.5.0
* @return string
*/
protected function addLineSpace() {
return '<br/><br/>';
}
/**
* Returns a simple text inside html <span> text.
*
* @author Stefan Herndler
* @since 1.5.0
* @param string $p_str_Text Message to be surrounded with simple html tag (span).
* @return string
*/
protected function addText($p_str_Text) {
return sprintf('<span>%s</span>', $p_str_Text);
}
/**
* Returns the html tag for an input/select label.
*
* @author Stefan Herndler
* @since 1.5.0
* @param string $p_str_SettingName Name of the Settings key to connect the Label with the input/select field.
* @param string $p_str_Caption Label caption.
* @return string
*
* Edited 2020-12-01T0159+0100..
* @since 2.1.6 no colon
*/
protected function addLabel($p_str_SettingName, $p_str_Caption) {
if (empty($p_str_Caption)) {
return "";
}
// remove the colon causing localization issues with French,
// and with languages not using punctuation at all,
// and with languages using other punctuation marks instead of colon,
// e.g. Greek using a raised dot.
// In French, colon is preceded by a space, forcibly non-breaking,
// and narrow per new school.
// Add colon to label strings for inclusion in localization.
// Colon after label is widely preferred best practice, mandatory per style guides.
// <https://softwareengineering.stackexchange.com/questions/234546/colons-in-internationalized-ui>
return sprintf('<label for="%s">%s</label>', $p_str_SettingName, $p_str_Caption);
// ^ here deleted colon 2020-12-08T1546+0100
}
/**
* Returns the html tag for an input [type = text].
*
* @author Stefan Herndler
* @since 1.5.0
* @param string $p_str_SettingName Name of the Settings key to pre load the input field.
* @param int $p_str_MaxLength Maximum length of the input, default 999 characters.
* @param bool $p_bool_Readonly Set the input to be read only, default false.
* @param bool $p_bool_Hidden Set the input to be hidden, default false.
* @return string
*/
protected function addTextBox($p_str_SettingName, $p_str_MaxLength = 999, $p_bool_Readonly = false, $p_bool_Hidden = false) {
$l_str_Style = "";
// collect data for given settings field
$l_arr_Data = $this->LoadSetting($p_str_SettingName);
if ($p_bool_Hidden) {
$l_str_Style .= 'display:none;';
}
return sprintf('<input type="text" name="%s" id="%s" maxlength="%d" style="%s" value="%s" %s/>',
$l_arr_Data["name"], $l_arr_Data["id"], $p_str_MaxLength,
$l_str_Style, $l_arr_Data["value"], $p_bool_Readonly ? 'readonly="readonly"' : '');
}
/**
* Returns the html tag for an input [type = checkbox].
*
* @author Stefan Herndler
* @since 1.5.0
* @param string $p_str_SettingName Name of the Settings key to pre load the input field.
* @return string
*/
protected function addCheckbox($p_str_SettingName) {
// collect data for given settings field
$l_arr_Data = $this->LoadSetting($p_str_SettingName);
return sprintf('<input type="checkbox" name="%s" id="%s" %s/>',
$l_arr_Data["name"], $l_arr_Data["id"],
MCI_Footnotes_Convert::toBool($l_arr_Data["value"]) ? 'checked="checked"' : '');
}
/**
* Returns the html tag for a select box.
*
* @author Stefan Herndler
* @since 1.5.0
* @param string $p_str_SettingName Name of the Settings key to pre select the current value.
* @param array $p_arr_Options Possible options to be selected.
* @return string
*/
protected function addSelectBox($p_str_SettingName, $p_arr_Options) {
// collect data for given settings field
$l_arr_Data = $this->LoadSetting($p_str_SettingName);
$l_str_Options = "";
/* loop through all array keys */
foreach ($p_arr_Options as $l_str_Value => $l_str_Caption) {
$l_str_Options .= sprintf('<option value="%s" %s>%s</option>',
$l_str_Value,
$l_arr_Data["value"] == $l_str_Value ? "selected" : "",
$l_str_Caption);
}
return sprintf('<select name="%s" id="%s">%s</select>',
$l_arr_Data["name"], $l_arr_Data["id"], $l_str_Options);
}
/**
* Returns the html tag for a text area.
*
* @author Stefan Herndler
* @since 1.5.0
* @param string $p_str_SettingName Name of the Settings key to pre fill the text area.
* @return string
*/
protected function addTextArea($p_str_SettingName) {
// collect data for given settings field
$l_arr_Data = $this->LoadSetting($p_str_SettingName);
return sprintf('<textarea name="%s" id="%s">%s</textarea>',
$l_arr_Data["name"], $l_arr_Data["id"], $l_arr_Data["value"]);
}
/**
* Returns the html tag for an input [type = text] with color selection class.
*
* @author Stefan Herndler
* @since 1.5.6
* @param string $p_str_SettingName Name of the Settings key to pre load the input field.
* @return string
*/
protected function addColorSelection($p_str_SettingName) {
// collect data for given settings field
$l_arr_Data = $this->LoadSetting($p_str_SettingName);
return sprintf('<input type="text" name="%s" id="%s" class="mfmmf-color-picker" value="%s"/>',
$l_arr_Data["name"], $l_arr_Data["id"], $l_arr_Data["value"]);
}
/**
* Returns the html tag for an input [type = num].
*
* @author Stefan Herndler
* @since 1.5.0
* @param string $p_str_SettingName Name of the Settings key to pre load the input field.
* @param int $p_in_Min Minimum value.
* @param int $p_int_Max Maximum value.
* @param bool $p_bool_Deci true if 0.1 steps and floating to string, false if integer (default)
* @return string
*
* Edited:
* @since 2.1.4 step argument and number_format() to allow decimals 2020-12-03T0631+0100..2020-12-12T1110+0100
*/
protected function addNumBox($p_str_SettingName, $p_in_Min, $p_int_Max, $p_bool_Deci = false ) {
// collect data for given settings field
$l_arr_Data = $this->LoadSetting($p_str_SettingName);
if ($p_bool_Deci) {
$l_str_Value = number_format(floatval($l_arr_Data["value"]), 1);
return sprintf('<input type="number" name="%s" id="%s" value="%s" step="0.1" min="%d" max="%d"/>',
$l_arr_Data["name"], $l_arr_Data["id"], $l_str_Value, $p_in_Min, $p_int_Max);
} else {
return sprintf('<input type="number" name="%s" id="%s" value="%d" min="%d" max="%d"/>',
$l_arr_Data["name"], $l_arr_Data["id"], $l_arr_Data["value"], $p_in_Min, $p_int_Max);
}
}
} // end of class

View file

@ -0,0 +1,140 @@
<?php
/**
* Includes the Plugin Class to display Diagnostics.
*
* @filesource
* @author Stefan Herndler
* @since 1.5.0 14.09.14 14:47
*/
/**
* Displays Diagnostics of the web server, PHP and WordPress.
*
* @author Stefan Herndler
* @since 1.5.0
*/
class MCI_Footnotes_Layout_Diagnostics extends MCI_Footnotes_LayoutEngine {
/**
* Returns a Priority index. Lower numbers have a higher Priority.
*
* @author Stefan Herndler
* @since 1.5.0
* @return int
*/
public function getPriority() {
return 999;
}
/**
* Returns the unique slug of the sub page.
*
* @author Stefan Herndler
* @since 1.5.0
* @return string
*/
protected function getSubPageSlug() {
return "-diagnostics";
}
/**
* Returns the title of the sub page.
*
* @author Stefan Herndler
* @since 1.5.0
* @return string
*/
protected function getSubPageTitle() {
return __("Diagnostics", MCI_Footnotes_Config::C_STR_PLUGIN_NAME);
}
/**
* Returns an array of all registered sections for the sub page.
*
* @author Stefan Herndler
* @since 1.5.0
* @return array
*/
protected function getSections() {
return array(
$this->addSection("diagnostics", __("Diagnostics", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), null, false)
);
}
/**
* Returns an array of all registered meta boxes for each section of the sub page.
*
* @author Stefan Herndler
* @since 1.5.0
* @return array
*/
protected function getMetaBoxes() {
return array(
$this->addMetaBox("diagnostics", "diagnostics", __("Displays information about the web server, PHP and WordPress", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), "Diagnostics")
);
}
/**
* Displays a diagnostics about the web server, php and WordPress.
*
* @author Stefan Herndler
* @since 1.5.0
*/
public function Diagnostics() {
global $wp_version;
$l_str_PhpExtensions = "";
// iterate through each PHP extension
foreach (get_loaded_extensions() as $l_int_Index => $l_str_Extension) {
if ($l_int_Index > 0) {
$l_str_PhpExtensions .= ' | ';
}
$l_str_PhpExtensions .= $l_str_Extension . ' ' . phpversion($l_str_Extension);
}
/** @var WP_Theme $l_obj_CurrentTheme */
$l_obj_CurrentTheme = wp_get_theme();
$l_str_WordPressPlugins = "";
// iterate through each installed WordPress Plugin
foreach (get_plugins() as $l_arr_Plugin) {
$l_str_WordPressPlugins .= '<tr>';
$l_str_WordPressPlugins .= '<td>' . $l_arr_Plugin["Name"] . '</td>';
$l_str_WordPressPlugins .= '<td>' . $l_arr_Plugin["Version"] . ' [' . $l_arr_Plugin["PluginURI"] . ']' . '</td>';
$l_str_WordPressPlugins .= '</tr>';
}
// load template file
$l_obj_Template = new MCI_Footnotes_Template(MCI_Footnotes_Template::C_STR_DASHBOARD, "diagnostics");
// replace all placeholders
$l_obj_Template->replace(
array(
"label-server" => __("Server name", MCI_Footnotes_Config::C_STR_PLUGIN_NAME),
"server" => $_SERVER["SERVER_NAME"],
"label-php" => __("PHP version", MCI_Footnotes_Config::C_STR_PLUGIN_NAME),
"php" => phpversion(),
"label-user-agent" => __("User agent", MCI_Footnotes_Config::C_STR_PLUGIN_NAME),
"user-agent" => $_SERVER["HTTP_USER_AGENT"],
"label-max-execution-time" => __("Max execution time", MCI_Footnotes_Config::C_STR_PLUGIN_NAME),
"max-execution-time" => ini_get('max_execution_time') . ' ' . __('seconds', MCI_Footnotes_Config::C_STR_PLUGIN_NAME),
"label-memory-limit" => __("Memory limit", MCI_Footnotes_Config::C_STR_PLUGIN_NAME),
"memory-limit" => ini_get('memory_limit'),
"label-php-extensions" => __("PHP extensions", MCI_Footnotes_Config::C_STR_PLUGIN_NAME),
"php-extensions" => $l_str_PhpExtensions,
"label-wordpress" => __("WordPress version", MCI_Footnotes_Config::C_STR_PLUGIN_NAME),
"wordpress" => $wp_version,
"label-theme" => __("Active Theme", MCI_Footnotes_Config::C_STR_PLUGIN_NAME),
"theme" => $l_obj_CurrentTheme->get("Name") . " " . $l_obj_CurrentTheme->get("Version") . ", " . $l_obj_CurrentTheme->get("Author"). " [" . $l_obj_CurrentTheme->get("AuthorURI") . "]",
"plugins" => $l_str_WordPressPlugins
)
);
// display template with replaced placeholders
echo $l_obj_Template->getContent();
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,18 +1,19 @@
<?php // phpcs:disable WordPress.Files.FileName.InvalidClassFileName
<?php
/**
* Handles all WordPress hooks of this Plugin.
*
* @filesource
* @package footnotes
* @since 1.5.0
* @date 12.09.14 10:56
* @author Stefan Herndler
* @since 1.5.0 12.09.14 10:56
*
* @since 2.2.0 (TBD) 2020-12-12T1223+0100
* Edited:
* @since 2.2.0 2020-12-12T1223+0100
*/
/**
* Registers all WordPress Hooks and executes them on demand.
*
* @author Stefan Herndler
* @since 1.5.0
*/
class MCI_Footnotes_Hooks {
@ -20,68 +21,74 @@ class MCI_Footnotes_Hooks {
/**
* Registers all WordPress hooks.
*
* @author Stefan Herndler
* @since 1.5.0
*/
public static function register_hooks() {
register_activation_hook( dirname( __FILE__ ) . '/../footnotes.php', array( 'MCI_Footnotes_Hooks', 'activate_plugin' ) );
register_deactivation_hook( dirname( __FILE__ ) . '/../footnotes.php', array( 'MCI_Footnotes_Hooks', 'deactivate_plugin' ) );
register_uninstall_hook( dirname( __FILE__ ) . '/../footnotes.php', array( 'MCI_Footnotes_Hooks', 'uninstall_plugin' ) );
public static function registerHooks() {
register_activation_hook(dirname(__FILE__) . "/../footnotes.php", array("MCI_Footnotes_Hooks", "activatePlugin"));
register_deactivation_hook(dirname(__FILE__) . "/../footnotes.php", array("MCI_Footnotes_Hooks", "deactivatePlugin"));
register_uninstall_hook(dirname(__FILE__) . "/../footnotes.php", array("MCI_Footnotes_Hooks", "uninstallPlugin"));
}
/**
* Executed when the Plugin gets activated.
*
* @author Stefan Herndler
* @since 1.5.0
*/
public static function activate_plugin() {
// Currently unused.
public static function activatePlugin() {
// currently unused
}
/**
* Executed when the Plugin gets deactivated.
*
* @author Stefan Herndler
* @since 1.5.0
*/
public static function deactivate_plugin() {
// Currently unused.
public static function deactivatePlugin() {
// currently unused
}
/**
* Executed when the Plugin gets uninstalled.
*
* @author Stefan Herndler
* @since 1.5.0
*
* @since 2.2.0 this function is not called any longer when deleting the plugin.
* Note: clear_all() didnt actually work.
* @see class/settings.php
* Edit: ClearAll didnt actually work.
* @since 2.2.0 this function is not called any longer when deleting the plugin
*/
public static function uninstall_plugin() {
// WordPress User has to be logged in.
if ( ! is_user_logged_in() ) {
wp_die( wp_kses_post( __( 'You must be logged in to run this script.', 'footnotes' ) ) );
public static function uninstallPlugin() {
// WordPress User has to be logged in
if (!is_user_logged_in()) {
wp_die(__('You must be logged in to run this script.', MCI_Footnotes_Config::C_STR_PLUGIN_NAME));
}
// WordPress User needs the permission to (un)install plugins.
if ( ! current_user_can( 'install_plugins' ) ) {
wp_die( wp_kses_post( __( 'You do not have permission to run this script.', 'footnotes' ) ) );
// WordPress User needs the permission to (un)install plugins
if (!current_user_can('install_plugins')) {
wp_die(__('You do not have permission to run this script.', MCI_Footnotes_Config::C_STR_PLUGIN_NAME));
}
// deletes all settings and restore the default values
// MCI_Footnotes_Settings::instance()->ClearAll();
}
/**
* Add Links to the Plugin in the "installed Plugins" page.
*
* @author Stefan Herndler
* @since 1.5.0
* @param array $p_arr_links Current Links.
* @param string $p_str_plugin_file_name Plugins init file name.
* @param array $p_arr_Links Current Links.
* @param string $p_str_PluginFileName Plugins init file name.
* @return array
*/
public static function plugin_links( $p_arr_links, $p_str_plugin_file_name ) {
// Append link to the WordPress Plugin page.
$p_arr_links[] = sprintf( '<a href="http://wordpress.org/support/plugin/footnotes" target="_blank">%s</a>', __( 'Support', 'footnotes' ) );
// Append link to the settings page.
$p_arr_links[] = sprintf( '<a href="%s">%s</a>', admin_url( 'admin.php?page=mfmmf-footnotes' ), __( 'Settings', 'footnotes' ) );
// Append link to the PayPal donate function.
$p_arr_links[] = sprintf( '<a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=6Z6CZDW8PPBBJ" target="_blank">%s</a>', __( 'Donate', 'footnotes' ) );
// Return new links.
return $p_arr_links;
public static function PluginLinks($p_arr_Links, $p_str_PluginFileName) {
// append link to the WordPress Plugin page
$p_arr_Links[] = sprintf('<a href="http://wordpress.org/support/plugin/footnotes" target="_blank">%s</a>', __('Support', MCI_Footnotes_Config::C_STR_PLUGIN_NAME));
// append link to the Settings page
$p_arr_Links[] = sprintf('<a href="%s">%s</a>', admin_url('admin.php?page=mfmmf-footnotes'), __('Settings', MCI_Footnotes_Config::C_STR_PLUGIN_NAME));
// append link to the PlayPal Donate function
$p_arr_Links[] = sprintf('<a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=6Z6CZDW8PPBBJ" target="_blank">%s</a>', __('Donate', MCI_Footnotes_Config::C_STR_PLUGIN_NAME));
// return new links
return $p_arr_Links;
}
}

View file

@ -1,11 +1,13 @@
<?php // phpcs:disable WordPress.Files.FileName.InvalidClassFileName
<?php
/**
* Includes the main Class of the Plugin.
*
* @filesource
* @package footnotes
* @since 1.5.0
* @date 12.09.14 10:56
* @author Stefan Herndler
* @since 1.5.0 12.09.14 10:56
*
*
* @lastmodified 2021-02-19T2031+0100
*
* @since 1.6.5 Bugfix: Improve widgets registration, thanks to @felipelavinz code contribution.
* @since 1.6.5 Update: Fix for deprecated PHP function create_function(), thanks to @psykonevro @daliasued bug reports, thanks to @felipelavinz code contribution.
@ -25,6 +27,7 @@
/**
* Entry point of the Plugin. Loads the Dashboard and executes the Task.
*
* @author Stefan Herndler
* @since 1.5.0
*/
class MCI_Footnotes {
@ -32,77 +35,79 @@ class MCI_Footnotes {
/**
* Reference to the Plugin Task object.
*
* @author Stefan Herndler
* @since 1.5.0
* @var null|MCI_Footnotes_Task
*/
public $a_obj_task = null;
public $a_obj_Task = null;
/**
* Idenfifies whether tooltips are enabled. Actual value depends on settings.
* Template process and script / stylesheet load optimization.
*
* - Bugfix: Templates: optimize template load and processing based on settings, thanks to @misfist code contribution.
*
* @since 2.4.0
* @date 2021-01-04T1355+0100
*
* @author Patrizia Lutz @misfist
*
* @link https://wordpress.org/support/topic/template-override-filter/#post-13864301
* @link https://github.com/misfist/footnotes/releases/tag/2.4.0d3 repository
* @link https://github.com/misfist/footnotes/compare/2.4.0%E2%80%A62.4.0d3 diff
*
* @contributor Patrizia Lutz @misfist
* @var bool
*
* @todo Refactor to have defines and assignments only in this class,
* then re-use these properties also in class/task.php (and elsewhere).
* Account for priority level issues. These properties must be assigned before
* the hooks—whose priority level may be configured to 0—are called in class/task.php.
* Streamline process depending on tooltip enabled status.
* Load tooltip inline script only if jQuery tooltips are enabled.
* Actual value depends on settings.
*/
public static $a_bool_tooltips_enabled = false;
/**
* Idenfifies whether alternative tooltips are enabled. Actual value depends
* on settings.
*
* @contributor Patrizia Lutz @misfist
* @var bool
*
* @todo Refactor to have defines only here, and use assignments also in class/task.php.
*/
public static $a_bool_alternative_tooltips_enabled = false;
public static $a_bool_TooltipsEnabled = false;
public static $a_bool_AlternativeTooltipsEnabled = false;
/**
* Executes the Plugin.
*
* @author Stefan Herndler
* @since 1.5.0
*
*
* - Bugfix: Improve widgets registration, thanks to @felipelavinz code contribution.
*
* @since 1.6.5
*
* @contributor @felipelavinz
* @link https://github.com/benleyjyc/footnotes/commit/87173d2980c7ff90e12ffee94ca7153e11163793
* @date 2020-02-25
* @link https://github.com/media-competence-institute/footnotes/commit/87173d2980c7ff90e12ffee94ca7153e11163793
*
* @see self::initialize_widgets()
* @see self::initializeWidgets()
*/
public function run() {
// Register language.
MCI_Footnotes_Language::register_hooks();
// Register Button hooks.
MCI_Footnotes_WYSIWYG::register_hooks();
// Register general hooks.
MCI_Footnotes_Hooks::register_hooks();
// register language
MCI_Footnotes_Language::registerHooks();
// register Button hooks
MCI_Footnotes_WYSIWYG::registerHooks();
// register general hooks
MCI_Footnotes_Hooks::registerHooks();
// Initialize the Plugin Dashboard.
$this->initialize_dashboard();
// Initialize the Plugin Task.
$this->initialize_task();
// initialize the Plugin Dashboard
$this->initializeDashboard();
// initialize the Plugin Task
$this->initializeTask();
// Register all Public Stylesheets and Scripts.
add_action( 'init', array( $this, 'register_public' ) );
// Enqueue all Public Stylesheets and Scripts.
add_action( 'wp_enqueue_scripts', array( $this, 'register_public' ) );
// Register all Widgets of the Plugin..
add_action( 'widgets_init', array( $this, 'initialize_widgets' ) );
// Register all Public Stylesheets and Scripts
add_action('init', array($this, 'registerPublic'));
// Enqueue all Public Stylesheets and Scripts
add_action('wp_enqueue_scripts', array($this, 'registerPublic'));
// Register all Widgets of the Plugin.
add_action('widgets_init', array($this, 'initializeWidgets'));
}
/**
* Initializes all Widgets of the Plugin.
*
* @author Stefan Herndler
* @since 1.5.0
*
*
* - Update: Fix for deprecated PHP function create_function(), thanks to @psykonevro @daliasued bug reports, thanks to @felipelavinz code contribution
*
* @since 1.6.5
@ -124,34 +129,37 @@ class MCI_Footnotes {
* and use the bare register_widget() here.
* @see self::run()
*
* Also, the visibility of initialize_widgets() is not private any longer.
* Also, the visibility of initializeWidgets() is not private any longer.
*/
public function initialize_widgets() {
register_widget( 'MCI_Footnotes_Widget_Reference_container' );
public function initializeWidgets() {
register_widget( "MCI_Footnotes_Widget_ReferenceContainer" );
}
/**
* Initializes the Dashboard of the Plugin and loads them.
*
* @author Stefan Herndler
* @since 1.5.0
*/
private function initialize_dashboard() {
private function initializeDashboard() {
new MCI_Footnotes_Layout_Init();
}
/**
* Initializes the Plugin Task and registers the Task hooks.
*
* @author Stefan Herndler
* @since 1.5.0
*/
private function initialize_task() {
$this->a_obj_task = new MCI_Footnotes_Task();
$this->a_obj_task->register_hooks();
private function initializeTask() {
$this->a_obj_Task = new MCI_Footnotes_Task();
$this->a_obj_Task->registerHooks();
}
/**
* Registers and enqueues scripts and stylesheets to the public pages.
*
* @author Stefan Herndler
* @since 1.5.0
*
* @since 2.0.0 Update: Tooltips: fix disabling bug by loading jQuery UI library, thanks to @rajinderverma @ericcorbett2 @honlapdavid @mmallett bug reports, thanks to @vonpiernik code contribution.
@ -160,7 +168,7 @@ class MCI_Footnotes {
* @since 2.1.4 automate passing version number for cache busting 2020-11-30T0646+0100
* @since 2.1.4 optionally enqueue an extra stylesheet 2020-12-04T2231+0100
*/
public function register_public() {
public function registerPublic() {
/**
* Enqueues external scripts.
@ -173,10 +181,10 @@ class MCI_Footnotes {
*
* The condition about tooltips was missing, only the not-alternative-tooltips part was present.
*/
// Set conditions re-used for stylesheet enqueuing.
self::$a_bool_tooltips_enabled = MCI_Footnotes_Convert::to_bool( MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_FOOTNOTES_MOUSE_OVER_BOX_ENABLED ) );
self::$a_bool_alternative_tooltips_enabled = MCI_Footnotes_Convert::to_bool( MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_FOOTNOTES_MOUSE_OVER_BOX_ALTERNATIVE ) );
$l_str_script_mode = MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_FOOTNOTES_REFERENCE_CONTAINER_SCRIPT_MODE );
// set conditions re-used for stylesheet enqueuing:
self::$a_bool_TooltipsEnabled = MCI_Footnotes_Convert::toBool(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_BOOL_FOOTNOTES_MOUSE_OVER_BOX_ENABLED ) );
self::$a_bool_AlternativeTooltipsEnabled = MCI_Footnotes_Convert::toBool(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_BOOL_FOOTNOTES_MOUSE_OVER_BOX_ALTERNATIVE ) );
$l_str_ScriptMode = MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_FOOTNOTES_REFERENCE_CONTAINER_SCRIPT_MODE);
/**
* Enqueues the jQuery library registered by WordPress.
@ -193,73 +201,62 @@ class MCI_Footnotes {
* After adding the alternative reference container, jQuery has become optional,
* but still enabled by default.
*/
if ( 'jquery' === $l_str_script_mode || ( self::$a_bool_tooltips_enabled && ! self::$a_bool_alternative_tooltips_enabled ) ) {
if ( $l_str_ScriptMode == 'jquery' || ( self::$a_bool_TooltipsEnabled && ! self::$a_bool_AlternativeTooltipsEnabled ) ) {
wp_enqueue_script( 'jquery' );
}
if ( self::$a_bool_tooltips_enabled && ! self::$a_bool_alternative_tooltips_enabled ) {
if ( self::$a_bool_TooltipsEnabled && ! self::$a_bool_AlternativeTooltipsEnabled ) {
/**
* Enqueues the jQuery Tools library shipped with the plugin.
*
* Redacted jQuery.browser, completed minification;
* see full header in js/jquery.tools.js.
*
* Add versioning.
*
* @since 2.1.2
* @date 2020-11-18T2150+0100
*
* No '-js' in the handle, is appended automatically.
*
* Deferring to the footer breaks jQuery tooltip display.
* @date 2021-02-23T1105+0100
* redacted jQuery.browser, completed minification;
* see full header in js/jquery.tools.js
* added versioning 2020-11-18T2150+0100
* not use '-js' in the handle, is appended automatically
*/
wp_enqueue_script(
'mci-footnotes-jquery-tools',
plugins_url( 'footnotes/js/jquery.tools.min.js' ),
plugins_url('footnotes/js/jquery.tools.min.js'),
array(),
'1.2.7.redacted.2',
false
'1.2.7.redacted.2'
);
/**
* Enqueues some jQuery UI libraries registered by WordPress.
* Registers jQuery UI from the JavaScript Content Delivery Network.
*
* - Update: Tooltips: fix disabling bug by loading jQuery UI library, thanks to @rajinderverma @ericcorbett2 @honlapdavid @mmallett bug reports, thanks to @vonpiernik code contribution.
*
* @since 2.0.0
* Alternatively, fetch jQuery UI from cdnjs.cloudflare.com:
* @since 2.0.0 add jQueryUI from Cloudflare 2020-10-26T1907+0100
* Used to add jQuery UI following @vonpiernik:
* <https://wordpress.org/support/topic/tooltip-hover-not-showing/#post-13456762>:
*
* @reporter @rajinderverma
* @link https://wordpress.org/support/topic/tooltip-hover-not-showing/
*
* @reporter @ericcorbett2
* @link https://wordpress.org/support/topic/tooltip-hover-not-showing/#post-13324142
* jQueryUI re-enables the tooltip infobox disabled when WPv5.5 was released.
*
* @reporter @honlapdavid
* @link https://wordpress.org/support/topic/tooltip-hover-not-showing/#post-13355421
* Updated for v2.0.4 by adding jQuery UI from WordPress following @check2020de:
* <https://wordpress.org/support/topic/gdpr-issue-with-jquery/>
* See <https://wordpress.stackexchange.com/questions/273986/correct-way-to-enqueue-jquery-ui>
*
* @reporter @mmallett
* @link https://wordpress.org/support/topic/tooltip-hover-not-showing/#post-13445437
*
* Fetch jQuery UI from cdnjs.cloudflare.com.
* @since 2.0.0
* @date 2020-10-26T1907+0100
* @contributor @vonpiernik
* @link https://wordpress.org/support/topic/tooltip-hover-not-showing/#post-13456762
*
* jQueryUI re-enables the tooltip infobox disabled when WPv5.5 was released. * @since 2.1.2
*
* - Update: Libraries: Load jQuery UI from WordPress, thanks to @check2020de issue report.
*
* @since 2.0.4
* @date 2020-11-01T1902+0100
* @reporter @check2020de
* @link https://wordpress.org/support/topic/gdpr-issue-with-jquery/
* @link https://wordpress.stackexchange.com/questions/273986/correct-way-to-enqueue-jquery-ui
* This was enabled in Footnotes v2.0.0 through v2.0.3.
* Re-added for 2.0.9d1 / 2.1.1d0 to look whether it can fix a broken tooltip display. 2020-11-07T1601+0100/2020-11-08T2246+0100
*/
//wp_register_script( 'jQueryUI', 'https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js', null, null, false ); // in header 2020-11-09T2003+0100
//wp_enqueue_script( 'jQueryUI' );
/**
* This is then needed instead of the above first instance:
* Add jQuery Tools and finish adding jQueryUI: 2020-11-08T1638+0100/2020-11-08T2246+0100
*/
//wp_enqueue_script('mci-footnotes-js-jquery-tools', plugins_url('../js/jquery.tools.min.js', __FILE__), ['jQueryUI']);
/**
* Enqueues some jQuery UI libraries registered by WordPress.
*
* @since 2.0.4 add jQuery UI from WordPress 2020-11-01T1902+0100
* If alternative tooltips are enabled, these libraries are not needed.
*/
wp_enqueue_script( 'jquery-ui-core' );
@ -311,43 +308,34 @@ class MCI_Footnotes {
* The media scope argument 'all' is the default.
* No need to use '-css' in the handle, as this is appended automatically.
*/
// Set tooltip mode for use in stylesheet name.
if ( self::$a_bool_tooltips_enabled ) {
if ( self::$a_bool_alternative_tooltips_enabled ) {
$l_str_tooltip_mode_short = 'al';
$l_str_tooltip_mode_rest = 'ternative-tooltips';
// set tooltip mode for use in stylesheet name:
if ( self::$a_bool_TooltipsEnabled ) {
if ( self::$a_bool_AlternativeTooltipsEnabled ) {
$l_str_TooltipMode = 'al';
$l_str_TComplement = 'ternative-tooltips';
} else {
$l_str_tooltip_mode_short = 'jq';
$l_str_tooltip_mode_rest = 'uery-tooltips';
$l_str_TooltipMode = 'jq';
$l_str_TComplement = 'uery-tooltips';
}
} else {
$l_str_tooltip_mode_short = 'no';
$l_str_tooltip_mode_rest = '-tooltips';
$l_str_TooltipMode = 'no';
$l_str_TComplement = '-tooltips';
}
// Set basic responsive page layout mode for use in stylesheet name.
$l_str_page_layout_option = MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_FOOTNOTES_PAGE_LAYOUT_SUPPORT );
switch ( $l_str_page_layout_option ) {
case 'reference-container':
$l_str_layout_mode = '1';
break;
case 'entry-content':
$l_str_layout_mode = '2';
break;
case 'main-content':
$l_str_layout_mode = '3';
break;
case 'none':
default:
$l_str_layout_mode = '0';
break;
// set basic responsive page layout mode for use in stylesheet name:
$l_str_PageLayoutOption = MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_FOOTNOTES_PAGE_LAYOUT_SUPPORT);
switch ( $l_str_PageLayoutOption ) {
case "reference-container": $l_str_LayoutMode = '1'; break;
case "entry-content" : $l_str_LayoutMode = '2'; break;
case "main-content" : $l_str_LayoutMode = '3'; break;
case "none": default: $l_str_LayoutMode = '0'; break;
}
// Enqueue the tailored united minified stylesheet.
// enqueue the tailored united minified stylesheet:
wp_enqueue_style(
'mci-footnotes-' . $l_str_tooltip_mode_short . $l_str_tooltip_mode_rest . '-pagelayout-' . $l_str_page_layout_option,
'mci-footnotes-' . $l_str_TooltipMode . $l_str_TComplement . '-pagelayout-' . $l_str_PageLayoutOption,
plugins_url(
MCI_Footnotes_Config::C_STR_PLUGIN_NAME . '/css/footnotes-' . $l_str_tooltip_mode_short . 'ttbrpl' . $l_str_layout_mode . '.min.css'
MCI_Footnotes_Config::C_STR_PLUGIN_NAME . '/css/footnotes-' . $l_str_TooltipMode . 'ttbrpl' . $l_str_LayoutMode . '.min.css'
),
array(),
C_STR_FOOTNOTES_VERSION,
@ -368,12 +356,12 @@ class MCI_Footnotes {
wp_enqueue_style( 'mci-footnotes-tooltips', plugins_url( MCI_Footnotes_Config::C_STR_PLUGIN_NAME . '/css/dev-tooltips.css' ), array(), C_STR_FOOTNOTES_VERSION );
wp_enqueue_style( 'mci-footnotes-alternative', plugins_url( MCI_Footnotes_Config::C_STR_PLUGIN_NAME . '/css/dev-tooltips-alternative.css' ), array(), C_STR_FOOTNOTES_VERSION );
$l_str_page_layout_option = MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_FOOTNOTES_PAGE_LAYOUT_SUPPORT );
if ( 'none' !== $l_str_page_layout_option ) {
$l_str_PageLayoutOption = MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_FOOTNOTES_PAGE_LAYOUT_SUPPORT);
if ($l_str_PageLayoutOption != 'none') {
wp_enqueue_style(
'mci-footnotes-layout-' . $l_str_page_layout_option,
'mci-footnotes-layout-' . $l_str_PageLayoutOption,
plugins_url(
MCI_Footnotes_Config::C_STR_PLUGIN_NAME . '/css/dev-layout-' . $l_str_page_layout_option . '.css'
MCI_Footnotes_Config::C_STR_PLUGIN_NAME . '/css/dev-layout-' . $l_str_PageLayoutOption . '.css'
),
array(),
C_STR_FOOTNOTES_VERSION,

View file

@ -1,11 +1,13 @@
<?php // phpcs:disable WordPress.Files.FileName.InvalidClassFileName
<?php
/**
* Loads text domain of current or default language for localization.
*
* @filesource
* @package footnotes
* @since 1.5.0
* @date 14.09.14 17:47
* @author Stefan Herndler
* @since 1.5.0 14.09.14 17:47
*
*
* @lastmodified 2021-02-18T2028+0100
*
* @since 2.0.0 Bugfix: Localization: correct function call apply_filters() with all required arguments after PHP 7.1 promoted warning to error, thanks to @matkus2 bug report and code contribution.
* @since 2.1.6 Bugfix: Localization: conform to WordPress plugin language file name scheme, thanks to @nikelaos bug report.
@ -14,6 +16,7 @@
/**
* Loads text domain of current or default language for localization.
*
* @author Stefan Herndler
* @since 1.5.0
*/
class MCI_Footnotes_Language {
@ -21,16 +24,18 @@ class MCI_Footnotes_Language {
/**
* Register WordPress Hook.
*
* @author Stefan Herndler
* @since 1.5.0
*/
public static function register_hooks() {
add_action( 'plugins_loaded', array( 'MCI_Footnotes_Language', 'load_text_domain' ) );
public static function registerHooks() {
add_action('plugins_loaded', array("MCI_Footnotes_Language", "loadTextDomain"));
}
/**
* Loads the text domain for current WordPress language if exists.
* Otherwise fallback "en_GB" will be loaded.
*
* @author Stefan Herndler
* @since 1.5.0
*
*
@ -42,7 +47,7 @@ class MCI_Footnotes_Language {
* @contributor @matkus2
* @link https://wordpress.org/support/topic/error-missing-parameter-if-using-php-7-1-or-later/
*
* Add 3rd (empty) argument in apply_filters() to prevent PHP from throwing an error.
* Add 3rd (empty) argument in apply_filters() to prevent PHP from throwing an error:
* “Fatal error: Uncaught ArgumentCountError: Too few arguments to function apply_filters()
*
* Yet get_locale() is defined w/o parameters in wp-includes/l10n.php:30, and
@ -52,7 +57,7 @@ class MCI_Footnotes_Language {
* But apply_filters() is defined with a 3rd parameter (and w/o the first one) in
* wp-includes/class-wp-hook.php:264, as public function apply_filters( $value, $args ).
*
* Taking it all together, probably the full function definition would be
* Taking it all together, probably the full function definition would be:
* public function apply_filters( $tag, $value, $args ).
* In the case of get_locale(), $args is empty.
*
@ -60,21 +65,22 @@ class MCI_Footnotes_Language {
* @link https://www.php.net/manual/en/migration71.incompatible.php
* @link https://www.php.net/manual/en/migration71.incompatible.php#migration71.incompatible.too-few-arguments-exception
*/
public static function load_text_domain() {
public static function loadTextDomain() {
// If language file with localization exists.
// if language file with localization exists:
if ( self::load( apply_filters( 'plugin_locale', get_locale(), '' ) ) ) {
return;
}
// Else fall back to British English.
self::load( 'en_GB' );
// else fall back to British English:
self::load( "en_GB" );
}
/**
* Loads a specific text domain.
*
* @author Stefan Herndler
* @since 1.5.1
* @param string $p_str_language_code Language Code to load a specific text domain.
* @param string $p_str_LanguageCode Language Code to load a specific text domain.
* @return bool
*
*
@ -86,14 +92,16 @@ class MCI_Footnotes_Language {
* @reporter @nikelaos
* @link https://wordpress.org/support/topic/more-feature-ideas/
*
* That is done by using load_plugin_textdomain().
* That is done by using load_plugin_textdomain():
* “The .mo file should be named based on the text domain with a dash, and then the locale exactly.
* @see wp-includes/l10n.php:857
*/
private static function load( $p_str_language_code ) {
private static function load($p_str_LanguageCode) {
return load_plugin_textdomain(
MCI_Footnotes_Config::C_STR_PLUGIN_NAME,
// This argument only fills the gap left by a deprecated argument (since WP2.7):
false,
// The plugin basedir is provided; trailing slash would be clipped:
MCI_Footnotes_Config::C_STR_PLUGIN_NAME . '/languages'
);
}

View file

@ -1,563 +0,0 @@
<?php // phpcs:disable WordPress.Files.FileName.InvalidClassFileName
/**
* Includes Layout Engine for the admin dashboard.
*
* @filesource
* @package footnotes
* @since 1.5.0
* @date 12.09.14 10:56
*
* @since 2.1.2 add versioning of settings.css for cache busting 2020-11-19T1456+0100
* @since 2.1.4 automate passing version number for cache busting 2020-11-30T0648+0100
* @since 2.1.4 optional step argument and support for floating in numbox 2020-12-05T0540+0100
* @since 2.1.6 fix punctuation-related localization issue in dashboard labels 2020-12-08T1547+0100
*
* @since 2.5.5 Bugfix: Stylesheets: minify to shrink the carbon footprint, increase speed and implement best practice, thanks to @docteurfitness issue report.
*/
/**
* Layout Engine for the administration dashboard.
*
* @since 1.5.0
*/
abstract class MCI_Footnotes_Layout_Engine {
/**
* Stores the Hook connection string for the child sub page.
*
* @since 1.5.0
* @var null|string
*/
protected $a_str_sub_page_hook = null;
/**
* Stores all Sections for the child sub page.
*
* @since 1.5.0
* @var array
*/
protected $a_arr_sections = array();
/**
* Returns a Priority index. Lower numbers have a higher Priority.
*
* @since 1.5.0
* @return int
*/
abstract public function get_priority();
/**
* Returns the unique slug of the child sub page.
*
* @since 1.5.0
* @return string
*/
abstract protected function get_sub_page_slug();
/**
* Returns the title of the child sub page.
*
* @since 1.5.0
* @return string
*/
abstract protected function get_sub_page_title();
/**
* Returns an array of all registered sections for a sub page.
*
* @since 1.5.0
* @return array
*/
abstract protected function get_sections();
/**
* Returns an array of all registered meta boxes.
*
* @since 1.5.0
* @return array
*/
abstract protected function get_meta_boxes();
/**
* Returns an array describing a sub page section.
*
* @since 1.5.0
* @param string $p_str_id Unique ID suffix.
* @param string $p_str_title Title of the section.
* @param int $p_int_settings_container_index Settings Container Index.
* @param bool $p_bool_has_submit_button Should a Submit Button be displayed for this section, default: true.
* @return array Array describing the section.
*/
protected function add_section( $p_str_id, $p_str_title, $p_int_settings_container_index, $p_bool_has_submit_button = true ) {
return array(
'id' => MCI_Footnotes_Config::C_STR_PLUGIN_NAME . '-' . $p_str_id,
'title' => $p_str_title,
'submit' => $p_bool_has_submit_button,
'container' => $p_int_settings_container_index,
);
}
/**
* Returns an array describing a meta box.
*
* @since 1.5.0
* @param string $p_str_section_id Parent Section ID.
* @param string $p_str_id Unique ID suffix.
* @param string $p_str_title Title for the meta box.
* @param string $p_str_callback_function_name Class method name for callback.
* @return array meta box description to be able to append a meta box to the output.
*/
protected function add_meta_box( $p_str_section_id, $p_str_id, $p_str_title, $p_str_callback_function_name ) {
return array(
'parent' => MCI_Footnotes_Config::C_STR_PLUGIN_NAME . '-' . $p_str_section_id,
'id' => $p_str_id,
'title' => $p_str_title,
'callback' => $p_str_callback_function_name,
);
}
/**
* Registers a sub page.
*
* @since 1.5.0
*/
public function register_sub_page() {
global $submenu;
if ( array_key_exists( plugin_basename( MCI_Footnotes_Layout_Init::C_STR_MAIN_MENU_SLUG ), $submenu ) ) {
foreach ( $submenu[ plugin_basename( MCI_Footnotes_Layout_Init::C_STR_MAIN_MENU_SLUG ) ] as $l_arr_sub_menu ) {
if ( plugin_basename( MCI_Footnotes_Layout_Init::C_STR_MAIN_MENU_SLUG . $this->get_sub_page_slug() ) === $l_arr_sub_menu[2] ) {
remove_submenu_page( MCI_Footnotes_Layout_Init::C_STR_MAIN_MENU_SLUG, MCI_Footnotes_Layout_Init::C_STR_MAIN_MENU_SLUG . $this->get_sub_page_slug() );
}
}
}
$this->a_str_sub_page_hook = add_submenu_page(
MCI_Footnotes_Layout_Init::C_STR_MAIN_MENU_SLUG,
$this->get_sub_page_title(),
$this->get_sub_page_title(),
'manage_options',
MCI_Footnotes_Layout_Init::C_STR_MAIN_MENU_SLUG . $this->get_sub_page_slug(),
array( $this, 'display_content' )
);
}
/**
* Registers all sections for a sub page.
*
* @since 1.5.0
*/
public function register_sections() {
foreach ( $this->get_sections() as $l_arr_section ) {
// Append tab to the tab-array.
$this->a_arr_sections[ $l_arr_section['id'] ] = $l_arr_section;
add_settings_section(
$l_arr_section['id'],
'',
array( $this, 'Description' ),
$l_arr_section['id']
);
$this->register_meta_boxes( $l_arr_section['id'] );
}
}
/**
* Registers all Meta boxes for a sub page.
*
* @since 1.5.0
* @param string $p_str_parent_id Parent section unique id.
*/
private function register_meta_boxes( $p_str_parent_id ) {
// Iterate through each meta box.
foreach ( $this->get_meta_boxes() as $l_arr_meta_box ) {
if ( $p_str_parent_id !== $l_arr_meta_box['parent'] ) {
continue;
}
add_meta_box(
$p_str_parent_id . '-' . $l_arr_meta_box['id'],
$l_arr_meta_box['title'],
array( $this, $l_arr_meta_box['callback'] ),
$p_str_parent_id,
'main'
);
}
}
/**
* Append javascript and css files for specific sub page.
*
* @since 1.5.0
*/
private function append_scripts() {
wp_enqueue_script( 'postbox' );
wp_enqueue_style( 'wp-color-picker' );
wp_enqueue_script( 'wp-color-picker' );
/**
* Registers and enqueues the dashboard stylesheet.
*
* - Bugfix: Stylesheets: minify to shrink the carbon footprint, increase speed and implement best practice, thanks to @docteurfitness issue report.
*
* @since 2.5.5
* @date 2021-02-14T1928+0100
*
* @reporter @docteurfitness
* @link https://wordpress.org/support/topic/simply-speed-optimisation/
*
* See the public stylesheet enqueuing:
* @see class/init.php
*
* added version # after changes started to settings.css from 2.1.2 on.
* automated update of version number for cache busting.
* No need to use '-styles' in the handle, as '-css' is appended automatically.
*/
if ( C_BOOL_CSS_PRODUCTION_MODE === true ) {
wp_register_style( 'mci-footnotes-admin', plugins_url( 'footnotes/css/settings.min.css' ), array(), C_STR_FOOTNOTES_VERSION );
} else {
wp_register_style( 'mci-footnotes-admin', plugins_url( 'footnotes/css/settings.css' ), array(), C_STR_FOOTNOTES_VERSION );
}
wp_enqueue_style( 'mci-footnotes-admin' );
}
// phpcs:disable WordPress.Security.NonceVerification.Recommended
// phpcs:disable WordPress.Security.NonceVerification.Missing
/**
* Displays the content of specific sub page.
*
* @since 1.5.0
*/
public function display_content() {
$this->append_scripts();
// TODO: add nonce verification.
// Get the current section.
reset( $this->a_arr_sections );
$l_str_active_section_id = isset( $_GET['t'] ) ? sanitize_text_field( wp_unslash( $_GET['t'] ) ) : key( $this->a_arr_sections );
$l_arr_active_section = $this->a_arr_sections[ $l_str_active_section_id ];
// Store settings.
$l_bool_settings_updated = false;
if ( array_key_exists( 'save-settings', $_POST ) ) {
if ( 'save' === $_POST['save-settings'] ) {
unset( $_POST['save-settings'] );
unset( $_POST['submit'] );
$l_bool_settings_updated = $this->save_settings();
}
}
// Display all sections and highlight the active section.
echo '<div class="wrap">';
echo '<h2 class="nav-tab-wrapper">';
// Iterate through all register sections.
foreach ( $this->a_arr_sections as $l_str_id => $l_arr_description ) {
$l_str_tab_active = ( $l_str_id === $l_arr_active_section['id'] ) ? ' nav-tab-active' : '';
echo sprintf(
'<a class="nav-tab%s" href="?page=%s&t=%s">%s</a>',
esc_attr( ( $l_str_id === $l_arr_active_section['id'] ) ? ' nav-tab-active' : '' ),
esc_attr( MCI_Footnotes_Layout_Init::C_STR_MAIN_MENU_SLUG . $this->get_sub_page_slug() ),
esc_attr( $l_str_id ),
esc_attr( $l_arr_description['title'] )
);
}
echo '</h2><br/>';
if ( $l_bool_settings_updated ) {
echo sprintf( '<div id="message" class="updated">%s</div>', esc_html( __( 'Settings saved', 'footnotes' ) ) );
}
// Form to submit the active section.
echo '<!--suppress HtmlUnknownTarget --><form method="post" action="">';
echo '<input type="hidden" name="save-settings" value="save" />';
// Outputs the settings field of the active section.
do_settings_sections( $l_arr_active_section['id'] );
do_meta_boxes( $l_arr_active_section['id'], 'main', null );
// Add submit button to active section if defined.
if ( $l_arr_active_section['submit'] ) {
submit_button();
}
echo '</form>';
echo '</div>';
// Echo JavaScript for the expand/collapse function of the meta boxes.
echo '<script type="text/javascript">';
echo 'jQuery(document).ready(function ($) {';
echo 'jQuery(".mfmmf-color-picker").wpColorPicker();';
echo "jQuery('.if-js-closed').removeClass('if-js-closed').addClass('closed');";
echo "postboxes.add_postbox_toggles('" . esc_js( $this->a_str_sub_page_hook ) . "');";
echo '});';
echo '</script>';
}
// phpcs:enable
// phpcs:disable WordPress.Security.NonceVerification.Recommended
// phpcs:disable WordPress.Security.NonceVerification.Missing
/**
* Save all Plugin settings.
*
* @since 1.5.0
* @return bool
*/
private function save_settings() {
$l_arr_new_settings = array();
// TODO: add nonce verification.
// Get current section.
reset( $this->a_arr_sections );
$l_str_active_section_id = isset( $_GET['t'] ) ? sanitize_text_field( wp_unslash( $_GET['t'] ) ) : key( $this->a_arr_sections );
$l_arr_active_section = $this->a_arr_sections[ $l_str_active_section_id ];
foreach ( MCI_Footnotes_Settings::instance()->get_defaults( $l_arr_active_section['container'] ) as $l_str_key => $l_mixed_value ) {
if ( array_key_exists( $l_str_key, $_POST ) ) {
$l_arr_new_settings[ $l_str_key ] = sanitize_text_field( wp_unslash( $_POST[ $l_str_key ] ) );
} else {
// Setting is not defined in the POST array, define it to avoid the Default value.
$l_arr_new_settings[ $l_str_key ] = '';
}
}
// Update settings.
return MCI_Footnotes_Settings::instance()->save_options( $l_arr_active_section['container'], $l_arr_new_settings );
}
// phpcs:enable
/**
* Output the Description of a section. May be overwritten in any section.
*
* @since 1.5.0
*/
public function description() {
// Default no description will be displayed.
}
/**
* Loads specific setting and returns an array with the keys [id, name, value].
*
* @since 1.5.0
* @param string $p_str_setting_key_name Settings Array key name.
* @return array Contains Settings ID, Settings Name and Settings Value.
*/
protected function load_setting( $p_str_setting_key_name ) {
// Get current section.
reset( $this->a_arr_sections );
$p_arr_return = array();
$p_arr_return['id'] = sprintf( '%s', $p_str_setting_key_name );
$p_arr_return['name'] = sprintf( '%s', $p_str_setting_key_name );
$p_arr_return['value'] = esc_attr( MCI_Footnotes_Settings::instance()->get( $p_str_setting_key_name ) );
return $p_arr_return;
}
/**
* Returns a line break to start a new line.
*
* @since 1.5.0
* @return string
*/
protected function add_newline() {
return '<br/>';
}
/**
* Returns a line break to have a space between two lines.
*
* @since 1.5.0
* @return string
*/
protected function add_line_space() {
return '<br/><br/>';
}
/**
* Returns a simple text inside html <span> text.
*
* @since 1.5.0
* @param string $p_str_text Message to be surrounded with simple html tag (span).
* @return string
*/
protected function add_text( $p_str_text ) {
return sprintf( '<span>%s</span>', $p_str_text );
}
/**
* Returns the html tag for an input/select label.
*
* @since 1.5.0
* @param string $p_str_setting_name Name of the Settings key to connect the Label with the input/select field.
* @param string $p_str_caption Label caption.
* @return string
*/
protected function add_label( $p_str_setting_name, $p_str_caption ) {
if ( empty( $p_str_caption ) ) {
return '';
}
/*
* Remove the colon causing localization issues with French, and with
* languages not using punctuation at all, and with languages using other
* punctuation marks instead of colon, e.g. Greek using a raised dot.
* In French, colon is preceded by a space, forcibly non-breaking, and
* narrow per new school.
* Add colon to label strings for inclusion in localization. Colon after
* label is widely preferred best practice, mandatory per
* [style guides](https://softwareengineering.stackexchange.com/questions/234546/colons-in-internationalized-ui).
*/
return sprintf( '<label for="%s">%s</label>', $p_str_setting_name, $p_str_caption );
}
/**
* Returns the html tag for an input [type = text].
*
* @since 1.5.0
* @param string $p_str_setting_name Name of the Settings key to pre load the input field.
* @param int $p_str_max_length Maximum length of the input, default 999 characters.
* @param bool $p_bool_readonly Set the input to be read only, default false.
* @param bool $p_bool_hidden Set the input to be hidden, default false.
* @return string
*/
protected function add_text_box( $p_str_setting_name, $p_str_max_length = 999, $p_bool_readonly = false, $p_bool_hidden = false ) {
$l_str_style = '';
// Collect data for given settings field.
$l_arr_data = $this->load_setting( $p_str_setting_name );
if ( $p_bool_hidden ) {
$l_str_style .= 'display:none;';
}
return sprintf(
'<input type="text" name="%s" id="%s" maxlength="%d" style="%s" value="%s" %s/>',
$l_arr_data['name'],
$l_arr_data['id'],
$p_str_max_length,
$l_str_style,
$l_arr_data['value'],
$p_bool_readonly ? 'readonly="readonly"' : ''
);
}
/**
* Returns the html tag for an input [type = checkbox].
*
* @since 1.5.0
* @param string $p_str_setting_name Name of the Settings key to pre load the input field.
* @return string
*/
protected function add_checkbox( $p_str_setting_name ) {
// Collect data for given settings field.
$l_arr_data = $this->load_setting( $p_str_setting_name );
return sprintf(
'<input type="checkbox" name="%s" id="%s" %s/>',
$l_arr_data['name'],
$l_arr_data['id'],
MCI_Footnotes_Convert::to_bool( $l_arr_data['value'] ) ? 'checked="checked"' : ''
);
}
/**
* Returns the html tag for a select box.
*
* @since 1.5.0
* @param string $p_str_setting_name Name of the Settings key to pre select the current value.
* @param array $p_arr_options Possible options to be selected.
* @return string
*/
protected function add_select_box( $p_str_setting_name, $p_arr_options ) {
// Collect data for given settings field.
$l_arr_data = $this->load_setting( $p_str_setting_name );
$l_str_options = '';
foreach ( $p_arr_options as $l_str_value => $l_str_caption ) {
$l_str_options .= sprintf(
'<option value="%s" %s>%s</option>',
$l_str_value,
$l_str_value === $l_arr_data['value'] ? 'selected' : '',
$l_str_caption
);
}
return sprintf(
'<select name="%s" id="%s">%s</select>',
$l_arr_data['name'],
$l_arr_data['id'],
$l_str_options
);
}
/**
* Returns the html tag for a text area.
*
* @since 1.5.0
* @param string $p_str_setting_name Name of the Settings key to pre fill the text area.
* @return string
*/
protected function add_textarea( $p_str_setting_name ) {
// Collect data for given settings field.
$l_arr_data = $this->load_setting( $p_str_setting_name );
return sprintf(
'<textarea name="%s" id="%s">%s</textarea>',
$l_arr_data['name'],
$l_arr_data['id'],
$l_arr_data['value']
);
}
/**
* Returns the html tag for an input [type = text] with color selection class.
*
* @since 1.5.6
* @param string $p_str_setting_name Name of the Settings key to pre load the input field.
* @return string
*/
protected function add_color_selection( $p_str_setting_name ) {
// Collect data for given settings field.
$l_arr_data = $this->load_setting( $p_str_setting_name );
return sprintf(
'<input type="text" name="%s" id="%s" class="mfmmf-color-picker" value="%s"/>',
$l_arr_data['name'],
$l_arr_data['id'],
$l_arr_data['value']
);
}
/**
* Returns the html tag for an input [type = num].
*
* @since 1.5.0
* @param string $p_str_setting_name Name of the Settings key to pre load the input field.
* @param int $p_in_min Minimum value.
* @param int $p_int_max Maximum value.
* @param bool $p_bool_deci true if 0.1 steps and floating to string, false if integer (default).
* @return string
*
* Edited:
* @since 2.1.4 step argument and number_format() to allow decimals 2020-12-03T0631+0100..2020-12-12T1110+0100
*/
protected function add_num_box( $p_str_setting_name, $p_in_min, $p_int_max, $p_bool_deci = false ) {
// Collect data for given settings field.
$l_arr_data = $this->load_setting( $p_str_setting_name );
if ( $p_bool_deci ) {
$l_str_value = number_format( floatval( $l_arr_data['value'] ), 1 );
return sprintf(
'<input type="number" name="%s" id="%s" value="%s" step="0.1" min="%d" max="%d"/>',
$l_arr_data['name'],
$l_arr_data['id'],
$l_str_value,
$p_in_min,
$p_int_max
);
} else {
return sprintf(
'<input type="number" name="%s" id="%s" value="%d" min="%d" max="%d"/>',
$l_arr_data['name'],
$l_arr_data['id'],
$l_arr_data['value'],
$p_in_min,
$p_int_max
);
}
}
}

View file

@ -1,149 +0,0 @@
<?php // phpcs:disable WordPress.Files.FileName.InvalidClassFileName
/**
* Includes the Plugin Class to display Diagnostics.
*
* @filesource
* @package footnotes
* @since 1.5.0
* @date 14.09.14 14:47
*/
/**
* Displays Diagnostics of the web server, PHP and WordPress.
*
* @since 1.5.0
*/
class MCI_Footnotes_Layout_Diagnostics extends MCI_Footnotes_Layout_Engine {
/**
* Returns a Priority index. Lower numbers have a higher Priority.
*
* @since 1.5.0
* @return int
*/
public function get_priority() {
return 999;
}
/**
* Returns the unique slug of the sub page.
*
* @since 1.5.0
* @return string
*/
protected function get_sub_page_slug() {
return '-diagnostics';
}
/**
* Returns the title of the sub page.
*
* @since 1.5.0
* @return string
*/
protected function get_sub_page_title() {
return __( 'Diagnostics', 'footnotes' );
}
/**
* Returns an array of all registered sections for the sub page.
*
* @since 1.5.0
* @return array
*/
protected function get_sections() {
return array(
$this->add_section( 'diagnostics', __( 'Diagnostics', 'footnotes' ), null, false ),
);
}
/**
* Returns an array of all registered meta boxes for each section of the sub page.
*
* @since 1.5.0
* @return array
*/
protected function get_meta_boxes() {
return array(
$this->add_meta_box( 'diagnostics', 'diagnostics', __( 'Displays information about the web server, PHP and WordPress', 'footnotes' ), 'Diagnostics' ),
);
}
/**
* Displays a diagnostics about the web server, php and WordPress.
*
* @since 1.5.0
*/
public function Diagnostics() {
global $wp_version;
$l_str_php_extensions = '';
// Iterate through each PHP extension.
foreach ( get_loaded_extensions() as $l_int_index => $l_str_extension ) {
if ( $l_int_index > 0 ) {
$l_str_php_extensions .= ' | ';
}
$l_str_php_extensions .= $l_str_extension . ' ' . phpversion( $l_str_extension );
}
$l_obj_current_theme = wp_get_theme();
$l_str_wordpress_plugins = '';
// Iterate through each installed WordPress Plugin.
foreach ( get_plugins() as $l_arr_plugin ) {
$l_str_wordpress_plugins .= '<tr>';
$l_str_wordpress_plugins .= '<td>' . $l_arr_plugin['Name'] . '</td>';
// phpcs:disable Generic.Strings.UnnecessaryStringConcat.Found
$l_str_wordpress_plugins .= '<td>' . $l_arr_plugin['Version'] . ' [' . $l_arr_plugin['PluginURI'] . ']' . '</td>';
// phpcs:enable
$l_str_wordpress_plugins .= '</tr>';
}
// Load template file.
$l_obj_template = new MCI_Footnotes_Template( MCI_Footnotes_Template::C_STR_DASHBOARD, 'diagnostics' );
if ( ! isset( $_SERVER['SERVER_NAME'] ) ) {
die;
} else {
$l_str_server_name = sanitize_text_field( wp_unslash( $_SERVER['SERVER_NAME'] ) );
}
if ( ! isset( $_SERVER['HTTP_USER_AGENT'] ) ) {
die;
} else {
$l_str_http_user_agent = sanitize_text_field( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) );
}
// Replace all placeholders.
$l_obj_template->replace(
array(
'label-server' => __( 'Server name', 'footnotes' ),
'server' => $l_str_server_name,
'label-php' => __( 'PHP version', 'footnotes' ),
'php' => phpversion(),
'label-user-agent' => __( 'User agent', 'footnotes' ),
'user-agent' => $l_str_http_user_agent,
'label-max-execution-time' => __( 'Max execution time', 'footnotes' ),
'max-execution-time' => ini_get( 'max_execution_time' ) . ' ' . __( 'seconds', 'footnotes' ),
'label-memory-limit' => __( 'Memory limit', 'footnotes' ),
'memory-limit' => ini_get( 'memory_limit' ),
'label-php-extensions' => __( 'PHP extensions', 'footnotes' ),
'php-extensions' => $l_str_php_extensions,
'label-wordpress' => __( 'WordPress version', 'footnotes' ),
'wordpress' => $wp_version,
'label-theme' => __( 'Active Theme', 'footnotes' ),
'theme' => $l_obj_current_theme->get( 'Name' ) . ' ' . $l_obj_current_theme->get( 'Version' ) . ', ' . $l_obj_current_theme->get( 'Author' ) . ' [' . $l_obj_current_theme->get( 'AuthorURI' ) . ']',
'plugins' => $l_str_wordpress_plugins,
)
);
// phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped
// Display template with replaced placeholders.
echo $l_obj_template->get_content();
// phpcs:enable
}
}

View file

@ -1,207 +0,0 @@
<?php // phpcs:disable WordPress.Files.FileName.InvalidClassFileName
/**
* Includes the Plugin settings menu.
*
* @filesource
* @package footnotes
* @since 1.5.0
* @date 12.09.14 10:26
*/
/**
* Handles the Settings interface of the Plugin.
*
* @since 1.5.0
*/
class MCI_Footnotes_Layout_Init {
/**
* Slug for the Plugin main menu.
*
* @since 1.5.0
* @var string
*/
const C_STR_MAIN_MENU_SLUG = 'mfmmf';
/**
* Plugin main menu name.
*
* @since 1.5.0
* @var string
*/
const C_STR_MAIN_MENU_TITLE = 'ManFisher';
/**
* Contains layout engine sub classes.
*
* @since 1.5.0
* @var array
*/
private $a_arr_sub_page_classes = array();
/**
* Class Constructor. Initializes all WordPress hooks for the Plugin Settings.
*
* @since 1.5.0
*/
public function __construct() {
foreach ( get_declared_classes() as $l_str_class_name ) {
if ( is_subclass_of( $l_str_class_name, 'MCI_Footnotes_Layout_Engine' ) ) {
$l_obj_class = new $l_str_class_name();
// Append new instance of the layout engine sub class.
$this->a_arr_sub_page_classes[ $l_obj_class->get_priority() ] = $l_obj_class;
}
}
ksort( $this->a_arr_sub_page_classes );
// Register hooks/actions.
add_action( 'admin_init', array( $this, 'initialize_settings' ) );
add_action( 'admin_menu', array( $this, 'register_main_menu' ) );
// Register AJAX callbacks for Plugin information.
add_action( 'wp_ajax_nopriv_footnotes_get_plugin_info', array( $this, 'get_plugin_meta_information' ) );
add_action( 'wp_ajax_footnotes_get_plugin_info', array( $this, 'get_plugin_meta_information' ) );
}
/**
* Initializes all sub pages and registers the settings.
*
* @since 1.5.0
*/
public function initialize_settings() {
MCI_Footnotes_Settings::instance()->register_settings();
// Iterate though each sub class of the layout engine and register their sections.
foreach ( $this->a_arr_sub_page_classes as $l_obj_layout_engine_sub_class ) {
$l_obj_layout_engine_sub_class->register_sections();
}
}
/**
* Registers the new main menu for the WordPress dashboard.
* Registers all sub menu pages for the new main menu.
*
* @since 1.5.0
* @see http://codex.wordpress.org/Function_Reference/add_menu_page
*/
public function register_main_menu() {
global $menu;
// Iterate through each main menu.
foreach ( $menu as $l_arr_main_menu ) {
// 3terate through each main menu attribute.
foreach ( $l_arr_main_menu as $l_str_attribute ) {
// Main menu already added, append sub pages and stop.
if ( self::C_STR_MAIN_MENU_SLUG === $l_str_attribute ) {
$this->register_sub_pages();
return;
}
}
}
// Add a new main menu page to the WordPress dashboard.
add_menu_page(
self::C_STR_MAIN_MENU_TITLE, // Page title.
self::C_STR_MAIN_MENU_TITLE, // Menu title.
'manage_options', // Capability.
self::C_STR_MAIN_MENU_SLUG, // Menu slug.
array( $this, 'display_other_plugins' ), // Function.
plugins_url( 'footnotes/img/main-menu.png' ), // Icon URL.
null // Position.
);
$this->register_sub_pages();
}
/**
* Registers all SubPages for this Plugin.
*
* @since 1.5.0
*/
private function register_sub_pages() {
// First registered sub menu page MUST NOT contain a unique slug suffix.
// Iterate though each sub class of the layout engine and register their sub page.
foreach ( $this->a_arr_sub_page_classes as $l_obj_layout_engine_sub_class ) {
$l_obj_layout_engine_sub_class->register_sub_page();
}
}
/**
* Displays other Plugins from the developers.
*
* @since 1.5.0
*/
public function display_other_plugins() {
printf( '<br/><br/>' );
// Load template file.
$l_obj_template = new MCI_Footnotes_Template( MCI_Footnotes_Template::C_STR_DASHBOARD, 'manfisher' );
// phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped
echo $l_obj_template->get_content();
// phpcs:enable
printf( '<em>visit <a href="https://cheret.de/plugins/footnotes-2/" target="_blank">Mark Cheret</a></em>' );
printf( '<br/><br/>' );
printf( '</div>' );
}
// phpcs:disable WordPress.Security.NonceVerification.Missing
/**
* AJAX call. returns a JSON string containing meta information about a specific WordPress Plugin.
*
* @since 1.5.0
*/
public function get_plugin_meta_information() {
// TODO: add nonce verification.
// Get plugin internal name from POST data.
if ( isset( $_POST['plugin'] ) ) {
$l_str_plugin_name = sanitize_text_field( wp_unslash( $_POST['plugin'] ) );
}
if ( empty( $l_str_plugin_name ) ) {
echo wp_json_encode( array( 'error' => 'Plugin name invalid.' ) );
exit;
}
$l_str_url = 'https://api.wordpress.org/plugins/info/1.0/' . $l_str_plugin_name . '.json';
// Call URL and collect data.
$l_arr_response = wp_remote_get( $l_str_url );
// Check if response is valid.
if ( is_wp_error( $l_arr_response ) ) {
echo wp_json_encode( array( 'error' => 'Error receiving Plugin Information from WordPress.' ) );
exit;
}
if ( ! array_key_exists( 'body', $l_arr_response ) ) {
echo wp_json_encode( array( 'error' => 'Error reading WordPress API response message.' ) );
exit;
}
// Get the body of the response.
$l_str_response = $l_arr_response['body'];
// Get plugin object.
$l_arr_plugin = json_decode( $l_str_response, true );
if ( empty( $l_arr_plugin ) ) {
echo wp_json_encode( array( 'error' => 'Error reading Plugin meta information.<br/>URL: ' . $l_str_url . '<br/>Response: ' . $l_str_response ) );
exit;
}
$l_int_num_ratings = array_key_exists( 'num_ratings', $l_arr_plugin ) ? intval( $l_arr_plugin['num_ratings'] ) : 0;
$l_int_rating = array_key_exists( 'rating', $l_arr_plugin ) ? floatval( $l_arr_plugin['rating'] ) : 0.0;
$l_int_stars = round( 5 * $l_int_rating / 100.0, 1 );
// Return Plugin information as JSON encoded string.
echo wp_json_encode(
array(
'error' => '',
'PluginDescription' => array_key_exists( 'short_description', $l_arr_plugin ) ? html_entity_decode( $l_arr_plugin['short_description'] ) : 'Error reading Plugin information',
'PluginAuthor' => array_key_exists( 'author', $l_arr_plugin ) ? html_entity_decode( $l_arr_plugin['author'] ) : 'unknown',
'PluginRatingText' => $l_int_stars . ' ' . __( 'rating based on', 'footnotes' ) . ' ' . $l_int_num_ratings . ' ' . __( 'ratings', 'footnotes' ),
'PluginRating1' => $l_int_stars >= 0.5 ? 'star-full' : 'star-empty',
'PluginRating2' => $l_int_stars >= 1.5 ? 'star-full' : 'star-empty',
'PluginRating3' => $l_int_stars >= 2.5 ? 'star-full' : 'star-empty',
'PluginRating4' => $l_int_stars >= 3.5 ? 'star-full' : 'star-empty',
'PluginRating5' => $l_int_stars >= 4.5 ? 'star-full' : 'star-empty',
'PluginRating' => $l_int_num_ratings,
'PluginLastUpdated' => array_key_exists( 'last_updated', $l_arr_plugin ) ? $l_arr_plugin['last_updated'] : 'unknown',
'PluginDownloads' => array_key_exists( 'downloaded', $l_arr_plugin ) ? $l_arr_plugin['downloaded'] : '---',
)
);
exit;
}
// phpcs:enable
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,20 +1,39 @@
<?php // phpcs:disable WordPress.Files.FileName.InvalidClassFileName
<?php
/**
* Includes the Template Engine to load and handle all Template files of the Plugin.
*
* @filesource
* @package footnotes
* @since 1.5.0
* @date 14.09.14 10:58
* @author Stefan Herndler
* @since 1.5.0 14.09.14 10:58
*
* @since 2.2.6 Adding: Templates: support for custom templates in sibling folder, thanks to @misfist issue report.
* @since 2.5.0 Adding: Templates: Enable template location stack, thanks to @misfist code contribution.
*
* @lastmodified 2021-02-18T2024+0100
*
* @since 2.0.3 prettify reference container template
* @since 2.0.3 replace tab with a space
* @since 2.0.3 replace 2 spaces with 1
* @since 2.0.4 collapse multiple spaces
* @since 2.0.6 prettify other templates (footnote, tooltip script, ref container row)
* @since 2.2.6 delete a space before a closing pointy bracket
*
* @since 2.2.6 support for custom templates in fixed location, while failing to add filter thanks to @misfist 2020-12-19T0606+0100
* @link https://wordpress.org/support/topic/template-override-filter/
*
* @since 2.4.0 templates may be in active theme, thanks to @misfist
* @link https://wordpress.org/support/topic/template-override-filter/#post-13846598
*
* @since 2.5.0 Enable template location stack, contributed by @misfist
* @link https://wordpress.org/support/topic/template-override-filter/#post-13864301
*
* @since 2.5.4 collapse HTML comments and PHP/JS docblocks (only)
*/
/**
* Handles each Template file for the Plugin Frontend (e.g. Settings Dashboard, Public pages, ...).
* Loads a template file, replaces all Placeholders and returns the replaced file content.
*
* @author Stefan Herndler
* @since 1.5.0
*/
class MCI_Footnotes_Template {
@ -22,38 +41,43 @@ class MCI_Footnotes_Template {
/**
* Directory name for dashboard templates.
*
* @author Stefan Herndler
* @since 1.5.0
* @var string
*/
const C_STR_DASHBOARD = 'dashboard';
const C_STR_DASHBOARD = "dashboard";
/**
* Directory name for public templates.
*
* @author Stefan Herndler
* @since 1.5.0
* @var string
*/
const C_STR_PUBLIC = 'public';
const C_STR_PUBLIC = "public";
/**
* Contains the content of the template after initialize.
*
* @author Stefan Herndler
* @since 1.5.0
* @var string
*/
private $a_str_original_content = '';
private $a_str_OriginalContent = "";
/**
* Contains the content of the template after initialize with replaced place holders.
*
* @author Stefan Herndler
* @since 1.5.0
* @var string
*/
private $a_str_replaced_content = '';
private $a_str_ReplacedContent = "";
/**
* Plugin Directory
*
* @author Patrizia Lutz @misfist
* @since 2.4.0d3
*
* @var string
@ -63,39 +87,42 @@ class MCI_Footnotes_Template {
/**
* Class Constructor. Reads and loads the template file without replace any placeholder.
*
* @author Stefan Herndler
* @since 1.5.0
* @param string $p_str_file_type Template file type (take a look on the Class constants).
* @param string $p_str_file_name Template file name inside the Template directory without the file extension.
* @param string $p_str_extension Optional Template file extension (default: html).
* @param string $p_str_FileType Template file type (take a look on the Class constants).
* @param string $p_str_FileName Template file name inside the Template directory without the file extension.
* @param string $p_str_Extension Optional Template file extension (default: html)
*
* - Adding: Templates: support for custom templates in sibling folder, thanks to @misfist issue report.
*
* @since 2.2.6
* @date 2020-12-19T0606+0100
*
* @reporter @misfist
* @since 2.2.6 support for custom templates 2020-12-19T0606+0100
* @link https://wordpress.org/support/topic/template-override-filter/
*
* @since 2.4.0 look for custom template in the active theme first, thanks to @misfist
* @link https://wordpress.org/support/topic/template-override-filter/#post-13846598
*/
public function __construct( $p_str_file_type, $p_str_file_name, $p_str_extension = 'html' ) {
// No template file type and/or file name set.
if ( empty( $p_str_file_type ) || empty( $p_str_file_name ) ) {
public function __construct($p_str_FileType, $p_str_FileName, $p_str_Extension = "html") {
// no template file type and/or file name set
if (empty($p_str_FileType) || empty($p_str_FileName)) {
return;
}
/**
* Define plugin root path.
* Define plugin root path
*
* @since 2.4.0d3
*
* @author Patrizia Lutz @misfist
*/
$this->plugin_directory = plugin_dir_path( dirname( __FILE__ ) );
/**
* Modularize functions.
* Modularize functions
*
* @since 2.4.0d3
*
* @author Patrizia Lutz @misfist
*/
$template = $this->get_template( $p_str_file_type, $p_str_file_name, $p_str_extension );
if ( $template ) {
if( $template = $this->get_template( $p_str_FileType, $p_str_FileName, $p_str_Extension ) ) {
$this->process_template( $template );
} else {
return;
@ -106,125 +133,124 @@ class MCI_Footnotes_Template {
/**
* Replace all placeholders specified in array.
*
* @author Stefan Herndler
* @since 1.5.0
* @param array $p_arr_placeholders Placeholders (key = placeholder, value = value).
* @param array $p_arr_Placeholders Placeholders (key = placeholder, value = value).
* @return bool True on Success, False if Placeholders invalid.
*/
public function replace( $p_arr_placeholders ) {
// No placeholders set.
if ( empty( $p_arr_placeholders ) ) {
public function replace($p_arr_Placeholders) {
// no placeholders set
if (empty($p_arr_Placeholders)) {
return false;
}
// Template content is empty.
if ( empty( $this->a_str_replaced_content ) ) {
// template content is empty
if (empty($this->a_str_ReplacedContent)) {
return false;
}
// Iterate through each placeholder and replace it with its value.
foreach ( $p_arr_placeholders as $l_str_placeholder => $l_str_value ) {
$this->a_str_replaced_content = str_replace( '[[' . $l_str_placeholder . ']]', $l_str_value, $this->a_str_replaced_content );
// iterate through each placeholder and replace it with its value
foreach($p_arr_Placeholders as $l_str_Placeholder => $l_str_Value) {
$this->a_str_ReplacedContent = str_replace("[[" . $l_str_Placeholder . "]]", $l_str_Value, $this->a_str_ReplacedContent);
}
// Success.
// success
return true;
}
/**
* Reloads the original content of the template file.
*
* @author Stefan Herndler
* @since 1.5.0
*/
public function reload() {
$this->a_str_replaced_content = $this->a_str_original_content;
$this->a_str_ReplacedContent = $this->a_str_OriginalContent;
}
/**
* Returns the content of the template file with replaced placeholders.
*
* @author Stefan Herndler
* @since 1.5.0
* @return string Template content with replaced placeholders.
*/
public function get_content() {
return $this->a_str_replaced_content;
public function getContent() {
return $this->a_str_ReplacedContent;
}
/**
* Process template file.
* Process template file
*
* @author Patrizia Lutz @misfist
*
* @since 2.4.0d3
*
* @param string $template The template to be processed.
* @param string $template
* @return void
*
* @since 2.0.3 Replace tab with a space.
* @since 2.0.3 Replace 2 spaces with 1.
* @since 2.0.4 Collapse multiple spaces.
* @since 2.2.6 Delete a space before a closing pointy bracket.
* @since 2.5.4 Collapse HTML comments and PHP/JS docblocks (only).
*
* @since 2.0.3 replace tab with a space
* @since 2.0.3 replace 2 spaces with 1
* @since 2.0.4 collapse multiple spaces
* @since 2.2.6 delete a space before a closing pointy bracket
* @since 2.5.4 collapse HTML comments and PHP/JS docblocks (only)
*/
public function process_template( $template ) {
// phpcs:disable WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
$this->a_str_original_content = preg_replace( '#<!--.+?-->#s', '', file_get_contents( $template ) );
// phpcs:enable
$this->a_str_original_content = preg_replace( '#/\*\*.+?\*/#s', '', $this->a_str_original_content );
$this->a_str_original_content = str_replace( "\n", '', $this->a_str_original_content );
$this->a_str_original_content = str_replace( "\r", '', $this->a_str_original_content );
$this->a_str_original_content = str_replace( "\t", ' ', $this->a_str_original_content );
$this->a_str_original_content = preg_replace( '# +#', ' ', $this->a_str_original_content );
$this->a_str_original_content = str_replace( ' >', '>', $this->a_str_original_content );
$this->a_str_OriginalContent = preg_replace( '#<!--.+?-->#s', "", file_get_contents( $template ) );
$this->a_str_OriginalContent = preg_replace( '#/\*\*.+?\*/#s', "", $this->a_str_OriginalContent );
$this->a_str_OriginalContent = str_replace( "\n", "", $this->a_str_OriginalContent );
$this->a_str_OriginalContent = str_replace( "\r", "", $this->a_str_OriginalContent );
$this->a_str_OriginalContent = str_replace( "\t", " ", $this->a_str_OriginalContent );
$this->a_str_OriginalContent = preg_replace( '# +#', " ", $this->a_str_OriginalContent );
$this->a_str_OriginalContent = str_replace( " >", ">", $this->a_str_OriginalContent );
$this->reload();
}
/**
* Get the template.
* Get the template
*
* - Adding: Templates: Enable template location stack, thanks to @misfist code contribution.
* @author Patrizia Lutz @misfist
*
* @since 2.4.0d3 Contribution.
* @since 2.5.0 Release.
* @since 2.4.0d3
*
* @contributor @misfist
* @link https://wordpress.org/support/topic/template-override-filter/#post-13864301
*
* @param string $p_str_file_type The file type of the template.
* @param string $p_str_file_name The file name of the template.
* @param string $p_str_extension The file extension of the template.
* @param string $p_str_FileType
* @param string $p_str_FileName
* @param string $p_str_Extension
* @return mixed false | template path
*/
public function get_template( $p_str_file_type, $p_str_file_name, $p_str_extension = 'html' ) {
public function get_template( $p_str_FileType, $p_str_FileName, $p_str_Extension = "html" ) {
$located = false;
/**
* The directory can be changed.
*
* @usage to change location of templates to 'template_parts/footnotes/':
* The directory change be modified
* @usage to change location of templates to `template_parts/footnotes/':
* add_filter( 'mci_footnotes_template_directory', function( $directory ) {
* return 'template_parts/footnotes/';
* return 'template_parts/footnotes/;
* } );
*/
$template_directory = apply_filters( 'mci_footnotes_template_directory', 'footnotes/templates/' );
$custom_directory = apply_filters( 'mci_footnotes_custom_template_directory', 'footnotes-custom/' );
$template_name = $p_str_file_type . '/' . $p_str_file_name . '.' . $p_str_extension;
$custom_directory = apply_filters( 'mci_footnotes_custom_template_directory', 'footnotes-custom/' );
$template_name = $p_str_FileType . '/' . $p_str_FileName . '.' . $p_str_Extension;
/**
* Look in active theme.
* Look in active (child) theme
*/
if ( file_exists( trailingslashit( get_stylesheet_directory() ) . $template_directory . $template_name ) ) {
$located = trailingslashit( get_stylesheet_directory() ) . $template_directory . $template_name;
/**
* Look in parent theme in case active is child.
*/
/**
* Look in parent theme
*/
} elseif ( file_exists( trailingslashit( get_template_directory() ) . $template_directory . $template_name ) ) {
$located = trailingslashit( get_template_directory() ) . $template_directory . $template_name;
/**
* Look in custom plugin directory.
*/
/**
* Look in custom directory
*/
} elseif ( file_exists( trailingslashit( WP_PLUGIN_DIR ) . $custom_directory . 'templates/' . $template_name ) ) {
$located = trailingslashit( WP_PLUGIN_DIR ) . $custom_directory . 'templates/' . $template_name;
/**
* Fall back to the templates shipped with the plugin.
*/
/**
* Look in plugin
*/
} elseif ( file_exists( $this->plugin_directory . 'templates/' . $template_name ) ) {
$located = $this->plugin_directory . 'templates/' . $template_name;
}
@ -232,4 +258,4 @@ class MCI_Footnotes_Template {
return $located;
}
}
} // end of class

View file

@ -1,12 +1,14 @@
<?php // phpcs:disable WordPress.Files.FileName.InvalidClassFileName
<?php
/**
* Widget base.
*
* @filesource
* @package footnotes
* @author Stefan Herndler
* @since 1.5.0
* @date 14.09.14 14:30
*
* @lastmodified 2021-02-18T0306+0100
* @date 2021-02-18T0240+0100
* @since 1.6.4 Update: replace deprecated function WP_Widget() with recommended __construct(), thanks to @dartiss code contribution.
*/
@ -19,45 +21,50 @@
* @author Stefan Herndler
* @since 1.5.0
*/
abstract class MCI_Footnotes_Widget_Base extends WP_Widget {
abstract class MCI_Footnotes_WidgetBase extends WP_Widget {
/**
* Returns an unique ID as string used for the Widget Base ID.
*
* @author Stefan Herndler
* @since 1.5.0
* @return string
*/
abstract protected function get_id();
abstract protected function getID();
/**
* Returns the Public name of child Widget to be displayed in the Configuration page.
*
* @author Stefan Herndler
* @since 1.5.0
* @return string
*/
abstract protected function get_name();
abstract protected function getName();
/**
* Returns the Description of the child widget.
*
* @author Stefan Herndler
* @since 1.5.0
* @return string
*/
abstract protected function get_description();
abstract protected function getDescription();
/**
* Returns the width of the Widget. Default width is 250 pixel.
*
* @author Stefan Herndler
* @since 1.5.0
* @return int
*/
protected function get_widget_width() {
protected function getWidgetWidth() {
return 250;
}
/**
* Class Constructor. Registers the child Widget to WordPress.
*
* @author Stefan Herndler
* @since 1.5.0
*
* - Update: replace deprecated function WP_Widget() with recommended __construct(), thanks to @dartiss code contribution.
@ -68,20 +75,14 @@ abstract class MCI_Footnotes_Widget_Base extends WP_Widget {
* “The called constructor method for WP_Widget in MCI_Footnotes_Widget_ReferenceContainer is deprecated since version 4.3.0! Use __construct() instead.
*/
public function __construct() {
$l_arr_widget_options = array(
'classname' => __CLASS__,
'description' => $this->get_description(),
);
$l_arr_control_options = array(
'id_base' => strtolower( $this->get_id() ),
'width' => $this->get_widget_width(),
);
// Registers the Widget.
$l_arr_WidgetOptions = array("classname" => __CLASS__, "description" => $this->getDescription());
$l_arr_ControlOptions = array("id_base" => strtolower($this->getID()), "width" => $this->getWidgetWidth());
// registers the Widget
parent::__construct(
strtolower( $this->get_id() ), // Unique ID for the widget, has to be lowercase.
$this->get_name(), // Plugin name to be displayed.
$l_arr_widget_options, // Optional Widget Options.
$l_arr_control_options // Optional Widget Control Options.
strtolower($this->getID()), // unique ID for the widget, has to be lowercase
$this->getName(), // Plugin name to be displayed
$l_arr_WidgetOptions, // Optional Widget Options
$l_arr_ControlOptions // Optional Widget Control Options
);
}
}

View file

@ -1,81 +1,85 @@
<?php // phpcs:disable WordPress.Files.FileName.InvalidClassFileName
<?php
/**
* Includes the Plugin Widget to put the Reference Container to the Widget area.
*
* @filesource
* @package footnotes
* @since 1.5.0
* @date 14.09.14 14:26
* @author Stefan Herndler
* @since 1.5.0 14.09.14 14:26
*
* @since 2.2.0 (TBD) 2020-12-12T2131+0100
* Edited 2.2.0 2020-12-12T2131+0100
*/
/**
* Registers a Widget to put the Reference Container to the widget area.
*
* @author Stefan Herndler
* @since 1.5.0
*/
class MCI_Footnotes_Widget_Reference_Container extends MCI_Footnotes_Widget_Base {
class MCI_Footnotes_Widget_ReferenceContainer extends MCI_Footnotes_WidgetBase {
/**
* Returns an unique ID as string used for the Widget Base ID.
*
* @author Stefan Herndler
* @since 1.5.0
* @return string
*/
protected function get_id() {
return 'footnotes_widget';
protected function getID() {
return "footnotes_widget";
}
/**
* Returns the Public name of the Widget to be displayed in the Configuration page.
*
* @author Stefan Herndler
* @since 1.5.0
* @return string
*/
protected function get_name() {
protected function getName() {
return MCI_Footnotes_Config::C_STR_PLUGIN_NAME;
}
/**
* Returns the Description of the child widget.
*
* @author Stefan Herndler
* @since 1.5.0
* @return string
*
* Edit: curly quotes 2.2.0 2020-12-12T2130+0100
*/
protected function get_description() {
return __( 'The widget defines the position of the reference container if set to “widget area”.', 'footnotes' );
protected function getDescription() {
return __('The widget defines the position of the reference container if set to “widget area”.', MCI_Footnotes_Config::C_STR_PLUGIN_NAME);
}
/**
* Outputs the Settings of the Widget.
*
* @author Stefan Herndler
* @since 1.5.0
* @param mixed $instance The instance of the widget.
* @param mixed $instance
* @return void
*
* Edit: curly quotes 2.2.0 2020-12-12T2130+0100
*/
public function form( $instance ) {
echo wp_kses_post( __( 'The widget defines the position of the reference container if set to “widget area”.', 'footnotes' ) );
public function form($instance) {
echo __('The widget defines the position of the reference container if set to “widget area”.', MCI_Footnotes_Config::C_STR_PLUGIN_NAME);
}
/**
* Outputs the Content of the Widget.
*
* @author Stefan Herndler
* @since 1.5.0
* @param mixed $args The widget's arguments.
* @param mixed $instance The instance of the widget.
* @param mixed $args
* @param mixed $instance
*/
public function widget( $args, $instance ) {
global $g_obj_mci_footnotes;
// Reference container positioning is set to "widget area".
if ( 'widget' === MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_REFERENCE_CONTAINER_POSITION ) ) {
// phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped
echo $g_obj_mci_footnotes->a_obj_task->Reference_Container();
// phpcs:enable
public function widget($args, $instance) {
global $g_obj_MCI_Footnotes;
// reference container positioning is set to "widget area"
if (MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_REFERENCE_CONTAINER_POSITION) == "widget") {
echo $g_obj_MCI_Footnotes->a_obj_Task->ReferenceContainer();
}
}
}

View file

@ -1,92 +1,83 @@
<?php // phpcs:disable WordPress.Files.FileName.InvalidClassFileName
<?php
/**
* Includes the Class to handle the WYSIWYG-Buttons.
*
* @filesource
* @package footnotes
* @since 1.5.0
* @date 14.09.14 17:30
* @author Stefan Herndler
* @since 1.5.0 14.09.14 17:30
*/
/**
* Handles the WSYIWYG-Buttons.
*
* @author Stefan Herndler
* @since 1.5.0
*/
class MCI_Footnotes_WYSIWYG {
/**
* Registers Button hooks.
*
* @return void
*/
public static function register_hooks() {
add_filter( 'mce_buttons', array( 'MCI_Footnotes_WYSIWYG', 'new_visual_editor_button' ) );
add_action( 'admin_print_footer_scripts', array( 'MCI_Footnotes_WYSIWYG', 'new_plain_text_editor_button' ) );
public static function registerHooks() {
add_filter("mce_buttons", array("MCI_Footnotes_WYSIWYG", "newVisualEditorButton"));
add_action("admin_print_footer_scripts", array("MCI_Footnotes_WYSIWYG", "newPlainTextEditorButton"));
add_filter( 'mce_external_plugins', array( 'MCI_Footnotes_WYSIWYG', 'include_scripts' ) );
add_filter("mce_external_plugins", array("MCI_Footnotes_WYSIWYG", "includeScripts"));
add_action( 'wp_ajax_nopriv_footnotes_get_tags', array( 'MCI_Footnotes_WYSIWYG', 'ajax_callback' ) );
add_action( 'wp_ajax_footnotes_get_tags', array( 'MCI_Footnotes_WYSIWYG', 'ajax_callback' ) );
add_action("wp_ajax_nopriv_footnotes_getTags", array("MCI_Footnotes_WYSIWYG", "ajaxCallback"));
add_action("wp_ajax_footnotes_getTags", array("MCI_Footnotes_WYSIWYG", "ajaxCallback"));
}
/**
* Append a new Button to the WYSIWYG editor of Posts and Pages.
*
* @author Stefan Herndler
* @since 1.5.0
* @param array $p_arr_buttons pre defined Buttons from WordPress.
* @param array $p_arr_Buttons pre defined Buttons from WordPress.
* @return array
*/
public static function new_visual_editor_button( $p_arr_buttons ) {
array_push( $p_arr_buttons, MCI_Footnotes_Config::C_STR_PLUGIN_NAME );
return $p_arr_buttons;
public static function newVisualEditorButton($p_arr_Buttons) {
array_push($p_arr_Buttons, MCI_Footnotes_Config::C_STR_PLUGIN_NAME);
return $p_arr_Buttons;
}
/**
* Add a new button to the plain text editor.
*
* @author Stefan Herndler
* @since 1.5.0
*/
public static function new_plain_text_editor_button() {
$l_obj_template = new MCI_Footnotes_Template( MCI_Footnotes_Template::C_STR_DASHBOARD, 'editor-button' );
// phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped
echo $l_obj_template->get_content();
// phpcs:enable
public static function newPlainTextEditorButton() {
$l_obj_Template = new MCI_Footnotes_Template(MCI_Footnotes_Template::C_STR_DASHBOARD, "editor-button");
echo $l_obj_Template->getContent();
}
/**
* Includes the Plugins WYSIWYG editor script.
*
* @author Stefan Herndler
* @since 1.5.0
* @param array $p_arr_plugins Scripts to be included to the editor.
* @param array $p_arr_Plugins Scripts to be included to the editor.
* @return array
*/
public static function include_scripts( $p_arr_plugins ) {
$p_arr_plugins[ MCI_Footnotes_Config::C_STR_PLUGIN_NAME ] = plugins_url( '/../js/wysiwyg-editor.js', __FILE__ );
return $p_arr_plugins;
public static function includeScripts($p_arr_Plugins) {
$p_arr_Plugins[MCI_Footnotes_Config::C_STR_PLUGIN_NAME] = plugins_url('/../js/wysiwyg-editor.js', __FILE__);
return $p_arr_Plugins;
}
/**
* AJAX Callback function when the Footnotes Button is clicked. Either in the Plain text or Visual editor.
* Returns an JSON encoded array with the Footnotes start and end short code.
*
* @author Stefan Herndler
* @since 1.5.0
*/
public static function ajax_callback() {
// Get start and end tag for the footnotes short code.
$l_str_starting_tag = MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_FOOTNOTES_SHORT_CODE_START );
$l_str_ending_tag = MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_FOOTNOTES_SHORT_CODE_END );
if ( 'userdefined' === $l_str_starting_tag || 'userdefined' === $l_str_ending_tag ) {
$l_str_starting_tag = MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_FOOTNOTES_SHORT_CODE_START_USER_DEFINED );
$l_str_ending_tag = MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_FOOTNOTES_SHORT_CODE_END_USER_DEFINED );
public static function ajaxCallback() {
// get start and end tag for the footnotes short code
$l_str_StartingTag = MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_FOOTNOTES_SHORT_CODE_START);
$l_str_EndingTag = MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_FOOTNOTES_SHORT_CODE_END);
if ($l_str_StartingTag == "userdefined" || $l_str_EndingTag == "userdefined") {
$l_str_StartingTag = MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_FOOTNOTES_SHORT_CODE_START_USER_DEFINED);
$l_str_EndingTag = MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_FOOTNOTES_SHORT_CODE_END_USER_DEFINED);
}
echo wp_json_encode(
array(
'start' => htmlspecialchars( $l_str_starting_tag ),
'end' => htmlspecialchars( $l_str_ending_tag ),
)
);
echo json_encode(array("start" => htmlspecialchars($l_str_StartingTag), "end" => htmlspecialchars($l_str_EndingTag)));
exit;
}
}

View file

@ -1,11 +0,0 @@
{
"require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "^0.7.1",
"wp-coding-standards/wpcs": "^2.3"
},
"scripts": {
"post-install-cmd": [
"bash _tools/setup.sh"
]
}
}

196
composer.lock generated
View file

@ -1,196 +0,0 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "3a147d50695956de52f7cbf827b47830",
"packages": [],
"packages-dev": [
{
"name": "dealerdirect/phpcodesniffer-composer-installer",
"version": "v0.7.1",
"source": {
"type": "git",
"url": "https://github.com/Dealerdirect/phpcodesniffer-composer-installer.git",
"reference": "fe390591e0241955f22eb9ba327d137e501c771c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Dealerdirect/phpcodesniffer-composer-installer/zipball/fe390591e0241955f22eb9ba327d137e501c771c",
"reference": "fe390591e0241955f22eb9ba327d137e501c771c",
"shasum": ""
},
"require": {
"composer-plugin-api": "^1.0 || ^2.0",
"php": ">=5.3",
"squizlabs/php_codesniffer": "^2.0 || ^3.0 || ^4.0"
},
"require-dev": {
"composer/composer": "*",
"phpcompatibility/php-compatibility": "^9.0",
"sensiolabs/security-checker": "^4.1.0"
},
"type": "composer-plugin",
"extra": {
"class": "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin"
},
"autoload": {
"psr-4": {
"Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Franck Nijhof",
"email": "franck.nijhof@dealerdirect.com",
"homepage": "http://www.frenck.nl",
"role": "Developer / IT Manager"
}
],
"description": "PHP_CodeSniffer Standards Composer Installer Plugin",
"homepage": "http://www.dealerdirect.com",
"keywords": [
"PHPCodeSniffer",
"PHP_CodeSniffer",
"code quality",
"codesniffer",
"composer",
"installer",
"phpcs",
"plugin",
"qa",
"quality",
"standard",
"standards",
"style guide",
"stylecheck",
"tests"
],
"support": {
"issues": "https://github.com/dealerdirect/phpcodesniffer-composer-installer/issues",
"source": "https://github.com/dealerdirect/phpcodesniffer-composer-installer"
},
"time": "2020-12-07T18:04:37+00:00"
},
{
"name": "squizlabs/php_codesniffer",
"version": "3.5.8",
"source": {
"type": "git",
"url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
"reference": "9d583721a7157ee997f235f327de038e7ea6dac4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/9d583721a7157ee997f235f327de038e7ea6dac4",
"reference": "9d583721a7157ee997f235f327de038e7ea6dac4",
"shasum": ""
},
"require": {
"ext-simplexml": "*",
"ext-tokenizer": "*",
"ext-xmlwriter": "*",
"php": ">=5.4.0"
},
"require-dev": {
"phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0"
},
"bin": [
"bin/phpcs",
"bin/phpcbf"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.x-dev"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Greg Sherwood",
"role": "lead"
}
],
"description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.",
"homepage": "https://github.com/squizlabs/PHP_CodeSniffer",
"keywords": [
"phpcs",
"standards"
],
"support": {
"issues": "https://github.com/squizlabs/PHP_CodeSniffer/issues",
"source": "https://github.com/squizlabs/PHP_CodeSniffer",
"wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki"
},
"time": "2020-10-23T02:01:07+00:00"
},
{
"name": "wp-coding-standards/wpcs",
"version": "2.3.0",
"source": {
"type": "git",
"url": "https://github.com/WordPress/WordPress-Coding-Standards.git",
"reference": "7da1894633f168fe244afc6de00d141f27517b62"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/WordPress/WordPress-Coding-Standards/zipball/7da1894633f168fe244afc6de00d141f27517b62",
"reference": "7da1894633f168fe244afc6de00d141f27517b62",
"shasum": ""
},
"require": {
"php": ">=5.4",
"squizlabs/php_codesniffer": "^3.3.1"
},
"require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "^0.5 || ^0.6",
"phpcompatibility/php-compatibility": "^9.0",
"phpcsstandards/phpcsdevtools": "^1.0",
"phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0"
},
"suggest": {
"dealerdirect/phpcodesniffer-composer-installer": "^0.6 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically."
},
"type": "phpcodesniffer-standard",
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Contributors",
"homepage": "https://github.com/WordPress/WordPress-Coding-Standards/graphs/contributors"
}
],
"description": "PHP_CodeSniffer rules (sniffs) to enforce WordPress coding conventions",
"keywords": [
"phpcs",
"standards",
"wordpress"
],
"support": {
"issues": "https://github.com/WordPress/WordPress-Coding-Standards/issues",
"source": "https://github.com/WordPress/WordPress-Coding-Standards",
"wiki": "https://github.com/WordPress/WordPress-Coding-Standards/wiki"
},
"time": "2020-05-13T23:57:56+00:00"
}
],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": [],
"platform-dev": [],
"plugin-api-version": "2.0.0"
}

View file

@ -1,61 +0,0 @@
#!/bin/sh
# Modified from: https://github.com/bjornjohansen/wp-pre-commit-hook
# Also: https://softdiscover.com/wordpress/perfect-setup-for-a-wordpress-project-development/
PROJECT=`php -r "echo dirname(dirname(dirname(realpath('$0'))));"`
STAGED_FILES_CMD=`git diff --cached --name-only --diff-filter=ACMR HEAD | grep \\\\.php`
# Determine if a file list is passed
if [ "$#" -eq 1 ]
then
oIFS=$IFS
IFS='
'
SFILES="$1"
IFS=$oIFS
fi
SFILES=${SFILES:-$STAGED_FILES_CMD}
echo "Checking PHP Lint..."
for FILE in $SFILES
do
php -l -d display_errors=0 $PROJECT/$FILE
if [ $? != 0 ]
then
echo "Fix the error before commit."
exit 1
fi
FILES="$FILES $PROJECT/$FILE"
done
if [ -f "$PROJECT/phpcs.ruleset.xml" ]
then
RULESET="$PROJECT/phpcs.ruleset.xml"
elif [ -f "$PROJECT/phpcs.xml.dist" ]
then
RULESET="$PROJECT/phpcs.xml.dist"
else
RULESET="WordPress"
fi
if [ "$FILES" != "" ]
then
echo "Checking Code Standard Compliance, using $RULESET as ruleset standard..."
./vendor/bin/phpcs --standard="$RULESET" --colors --encoding=utf-8 -n -p $FILES
if [ $? != 0 ]
then
echo "Coding standards errors have been detected. Running phpcbf..."
./vendor/bin/phpcbf --standard="$RULESET" --encoding=utf-8 -n -p $FILES
git add $FILES
echo "Running Code Sniffer again..."
./vendor/bin/phpcs --standard="$RULESET" --colors --encoding=utf-8 -n -p $FILES
if [ $? != 0 ]
then
echo "Errors found not fixable automatically. You need to manually fix them."
exit 1
fi
fi
fi
exit $?

View file

@ -1,27 +1,27 @@
<?php
/**
* Plugin Name: footnotes
* Plugin URI: https://wordpress.org/plugins/footnotes/
* Description: time to bring footnotes to your website! footnotes are known from offline publishing and everybody takes them for granted when reading a magazine.
* Author: Mark Cheret
* Version: 2.5.6
* Author URI: http://cheret.de/plugins/footnotes-2/
* Text Domain: footnotes
* Domain Path: /languages
*
* @package footnotes
* @copyright 2021 Mark Cheret (email: mark@cheret.de)
/*
Plugin Name: footnotes
Plugin URI: https://wordpress.org/plugins/footnotes/
Description: time to bring footnotes to your website! footnotes are known from offline publishing and everybody takes them for granted when reading a magazine.
Author: Mark Cheret
Version: 2.5.6d4
Author URI: http://cheret.de/plugins/footnotes-2/
Text Domain: footnotes
Domain Path: /languages
*/
/*
* Copyright 2021 Mark Cheret (email: mark@cheret.de)
*/
/**
* Version number for stylesheet cache busting.
*
* @since 2.1.4
* @since 2.5.3 (Hungarian)
* @var str
* @lastmodified 2021-02-23T2304+0100
* @lastmodified 2021-02-20T0438+0100
* @committer @pewgeuges
*/
define( 'C_STR_FOOTNOTES_VERSION', '2.5.6' );
define( 'C_STR_FOOTNOTES_VERSION', '2.5.6d4' );
/*
LICENSE NOTICE
@ -44,21 +44,21 @@ define( 'C_STR_FOOTNOTES_VERSION', '2.5.6' );
* Plugins main PHP file.
*
* @filesource
* @package footnotes
* @author Stefan Herndler
* @since 0.0.1
*/
// Get all common classes and functions.
require_once dirname( __FILE__ ) . '/includes.php';
// Get all common classes and functions
require_once(dirname(__FILE__) . "/includes.php");
// Add Plugin Links to the "installed plugins" page.
// add Plugin Links to the "installed plugins" page
$l_str_plugin_file = 'footnotes/footnotes.php';
add_filter( "plugin_action_links_{$l_str_plugin_file}", array( 'MCI_Footnotes_Hooks', 'plugin_links' ), 10, 2 );
add_filter("plugin_action_links_{$l_str_plugin_file}", array("MCI_Footnotes_Hooks", "PluginLinks"), 10, 2);
// Initialize the Plugin.
$g_obj_mci_footnotes = new MCI_Footnotes();
// Run the Plugin.
$g_obj_mci_footnotes->run();
// initialize the Plugin
$g_obj_MCI_Footnotes = new MCI_Footnotes();
// run the Plugin
$g_obj_MCI_Footnotes->run();
/**
* Sets the stylesheet enqueuing mode for production.

View file

@ -3,37 +3,36 @@
* Includes all common files.
*
* @filesource
* @package footnotes
* @author Stefan Herndler
* @since 1.5.0 14.09.14 13:40
*/
/**
* Requires (`require_once`) all `*.php` files inside a specific Directory.
* Requires (require_once) all *.php files inside a specific Directory.
*
* @author Stefan Herndler
* @since 1.5.0
* @param string $p_str_directory Absolute Directory path to lookup for `*.php` files.
* @param string $p_str_Directory Absolute Directory path to lookup for *.php files
*/
function mci_footnotes_require_php_files( $p_str_directory ) {
// Append slash at the end of the Directory if not exist.
if ( '/' !== substr( $p_str_directory, -1 ) ) {
$p_str_directory .= '/';
function MCI_Footnotes_requirePhpFiles($p_str_Directory) {
// append slash at the end of the Directory if not exist
if (substr($p_str_Directory, -1) != "/") {
$p_str_Directory .= "/";
}
// Get all PHP files inside Directory.
$l_arr_files = scandir( $p_str_directory );
// Iterate through each class.
foreach ( $l_arr_files as $l_str_file_name ) {
// Skip all non-PHP files.
if ( '.php' !== strtolower( substr( $l_str_file_name, -4 ) ) ) {
// get all PHP files inside Directory
$l_arr_Files = scandir($p_str_Directory);
// iterate through each class
foreach ($l_arr_Files as $l_str_FileName) {
// skip all non *.php files
if (strtolower(substr($l_str_FileName, -4)) != ".php") {
continue;
}
// phpcs:disable Generic.Commenting.DocComment.MissingShort
/** @noinspection PhpIncludeInspection */
require_once $p_str_directory . $l_str_file_name;
// phpcs:enable
require_once($p_str_Directory . $l_str_FileName);
}
}
mci_footnotes_require_php_files( dirname( __FILE__ ) . '/class' );
mci_footnotes_require_php_files( dirname( __FILE__ ) . '/class/layout' );
mci_footnotes_require_php_files( dirname( __FILE__ ) . '/class/widgets' );
MCI_Footnotes_requirePhpFiles(dirname(__FILE__) . "/class");
MCI_Footnotes_requirePhpFiles(dirname(__FILE__) . "/class/dashboard");
MCI_Footnotes_requirePhpFiles(dirname(__FILE__) . "/class/widgets");

View file

@ -1,10 +1,10 @@
=== footnotes ===
Contributors: mark.cheret, lolzim, rumperuu, aricura, misfist, ericakfranz, dartiss, docteurfitness, felipelavinz, martinneumannat, matkus2, meglio, spaceling, vonpiernik, pewgeuges
Contributors: mark.cheret, lolzim, dartiss, docteurfitness, felipelavinz, martinneumannat, matkus2, meglio, misfist, rumperuu, spaceling, vonpiernik, pewgeuges
Tags: footnote, footnotes, bibliography, formatting, notes, Post, posts, reference, referencing
Requires at least: 3.9
Tested up to: 5.6.1
Requires PHP: 5.6
Stable Tag: 2.5.6
Stable Tag: 2.5.5
License: GPLv3 or later
License URI: http://www.gnu.org/licenses/gpl-3.0.html
@ -80,7 +80,7 @@ Visit this swift write-up from a **footnotes** user by the name of **Southwest**
= 2.5.6 =
- Bugfix: Reference container: optional alternative expanding and collapsing without jQuery for use with hard links, thanks to @hopper87it @pkverma99 issue reports.
- Bugfix: Alternative tooltips: shrink width to short content.
- Update: Documentation: slightly revise or update the plugins welcome page on WordPress.org.
- Update: Documentation: slightly revise / update the plugins welcome page on WordPress.org.
= 2.5.5 =
- Update: Stylesheets: increase speed and energy efficiency by tailoring stylesheets to the needs of the instance, thanks to @docteurfitness design contribution.
@ -326,7 +326,7 @@ Visit this swift write-up from a **footnotes** user by the name of **Southwest**
= 2.0.4 =
- Update: Restore arrow settings to customize or disable the now prepended arrow symbol.
- Update: Libraries: Load jQuery UI from WordPress, thanks to @check2020de issue report.
- Update: GDPR: Add jQuery UI from WordPress instead of third party.
- Bugfix: Referrers and backlinks: remove hard links to streamline browsing history, thanks to @theroninjedi47 bug report.
- Bugfix: Reference container: remove inconvenient left/right cellpadding.
- Bugfix: Tooltips: improve layout with inherited font size by lower line height.

View file

@ -54,7 +54,7 @@
type: 'POST',
url: '/wp-admin/admin-ajax.php',
data: {
action: 'footnotes_get_plugin_info',
action: 'footnotes_getPluginInfo',
plugin: '[[plugin-name]]'
},
dataType: 'json',

View file

@ -4,8 +4,8 @@
-->
<span
class="footnote_referrer relative"
onmouseover="footnote_tooltip_show('footnote_plugin_tooltip_text_[[post_id]]_[[container_id]]_[[note_id]]')"
onmouseout="footnote_tooltip_hide('footnote_plugin_tooltip_text_[[post_id]]_[[container_id]]_[[note_id]]')"
onmouseover="footnoteTooltipShow('footnote_plugin_tooltip_text_[[post_id]]_[[container_id]]_[[note_id]]')"
onmouseout="footnoteTooltipHide('footnote_plugin_tooltip_text_[[post_id]]_[[container_id]]_[[note_id]]')"
><[[link-span]]
onclick="footnote_moveToAnchor_[[post_id]]_[[container_id]]('footnote_plugin_reference_[[post_id]]_[[container_id]]_[[note_id]]');"
[[hard-link]]
@ -17,7 +17,7 @@
>[[anchor-element]]<span
id="footnote_plugin_tooltip_text_[[post_id]]_[[container_id]]_[[note_id]]"
class="footnote_tooltip position hidden"
onmouseout="footnote_tooltip_hide('footnote_plugin_tooltip_text_[[post_id]]_[[container_id]]_[[note_id]]')"
onmouseout="footnoteTooltipHide('footnote_plugin_tooltip_text_[[post_id]]_[[container_id]]_[[note_id]]')"
[[style]]
>[[text]]</span
></span