Skip to content

Instantly share code, notes, and snippets.

@SalvatoreNoschese
Created August 19, 2024 07:19
Show Gist options
  • Save SalvatoreNoschese/5607cc118c70ec9940ecc0e439420c06 to your computer and use it in GitHub Desktop.
Save SalvatoreNoschese/5607cc118c70ec9940ecc0e439420c06 to your computer and use it in GitHub Desktop.
<?php
/*
Plugin Name: Tiny GoToTop
Description: A simple plugin to add a "go to top" button to your site.
Version: 1.0
Author: Salvatore Noschese
Author URI: https://salvatorenoschese.it
Text Domain: tiny-gototop
Domain Path: /languages
*/
class Tiny_GoToTop {
// Default settings for the plugin
const DEFAULTS = [
'main_color' => '#023e47',
'secondary_color' => '#8b6b36',
'opacity' => 0.5,
'position_right' => 20,
'position_bottom' => 20,
'padding' => 10,
'width' => 20,
'height' => 20,
'border_radius' => 50, // % for border-radius
];
// Hold plugin data
private $plugin_data;
// Constructor to initialize the plugin, load data, and add hooks
public function __construct() {
// Load plugin data
if (!function_exists('get_plugin_data')) {
require_once(ABSPATH . 'wp-admin/includes/plugin.php');
}
$this->plugin_data = get_plugin_data(__FILE__);
// Load the plugin's text domain for translations
add_action('plugins_loaded', [$this, 'load_textdomain']);
// Add a settings page to the WordPress admin menu
add_action('admin_menu', [$this, 'add_settings_page']);
// Enqueue scripts and styles for the admin area
add_action('admin_enqueue_scripts', [$this, 'enqueue_admin_scripts']);
// Enqueue scripts and styles for the frontend
add_action('wp_enqueue_scripts', [$this, 'enqueue_frontend_scripts']);
// Print the "go to top" button in the footer
add_action('wp_footer', [$this, 'print_button']);
// add settings link
add_filter('plugin_action_links_' . plugin_basename(__FILE__), [$this, 'add_plugin_page_settings_link']);
// add donate link
add_filter('plugin_row_meta', [$this, 'plugin_row_meta'], 10, 2);
// Add the custom footer
add_filter('admin_footer_text', [$this, 'custom_footer_text']);
}
// Load text domain for internationalization
public function load_textdomain() {
load_plugin_textdomain('tiny-gototop', false, dirname(plugin_basename(__FILE__)) . '/languages');
}
// custom footer
public function custom_footer_text($footer_text) {
$screen = get_current_screen();
if ($screen && strpos($screen->id, 'tiny-gototop') !== false) {
$plugin_name = $this->plugin_data['Name'];
$plugin_version = $this->plugin_data['Version'];
$author = $this->plugin_data['Author'];
return "<strong><em>$plugin_name v$plugin_version | by $author</em></strong>";
}
return $footer_text;
}
// Get a plugin option, returning the default if the option is not set
public function get_option($name) {
return get_option('tiny_gototop_' . $name, self::DEFAULTS[$name]);
}
// Remove options if deactivated
public static function deactivate() {
$option_names = [
'main_color', 'secondary_color', 'opacity', 'position_right',
'position_bottom', 'padding', 'width', 'height', 'border_radius'
];
foreach ($option_names as $option) {
delete_option('tiny_gototop_' . $option);
}
// Rimuovi il file CSS generato
$css_file = plugin_dir_path(__FILE__) . 'assets/tiny-gototop.css';
if (file_exists($css_file)) {
unlink($css_file);
}
// Rimuovi il transient
delete_transient('tiny_gototop_css');
}
// add settings link
public function add_plugin_page_settings_link($actions) {
$mylinks = [
'<a href="https://salvatorenoschese.it" title="' . __('Support') . '" target="_blank">' . __('Support') . ' 🔗</a>',
'<a href="' . admin_url("options-general.php?page=tiny-gototop") . '" title="' . __('Settings') . '">' . __('Settings') . ' ⚙️</a>',
];
return array_merge($actions, $mylinks);
}
// add donate link
public function plugin_row_meta($links, $file) {
if (plugin_basename(__FILE__) === $file) {
$new_links = [
'<a href="https://paypal.me/SalvatoreN" target="_blank">' . __('Donate', 'tiny-gototop') . ' &#127873;</a>'
];
$links = array_merge($links, $new_links);
}
return $links;
}
// Generate the CSS for the "go to top" button
public function generate_css($css = null) {
// If no custom CSS is passed, generate it based on settings
if ($css === null) {
$main_color = $this->get_option('main_color');
$secondary_color = $this->get_option('secondary_color');
$opacity = $this->get_option('opacity');
$position_right = $this->get_option('position_right');
$position_bottom = $this->get_option('position_bottom');
$padding = $this->get_option('padding');
$width = $this->get_option('width');
$height = $this->get_option('height');
$border_radius = $this->get_option('border_radius');
// CSS rules for the button
$css = "#go-to-top {\n";
$css .= " display: none;\n";
$css .= " position: fixed;\n";
$css .= " bottom: {$position_bottom}px;\n";
$css .= " right: {$position_right}px;\n";
$css .= " cursor: pointer;\n";
$css .= " padding: {$padding}px;\n";
$css .= " width: {$width}px;\n";
$css .= " height: {$height}px;\n";
$css .= " border-radius: {$border_radius}%;\n";
$css .= " z-index: 1000;\n";
$css .= " opacity: {$opacity};\n";
$css .= " box-shadow: 0 2px 5px rgba(0,0,0,0.3);\n";
$css .= " background-color: {$main_color};\n";
$css .= " transition: background-color 0.3s ease;\n";
$css .= "}\n";
// CSS rules for hover state
$css .= "@media (hover: hover) {\n";
$css .= " #go-to-top:hover {\n";
$css .= " background-color: {$secondary_color};\n";
$css .= " }\n";
$css .= "}\n";
// CSS rules for active background
$css .= "#go-to-top.active-background {\n";
$css .= " background-color: {$secondary_color};\n";
$css .= "}";
}
// Save the generated CSS to a file
$css_file = plugin_dir_path(__FILE__) . 'assets/tiny-gototop.css';
file_put_contents($css_file, $css);
// Store the CSS in a transient for faster access
set_transient('tiny_gototop_css', $css, 12 * HOUR_IN_SECONDS);
}
// Save the plugin settings, resetting to defaults if necessary
public function save_settings($reset = false) {
// Check the nonce for security
check_admin_referer('tiny_gototop_update_options');
// Loop through each setting
foreach (self::DEFAULTS as $key => $default) {
if ($reset) {
// Reset to default if reset is true
update_option('tiny_gototop_' . $key, $default);
} else {
// Otherwise, save the value from the form, or default if not set
$value = isset($_POST['tiny_gototop_' . $key]) ? $this->sanitize_option($key, $_POST['tiny_gototop_' . $key]) : $default;
update_option('tiny_gototop_' . $key, $value);
}
}
// Generate the updated CSS
$this->generate_css();
}
// Sanitize options based on their expected data type
public function sanitize_option($key, $value) {
switch ($key) {
case 'main_color':
case 'secondary_color':
return sanitize_hex_color($value); // Sanitize colors
case 'opacity':
return floatval($value); // Convert opacity to float
default:
return intval($value); // Convert other values to integers
}
}
// Add the settings page to the WordPress admin menu
public function add_settings_page() {
add_options_page(
sprintf(__('Tiny GoToTop: %s', 'tiny-gototop'), __('Settings')), // Page title
__('Tiny GoToTop', 'tiny-gototop'),
'manage_options',
'tiny-gototop',
[$this, 'render_settings_page']
);
}
// Render the settings page in the admin area
public function render_settings_page() {
// Ensure the CSS file exists
$this->check_css_file();
?>
<div class="wrap">
<h1>Tiny GoToTop: <?php _e('Settings'); ?> ⚙️</h1>
<?php
// Handle form submission for saving settings
if (isset($_POST['submit']) && check_admin_referer('tiny_gototop_update_options')) {
$this->save_settings();
echo '<div class="notice notice-success is-dismissible"><p>' . __('Settings Saved ✅', 'tiny-gototop') . '</p></div>';
}
// Handle form submission for resetting settings
if (isset($_POST['reset']) && check_admin_referer('tiny_gototop_update_options')) {
$this->save_settings(true);
echo '<div class="notice notice-warning is-dismissible"><p>' . __('Settings Restored 🗑️', 'tiny-gototop') . '</p></div>';
}
?>
<hr />
<form method="post" action="">
<?php wp_nonce_field('tiny_gototop_update_options'); ?>
<table class="form-table">
<?php $this->render_settings_fields(); ?>
</table>
<hr />
<code><small><?php _e('ℹ️ Live preview always present here in the backend!', 'tiny-gototop'); ?></small></code>
<div class="submit">
<input type="submit" name="submit" class="button-primary" value="<?php _e('Save Changes', 'tiny-gototop'); ?>" />
<input type="submit" name="reset" class="button-secondary" value="<?php _e('Restore Default', 'tiny-gototop'); ?>" />
</div>
</form>
</div>
<?php
// Display the preview of the "go to top" button
$this->print_button();
}
// Render the fields for the settings page
private function render_settings_fields() {
// Define the fields to be rendered
$fields = [
'main_color' => __('Main Color', 'tiny-gototop'),
'secondary_color' => __('Secondary Color', 'tiny-gototop'),
'opacity' => __('Opacity', 'tiny-gototop'),
'position_right' => __('Right (px)', 'tiny-gototop'),
'position_bottom' => __('Bottom (px)', 'tiny-gototop'),
'padding' => __('Padding (px)', 'tiny-gototop'),
'width' => __('Width (px)', 'tiny-gototop'),
'height' => __('Height (px)', 'tiny-gototop'),
'border_radius' => __('Border Radius (%)', 'tiny-gototop'),
];
// Loop through each field to render its label and input
foreach ($fields as $key => $label) {
echo '<tr>';
echo '<th scope="row"><label for="tiny_gototop_' . $key . '">' . $label . '</label></th>';
echo '<td>';
// Render different input types based on the setting type
if ($key === 'opacity') {
$this->render_opacity_select($key); // Opacity uses a select dropdown
} elseif (in_array($key, ['main_color', 'secondary_color'])) {
$this->render_color_input($key); // Colors use a color picker
} else {
$this->render_number_input($key); // Others use a number input
}
echo '</td>';
echo '</tr>';
}
}
// Render the select dropdown for the opacity setting
private function render_opacity_select($key) {
$current_opacity = esc_attr($this->get_option($key));
echo '<select class="go-to-top-select" name="tiny_gototop_' . $key . '" style="width:60px">';
// Generate options from 0 to 1 in increments of 0.1
for ($i = 0; $i <= 10; $i++) {
$value = $i / 10;
echo '<option value="' . $value . '" ' . selected($current_opacity, $value, false) . '>' . $value . '</option>';
}
echo '</select>';
}
// Render the color picker input
private function render_color_input($key) {
echo '<input type="text" class="tiny-color-picker" id="tiny_gototop_' . $key . '" name="tiny_gototop_' . $key . '" value="' . esc_attr($this->get_option($key)) . '" />';
}
// Render the number input for various settings
private function render_number_input($key) {
echo '<input type="number" id="tiny_gototop_' . $key . '" name="tiny_gototop_' . $key . '" value="' . esc_attr($this->get_option($key)) . '" />';
}
// Ensure the CSS file exists, generate it if it doesn't
public function check_css_file() {
$css_file = plugin_dir_path(__FILE__) . 'assets/tiny-gototop.css';
if (!file_exists($css_file)) {
$this->generate_css();
}
}
// Print the "go to top" button in the frontend or admin preview
public function print_button() {
$width = $this->get_option('width');
$height = $this->get_option('height');
// Attributes for the admin preview
$attrib = is_admin() ? 'title="' . __('Just a preview', 'tiny-gototop') . '" style="display:block" ' : '';
echo '
<!-- Go to top -->
<img id="go-to-top" src="' . plugin_dir_url(__FILE__) . 'assets/tiny-gototop.svg" alt="' . __('go to top (svg)', 'tiny-gototop') . '" width="' . esc_attr($width) . '" height="' . esc_attr($height) . '" ' . $attrib . '/>
<!-- Go to top -->';
}
// Enqueue admin scripts and styles, including color picker and custom CSS
public function enqueue_admin_scripts($hook_suffix) {
if ($hook_suffix === 'settings_page_tiny-gototop') {
$css_version = time(); // Use current timestamp to avoid cache issues
wp_enqueue_style('wp-color-picker');
wp_enqueue_script('tiny-gototop-backend-script', plugin_dir_url(__FILE__) . 'assets/tiny-gototop-backend.js', array('wp-color-picker'), false, true);
wp_enqueue_style('tiny-gototop-backend-style', plugin_dir_url(__FILE__) . 'assets/tiny-gototop-backend.css');
wp_enqueue_style('tiny-gototop-style', plugin_dir_url(__FILE__) . 'assets/tiny-gototop.css', array(), $css_version);
}
}
// Enqueue frontend scripts and styles
public function enqueue_frontend_scripts() {
$this->check_css_file(); // Ensure the CSS file exists
$css_file = plugin_dir_path(__FILE__) . 'assets/tiny-gototop.css';
$css_version = filemtime($css_file); // Use file modification time for cache busting
wp_enqueue_style('tiny-gototop-style', plugin_dir_url(__FILE__) . 'assets/tiny-gototop.css', array(), $css_version);
wp_enqueue_script('tiny-gototop-script', plugin_dir_url(__FILE__) . 'assets/tiny-gototop.js', array(), null, true);
}
}
// Instantiate the Tiny_GoToTop class to initialize the plugin
$tiny_gototop = new Tiny_GoToTop();
// Clean if deactivated
register_deactivation_hook(__FILE__, ['Tiny_GoToTop', 'deactivate']);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment