File: /home/axxoncom/public_html/wp-content/plugins/timeliner-elementor/src/Merkulove/Unity/Settings.php
<?php
/**
* Timeliner for Elementor
* Beautiful graphical representation of a period of time for Elementor
* Exclusively on https://1.envato.market/timeliner-elementor
*
* @encoding UTF-8
* @version 1.0.4
* @copyright (C) 2018 - 2024 Merkulove ( https://merkulov.design/ ). All rights reserved.
* @license Envato License https://1.envato.market/KYbje
* @contributors Nemirovskiy Vitaliy (nemirovskiyvitaliy@gmail.com), Dmitry Merkulov (dmitry@merkulov.design)
* @support help@merkulov.design
**/
namespace Merkulove\TimelinerElementor\Unity;
/** Exit if accessed directly. */
if ( ! defined( 'ABSPATH' ) ) {
header( 'Status: 403 Forbidden' );
header( 'HTTP/1.1 403 Forbidden' );
exit;
}
/**
* SINGLETON: Class used to implement plugin settings.
*
* @since 1.0.0
*
**/
final class Settings {
/**
* Plugin settings.
*
* @since 1.0.0
* @access public
* @var array
**/
public $options = [];
/**
* The one true Settings.
*
* @since 1.0.0
* @access private
* @var Settings
**/
private static $instance;
/**
* Sets up a new Settings instance.
*
* @since 1.0.0
* @access private
*
* @return void
**/
private function __construct() {
/** Get plugin settings. */
$this->get_options();
/** Add plugin settings page. */
$this->add_settings_page();
/** Ajax handler for media library control */
add_action( 'wp_ajax_unity_media_library', [ $this, 'field_media_library' ] );
}
/**
* Filed media library
* Refresh image in media library
* @return void
*/
public function field_media_library() {
if( isset( $_GET[ 'id' ] ) ) {
$image = wp_get_attachment_image(
filter_input( INPUT_GET, 'id', FILTER_VALIDATE_INT ),
'medium'
);
$data = array(
'image' => $image,
);
wp_send_json_success( $data );
} else {
wp_send_json_error();
}
}
/**
* Render Tabs Headers.
*
* @param string $current_tab - current tab slug
*
* @return void
*/
private function render_tabs( string $current_tab = '') {
/** Tabs array. */
$tabs = Plugin::get_tabs();
/** If the plugin haven't Envato ID, remove activation tab. */
if ( 0 === EnvatoItem::get_instance()->get_id() ) {
unset( $tabs['activation'] );
}
/** Render Tabs. */
?>
<aside class="mdc-drawer">
<div class="mdc-drawer__content">
<nav class="mdc-list">
<?php $this->render_logo(); ?>
<hr class="mdc-plugin-menu">
<hr class="mdc-list-divider">
<h6 class="mdc-list-group__subheader"><?php echo esc_html__( 'Plugin settings', 'timeliner-elementor' ) ?></h6>
<?php
foreach ( $tabs as $tab => $value ) {
/** Skip disabled tabs. */
if ( ! Tab::is_tab_enabled( $tab ) ) { continue; }
/** Prepare CSS classes. */
$classes = [];
$classes[] = 'mdc-list-item';
$classes[] = 'mdp-menu-tab-' . esc_attr( $tab );
/** Mark Active Tab. */
if ( $tab === $current_tab ) {
$classes[] = 'mdc-list-item--activated';
}
/** Prepare link. */
$link = admin_url( 'admin.php?page=mdp_timeliner_elementor_settings&tab=' . $tab );
?>
<a class="<?php echo esc_attr( implode( ' ', $classes ) ); ?>" href="<?php echo esc_attr( $link ); ?>">
<i class='material-icons mdc-list-item__graphic' aria-hidden='true'><?php esc_html_e( $value['icon'] ); ?></i>
<span class='mdc-list-item__text'><?php esc_html_e( $value['label'] ); ?></span>
</a>
<?php
}
/** Helpful links. */
$this->support_link();
/** Activation Status. */
TabActivation::get_instance()->display_status();
/** Social links */
$this->social_link();
?>
</nav>
</div>
</aside>
<?php
}
/**
* Displays useful links for an activated and non-activated plugin.
*
* @since 1.0.0
* @access private
*
* @return void
**/
private function support_link() {
/** Disable this method for custom type plugins. */
if ( 'custom' === Plugin::get_type() ) { return; }
?>
<hr class="mdc-list-divider">
<h6 class="mdc-list-group__subheader"><?php echo esc_html__( 'Helpful links', 'timeliner-elementor' ) ?></h6>
<a class="mdc-list-item" href="https://docs.merkulov.design/tag/timeliner" target="_blank">
<i class="material-icons mdc-list-item__graphic" aria-hidden="true">collections_bookmark</i>
<span class="mdc-list-item__text"><?php echo esc_html__( 'Documentation', 'timeliner-elementor' ) ?></span>
</a>
<?php if ( TabActivation::get_instance()->is_activated() ) : /** Activated. */ ?>
<a class="mdc-list-item" href="https://1.envato.market/timeliner-elementor-support" target="_blank">
<i class="material-icons mdc-list-item__graphic" aria-hidden="true">mail</i>
<span class="mdc-list-item__text"><?php echo esc_html__( 'Get help', 'timeliner-elementor' ) ?></span>
</a>
<a class="mdc-list-item" href="https://1.envato.market/cc-downloads" target="_blank">
<i class="material-icons mdc-list-item__graphic" aria-hidden="true">thumb_up</i>
<span class="mdc-list-item__text"><?php echo esc_html__( 'Rate this plugin', 'timeliner-elementor' ) ?></span>
</a>
<?php endif; ?>
<a class="mdc-list-item" href="https://1.envato.market/cc-merkulove" target="_blank">
<i class="material-icons mdc-list-item__graphic" aria-hidden="true">store</i>
<span class="mdc-list-item__text"><?php echo esc_html__( 'More plugins', 'timeliner-elementor' ) ?></span>
</a>
<?php
}
/**
* Render social links
* @return void
*/
private function social_link() {
?>
<div class="mdc-social">
<a class="mdc-list-item" href="https://www.facebook.com/merkuloveteam" target="_blank" title="Facebook">
<svg width="16" aria-hidden="true" focusable="false" data-icon="facebook" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M504 256C504 119 393 8 256 8S8 119 8 256c0 123.78 90.69 226.38 209.25 245V327.69h-63V256h63v-54.64c0-62.15 37-96.48 93.67-96.48 27.14 0 55.52 4.84 55.52 4.84v61h-31.28c-30.8 0-40.41 19.12-40.41 38.73V256h68.78l-11 71.69h-57.78V501C413.31 482.38 504 379.78 504 256z"></path></svg>
</a>
<a class="mdc-list-item" href="https://twitter.com/merkuloveteam" target="_blank" title="Twitter">
<svg width="16" aria-hidden="true" focusable="false" data-icon="twitter" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z"></path></svg>
</a>
<a class="mdc-list-item" href="https://www.instagram.com/merkulove.team" target="_blank" title="Instagram">
<svg width="16" aria-hidden="true" focusable="false" data-icon="instagram" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" d="M224.1 141c-63.6 0-114.9 51.3-114.9 114.9s51.3 114.9 114.9 114.9S339 319.5 339 255.9 287.7 141 224.1 141zm0 189.6c-41.1 0-74.7-33.5-74.7-74.7s33.5-74.7 74.7-74.7 74.7 33.5 74.7 74.7-33.6 74.7-74.7 74.7zm146.4-194.3c0 14.9-12 26.8-26.8 26.8-14.9 0-26.8-12-26.8-26.8s12-26.8 26.8-26.8 26.8 12 26.8 26.8zm76.1 27.2c-1.7-35.9-9.9-67.7-36.2-93.9-26.2-26.2-58-34.4-93.9-36.2-37-2.1-147.9-2.1-184.9 0-35.8 1.7-67.6 9.9-93.9 36.1s-34.4 58-36.2 93.9c-2.1 37-2.1 147.9 0 184.9 1.7 35.9 9.9 67.7 36.2 93.9s58 34.4 93.9 36.2c37 2.1 147.9 2.1 184.9 0 35.9-1.7 67.7-9.9 93.9-36.2 26.2-26.2 34.4-58 36.2-93.9 2.1-37 2.1-147.8 0-184.8zM398.8 388c-7.8 19.6-22.9 34.7-42.6 42.6-29.5 11.7-99.5 9-132.1 9s-102.7 2.6-132.1-9c-19.6-7.8-34.7-22.9-42.6-42.6-11.7-29.5-9-99.5-9-132.1s-2.6-102.7 9-132.1c7.8-19.6 22.9-34.7 42.6-42.6 29.5-11.7 99.5-9 132.1-9s102.7-2.6 132.1 9c19.6 7.8 34.7 22.9 42.6 42.6 11.7 29.5 9 99.5 9 132.1s2.7 102.7-9 132.1z"></path></svg>
</a>
<a class="mdc-list-item" href="https://dribbble.com/merkuloveteam" target="_blank" title="Dribbble">
<svg width="16" aria-hidden="true" focusable="false" data-icon="dribbble" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 8C119.252 8 8 119.252 8 256s111.252 248 248 248 248-111.252 248-248S392.748 8 256 8zm163.97 114.366c29.503 36.046 47.369 81.957 47.835 131.955-6.984-1.477-77.018-15.682-147.502-6.818-5.752-14.041-11.181-26.393-18.617-41.614 78.321-31.977 113.818-77.482 118.284-83.523zM396.421 97.87c-3.81 5.427-35.697 48.286-111.021 76.519-34.712-63.776-73.185-116.168-79.04-124.008 67.176-16.193 137.966 1.27 190.061 47.489zm-230.48-33.25c5.585 7.659 43.438 60.116 78.537 122.509-99.087 26.313-186.36 25.934-195.834 25.809C62.38 147.205 106.678 92.573 165.941 64.62zM44.17 256.323c0-2.166.043-4.322.108-6.473 9.268.19 111.92 1.513 217.706-30.146 6.064 11.868 11.857 23.915 17.174 35.949-76.599 21.575-146.194 83.527-180.531 142.306C64.794 360.405 44.17 310.73 44.17 256.323zm81.807 167.113c22.127-45.233 82.178-103.622 167.579-132.756 29.74 77.283 42.039 142.053 45.189 160.638-68.112 29.013-150.015 21.053-212.768-27.882zm248.38 8.489c-2.171-12.886-13.446-74.897-41.152-151.033 66.38-10.626 124.7 6.768 131.947 9.055-9.442 58.941-43.273 109.844-90.795 141.978z"></path></svg>
</a>
</div>
<?php
}
/**
* Add plugin settings page.
*
* @since 1.0.0
* @access public
*
* @return void
**/
public function add_settings_page() {
add_action( 'admin_menu', [ $this, 'add_admin_menu' ], 1000 );
add_action( 'admin_init', [ $this, 'settings_init' ] );
}
/**
* Generate Settings Page.
*
* @since 1.0.0
* @access public
*
* @return void
**/
public function settings_init() {
/** Add settings foreach tab. */
foreach ( Plugin::get_tabs() as $tab_slug => $tab ) {
/** Skip tabs without handlers. */
if ( empty( $tab['class'] ) ) { continue; }
/** Call add_settings from appropriate class for each tab. */
call_user_func( [ $tab['class'], 'get_instance' ] )->add_settings( $tab_slug );
}
}
/**
* Add admin menu for plugin settings.
*
* @since 1.0.0
* @access public
*
* @return void
**/
public function add_admin_menu() {
$options = Settings::get_instance()->options;
/** Submenu for Elementor plugins. */
if ( 'elementor' === Plugin::get_type() ) {
$this->add_submenu_elementor( $options );
/** Submenu for WPBakery plugins. */
} else if ( 'wpbakery' === Plugin::get_type() ) {
$this->add_submenu_wpbakery( $options );
/** Root level menu for WordPress plugins. */
} else {
$this->add_menu_wordpress( $options );
}
}
/**
* Add admin menu for Elementor plugins.
*
* @since 1.0.0
* @access private
*
* @return void
**/
private function add_submenu_elementor( $options ) {
/** Check if Elementor installed and activated. */
$parent = 'options-general.php';
if ( did_action( 'elementor/loaded' ) ) {
$parent = 'elementor';
//$parent = 'edit-comments.php';
}
add_submenu_page(
$parent,
'Timeliner ' . esc_html__( 'Settings', 'timeliner-elementor' ),
'Timeliner ' . esc_html__( 'for Elementor', 'timeliner-elementor' ),
$options[ 'capability_settings' ] ?? 'manage_options',
'mdp_timeliner_elementor_settings',
[ $this, 'options_page' ]
);
}
/**
* Add admin menu for WPBakery plugins.
*
* @since 1.0.0
* @access private
*
* @return void
**/
private function add_submenu_wpbakery( $options ) {
/** Check if Elementor installed and activated. */
$parent = 'options-general.php';
add_submenu_page(
$parent,
'Timeliner ' . esc_html__( 'Settings', 'timeliner-elementor' ),
'Timeliner ' . esc_html__( 'for Elementor', 'timeliner-elementor' ),
$options[ 'capability_settings' ] ?? 'manage_options',
'mdp_timeliner_elementor_settings',
[ $this, 'options_page' ]
);
}
/**
* Add admin menu for WordPress plugins.
*
* @since 1.0.0
* @access private
*
* @return void
**/
private function add_menu_wordpress( $options ) {
add_menu_page(
'Timeliner for Elementor ' . esc_html__( 'Settings', 'timeliner-elementor' ),
'Timeliner for Elementor',
$options[ 'capability_settings' ] ?? 'manage_options',
'mdp_timeliner_elementor_settings',
[ $this, 'options_page' ],
$this->get_admin_menu_icon(),
$this->get_admin_menu_position()
);
}
/**
* Return path to admin menu icon or base64 encoded image.
*
* @return string
**/
private function get_admin_menu_icon(): string {
return 'data:image/svg+xml;base64,' . base64_encode( file_get_contents( Plugin::get_path() . 'images/logo-menu.svg' ) );
}
/**
* Calculate admin menu position based on plugin slug value.
*
* @since 1.0.0
* @access public
*
* @return string
**/
private function get_admin_menu_position(): string {
$hash = md5( Plugin::get_slug() );
$int = (int) filter_var( $hash, FILTER_SANITIZE_NUMBER_INT );
$int = (int) ( $int / 1000000000000 );
return '58.' . $int;
}
/**
* Plugin Settings Page.
*
* @return void
*/
public function options_page() {
$options = Settings::get_instance()->options;
/** User rights check. */
if ( ! current_user_can( $options[ 'capability_settings' ] ?? 'manage_options' ) ) { return; } ?>
<!--suppress HtmlUnknownTarget -->
<form action='options.php' method='post'>
<div class="wrap">
<?php
/** Current tab slug */
$current_tab = $this->get_current_tab();
/** Render "Settings saved!" message. */
$this->render_nags();
/** Render Tabs Headers. */
?><section class="mdp-aside"><?php $this->render_tabs( $current_tab ); ?></section><?php
/** Render Tabs Body. */
?><section class="mdp-tab-content mdp-tab-name-<?php echo esc_attr( $current_tab ) ?>"><?php
/** Call settings from appropriate class for current tab. */
foreach ( Plugin::get_tabs() as $tab_slug => $tab ) {
/** Work only on current tab. */
if ( ! $this->is_tab( $tab_slug, $current_tab ) ) { continue; }
/** Skip tabs without handlers. */
if ( empty( $tab['class'] ) ) { continue; }
call_user_func( [ $tab['class'], 'get_instance' ] )->do_settings( $tab_slug );
}
?>
</section>
</div>
</form>
<?php
}
/**
* Return current selected tab or first tab.
*
* @access private
* @return string
*/
private function get_current_tab(): string {
$tab = key( Plugin::get_tabs() ); // First tab is default tab
if ( isset ( $_GET['tab'] ) ) {
$tab = sanitize_key( $_GET['tab'] );
}
return apply_filters( 'timeliner_elementor_current_tab', $tab );
}
/**
* Check if passed tab is current tab and tab is enabled.
*
* @param string $tab - Current tab slug.
* @param string $current_tab - Current tab slug.
*
* @return bool
*/
private function is_tab( string $tab, string $current_tab ): bool {
return ( $tab === $current_tab ) && Tab::is_tab_enabled( $current_tab );
}
/**
* Render nags on after settings save.
*
* @since 1.0.0
* @access private
*
* @return void
**/
private function render_nags() {
/** Exit if this is not settings update. */
if ( ! isset( $_GET['settings-updated'] ) ) { return; }
/** Render "Settings Saved" message. */
$this->render_nag_saved();
/** Render Activation message. */
$this->render_nag_activation();
}
/**
* Render "Settings Saved" message.
*
* @since 1.0.0
* @access private
*
* @return void
**/
private function render_nag_saved() {
/** Exit if settings saving was not successful. */
if ( 'true' !== $_GET['settings-updated'] ) { return; }
/** Render "Settings Saved" message. */
UI::get_instance()->render_snackbar( esc_html__( 'Settings saved!', 'timeliner-elementor' ) );
}
/**
* Render Activation message.
*
* @since 1.0.0
* @access private
*
* @return void
**/
private function render_nag_activation() {
/** Exit if haven't tab slug. */
if ( ! isset( $_GET['tab'] ) ) { return; }
/** Exit if this not activation tab. */
if ( 'activation' !== $_GET['tab'] ) { return; }
/** Render Activation message. */
if ( TabActivation::get_instance()->is_activated() ) {
/** Render "Activation success" message. */
UI::get_instance()->render_snackbar( esc_html__( 'Plugin activated successfully.', 'timeliner-elementor' ), 'success', 5500 );
return;
}
/** Render "Activation failed" message. */
UI::get_instance()->render_snackbar( esc_html__( 'Invalid purchase code.', 'timeliner-elementor' ), 'error', 5500 );
}
/**
* Render logo and Save changes button in plugin settings.
*
* @since 1.0.0
* @access private
*
* @return void
**/
private function render_logo() {
?>
<div class="mdc-drawer__header mdc-plugin-fixed">
<a class="mdc-list-item mdp-plugin-title" href="#">
<i class="mdc-list-item__graphic" aria-hidden="true">
<img src="<?php echo esc_attr( Plugin::get_url() . 'images/logo-color.svg' ); ?>" alt="<?php echo esc_attr( 'TimelinerElementor' ) ?>">
</i>
<span class="mdc-list-item__text">
<?php if ( 'wordpress' === Plugin::get_type() ) : ?>
<?php echo esc_html( 'Timeliner for Elementor' ); ?>
<?php else: ?>
<?php echo esc_html( 'Timeliner' ); ?>
<?php endif; ?>
</span>
<span class="mdc-list-item__text">
<sup>
<?php esc_html_e( 'v.', 'timeliner-elementor' ); ?>
<?php echo esc_attr( Plugin::get_version() ); ?>
</sup>
</span>
</a>
<button type="submit" name="submit" id="submit" class="mdc-button mdc-button--dense mdc-button--raised">
<span class="mdc-button__label"><?php esc_html_e( 'Save changes', 'timeliner-elementor' ) ?></span>
</button>
</div>
<?php
}
/**
* Return settings array with default values.
*
* @param bool $tabs - setting tabs
*
* @return array
*/
public function get_default_settings( bool $tabs = false ): array {
/** Get all plugin tabs with settings fields */
if ( ! $tabs ) { $tabs = Plugin::get_tabs(); }
$default = [];
/** Collect settings from each tab. */
foreach ( $tabs as $tab ) {
/** If current tab haven't fields. */
if ( empty( $tab['fields'] ) ) { continue; }
/** Collect default values from each field. */
foreach ( $tab['fields'] as $field_slug => $field ) {
$default[$field_slug] = $field[ 'default' ] ?? '';
}
}
return $default;
}
/**
* Get plugin settings with default values.
*
* @since 1.0.0
* @access public
*
* @return void
**/
public function get_options() {
/** Default values. */
$defaults = $this->get_default_settings();
$results = [];
/** Get all plugin tabs with settings fields. */
$tabs = Plugin::get_tabs();
/** Collect settings from each tab. */
foreach ( $tabs as $tab_slug => $tab ) {
$opt_name = "mdp_timeliner_elementor_{$tab_slug}_settings";
$options = get_option( $opt_name );
$results = wp_parse_args( $options, $defaults );
$defaults = $results;
}
$this->options = $results;
}
/**
* Get CSS string from sides control
*
* @param array $options
* @param $slug
*
* @return string
*/
public static function get_sides_css( $slug, array $options = array() ): string {
if ( empty( $options ) ) {
$options = Settings::get_instance()->options;
}
$css = '';
foreach ( [ 'top', 'right', 'bottom', 'left' ] as $side ) {
$value = $options[ $slug . '_' .$side ] ?? $options[ $slug ][ $side ] ?? 0;
$unit = $options[ $slug . '_unit' ] ?? 'px';
$css .= $value . $unit . ' ';
}
return trim( $css );
}
/**
* Main Settings Instance.
*
* @return Settings
*/
public static function get_instance(): Settings {
if ( ! isset( self::$instance ) && ! ( self::$instance instanceof self ) ) {
self::$instance = new self;
}
return self::$instance;
}
}