true, 'google-map' => true, 'image' => true, 'slider' => true, 'post-carousel' => true, 'editor' => true, ); public function __construct() { add_action( 'admin_init', array( $this, 'admin_activate_widget' ) ); add_action( 'admin_menu', array( $this, 'admin_menu_init' ) ); add_action( 'admin_init', array( $this, 'clear_file_cache' ) ); add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) ); add_action( 'admin_enqueue_scripts', array( $this, 'admin_register_scripts' ) ); // All the Ajax actions. add_action( 'wp_ajax_so_widgets_bundle_manage', array( $this, 'admin_ajax_manage_handler' ) ); add_action( 'wp_ajax_sow_get_javascript_variables', array( $this, 'admin_ajax_get_javascript_variables' ) ); add_action( 'wp_ajax_so_widgets_setting_form', array( $this, 'admin_ajax_settings_form' ) ); add_action( 'wp_ajax_so_widgets_setting_save', array( $this, 'admin_ajax_settings_save' ) ); // Initialize the widgets, but do it fairly late. add_action( 'plugins_loaded', array( $this, 'set_plugin_textdomain' ), 1 ); add_action( 'after_setup_theme', array( $this, 'get_widget_folders' ), 11 ); add_action( 'after_setup_theme', array( $this, 'load_widget_plugins' ), 11 ); // Add the plugin_action_links links. add_action( 'plugin_action_links_' . plugin_basename( __FILE__ ), array( $this, 'plugin_action_links' ) ); add_action( 'admin_init', array( $this, 'plugin_version_check' ) ); add_action( 'siteorigin_widgets_version_update', array( $this, 'handle_update' ), 10, 2 ); // Actions for clearing widget cache. add_action( 'switch_theme', array( $this, 'clear_widget_cache' ) ); add_action( 'activated_plugin', array( $this, 'clear_widget_cache' ) ); add_action( 'upgrader_process_complete', array( $this, 'clear_widget_cache' ) ); // These filters are used to activate any widgets that are missing. add_filter( 'siteorigin_panels_data', array( $this, 'load_missing_widgets' ) ); add_filter( 'siteorigin_panels_prebuilt_layout', array( $this, 'load_missing_widgets' ) ); add_filter( 'siteorigin_panels_widget_object', array( $this, 'load_missing_widget' ), 10, 2 ); add_filter( 'wp_enqueue_scripts', array( $this, 'register_general_scripts' ) ); add_filter( 'wp_enqueue_scripts', array( $this, 'enqueue_active_widgets_scripts' ) ); // Add compatibility for Autoptimize. if ( class_exists( 'autoptimizeMain', false ) ) { add_filter( 'autoptimize_filter_css_exclude', array( $this, 'include_widgets_css_in_autoptimize' ), 10, 2 ); } } /** * Get the single of this plugin. * * @return SiteOrigin_Widgets_Bundle */ public static function single() { static $single; if ( empty( $single ) ) { $single = new SiteOrigin_Widgets_Bundle(); } return $single; } /** * Set the text domain for the plugin. * * @action plugins_loaded */ public function set_plugin_textdomain() { load_plugin_textdomain( 'so-widgets-bundle', false, dirname( plugin_basename( __FILE__ ) ) . '/lang/' ); } /** * This clears the file cache. * * @action admin_init */ public function plugin_version_check() { $active_version = get_option( 'siteorigin_widget_bundle_version' ); $is_new = empty( $active_version ) || version_compare( $active_version, SOW_BUNDLE_VERSION, '<' ); $is_new = apply_filters( 'siteorigin_widgets_is_new_version', $is_new ); if ( $is_new ) { update_option( 'siteorigin_widget_bundle_version', SOW_BUNDLE_VERSION ); // If this is a new version, then trigger an action to let widgets handle the updates. do_action( 'siteorigin_widgets_version_update', SOW_BUNDLE_VERSION, $active_version ); $this->clear_widget_cache(); } } /** * This should call any necessary functions when the plugin has been updated. * * @action siteorigin_widgets_version_update */ public function handle_update( $old_version, $new_version ) { // Always check for new widgets. $this->check_for_new_widgets(); } /** * Deletes any CSS generated by/for the widgets. * Called on 'upgrader_process_complete', 'switch_theme', and 'activated_plugin' actions. * Can also be called directly on the `SiteOrigin_Widgets_Bundle` singleton class. * * @action upgrader_process_complete Occurs after any theme, plugin or the WordPress core is updated to a new version. * @action switch_theme Occurs after switching to a different theme. * @action activated_plugin Occurs after a plugin has been activated. */ public function clear_widget_cache() { // Remove all cached CSS for SiteOrigin Widgets. require_once ABSPATH . 'wp-admin/includes/file.php'; if ( function_exists( 'WP_Filesystem' ) && WP_Filesystem() ) { global $wp_filesystem; $upload_dir = wp_upload_dir(); // Remove any old widget cache files, if they exist. $list = $wp_filesystem->dirlist( $upload_dir['basedir'] . '/siteorigin-widgets/' ); if ( ! empty( $list ) ) { foreach ( $list as $file ) { // Delete the file $wp_filesystem->delete( $upload_dir['basedir'] . '/siteorigin-widgets/' . $file['name'] ); } } // Alert other plugins that we've deleted all CSS files. do_action( 'siteorigin_widgets_stylesheet_cleared' ); } } /** * Setup and return the widget folders. */ public function check_for_new_widgets() { // get list of available widgets $widgets = array_keys( $this->get_widgets_list() ); // get option for previously installed widgets $old_widgets = get_option( 'siteorigin_widgets_old_widgets' ); // if this has never been set before, it's probably a new installation so we don't want to notify for all the widgets if ( empty( $old_widgets ) ) { update_option( 'siteorigin_widgets_old_widgets', implode( ',', $widgets ) ); return; } $old_widgets = explode( ',', $old_widgets ); $new_widgets = array_diff( $widgets, $old_widgets ); if ( ! empty( $new_widgets ) ) { update_option( 'siteorigin_widgets_new_widgets', $new_widgets ); update_option( 'siteorigin_widgets_old_widgets', implode( ',', $widgets ) ); } } /** * Setup and return the widget folders. */ public function get_widget_folders() { if ( empty( $this->widget_folders ) ) { // We can use this filter to add more folders to use for widgets. $this->widget_folders = apply_filters( 'siteorigin_widgets_widget_folders', array( plugin_dir_path( __FILE__ ) . 'widgets/', ) ); } return $this->widget_folders; } /** * Load all the widgets if their plugins are not already active. * * @action plugins_loaded */ public function load_widget_plugins() { // Load all the widget we currently have active and filter them. $active_widgets = $this->get_active_widgets(); $widget_folders = $this->get_widget_folders(); foreach ( $active_widgets as $widget_id => $active ) { if ( empty( $active ) ) { continue; } foreach ( $widget_folders as $folder ) { if ( ! file_exists( $folder . $widget_id . '/' . $widget_id . '.php' ) ) { continue; } // Include this widget file. include_once $folder . $widget_id . '/' . $widget_id . '.php'; } } } /** * Get a list of currently active widgets. * * @param bool $filter * * @return mixed|void */ public function get_active_widgets( $filter = true ) { // Basic caching of the current active widgets. $active_widgets = wp_cache_get( 'active_widgets', 'siteorigin_widgets' ); if ( empty( $active_widgets ) ) { $active_widgets = get_option( 'siteorigin_widgets_active', array() ); $active_widgets = wp_parse_args( $active_widgets, apply_filters( 'siteorigin_widgets_default_active', self::$default_active_widgets ) ); // Migrate any old names. foreach ( $active_widgets as $widget_name => $is_active ) { if ( substr( $widget_name, 0, 3 ) !== 'so-' ) { continue; } if ( preg_match( '/so-([a-z\-]+)-widget/', $widget_name, $matches ) && ! isset( $active_widgets[ $matches[1] ] ) ) { unset( $active_widgets[ $widget_name ] ); $active_widgets[ $matches[1] ] = $is_active; } } if ( $filter ) { $active_widgets = apply_filters( 'siteorigin_widgets_active_widgets', $active_widgets ); } wp_cache_add( 'active_widgets', $active_widgets, 'siteorigin_widgets' ); } return $active_widgets; } /** * Enqueue the admin page stuff. */ public function admin_enqueue_scripts( $prefix ) { if ( $prefix != 'plugins_page_so-widgets-plugins' ) { return; } wp_enqueue_style( 'siteorigin-widgets-manage-admin', plugin_dir_url( __FILE__ ) . 'admin/admin.css', array(), SOW_BUNDLE_VERSION ); wp_enqueue_script( 'siteorigin-widgets-trianglify', plugin_dir_url( __FILE__ ) . 'admin/trianglify' . SOW_BUNDLE_JS_SUFFIX . '.js', array(), SOW_BUNDLE_VERSION ); wp_enqueue_script( 'siteorigin-widgets-manage-admin', plugin_dir_url( __FILE__ ) . 'admin/admin' . SOW_BUNDLE_JS_SUFFIX . '.js', array(), SOW_BUNDLE_VERSION ); wp_localize_script( 'siteorigin-widgets-manage-admin', 'soWidgetsAdmin', array( 'toggleUrl' => wp_nonce_url( admin_url( 'admin-ajax.php?action=so_widgets_bundle_manage' ), 'manage_so_widget' ), ) ); } /** * The fallback (from ajax) URL handler for activating or deactivating a widget. */ public function admin_activate_widget() { if ( current_user_can( apply_filters( 'siteorigin_widgets_admin_menu_capability', 'manage_options' ) ) && ! empty( $_GET['page'] ) && $_GET['page'] == 'so-widgets-plugins' && ! empty( $_GET['widget_action'] ) && ! empty( $_GET['widget'] ) && isset( $_GET['_wpnonce'] ) && wp_verify_nonce( $_GET['_wpnonce'], 'siteorigin_widget_action' ) ) { switch ( $_GET['widget_action'] ) { case 'activate': $this->activate_widget( $_GET['widget'] ); break; case 'deactivate': $this->deactivate_widget( $_GET['widget'] ); break; } // Redirect and clear all the args wp_redirect( add_query_arg( array( '_wpnonce' => false, 'widget_action_done' => 'true', ) ) ); } } /** * Clear all old CSS files. * * @var bool Whether to forcefully clear the file cache. * @var int The maximum age of a file before it's removed. */ public static function clear_file_cache( $force_delete = false, $css_expire = 604800 ) { // Use this variable to ensure this only runs once per request. static $done = false; if ( $done && ! $force_delete ) { return; } if ( ! get_transient( 'sow:cleared' ) || $force_delete ) { require_once ABSPATH . 'wp-admin/includes/file.php'; if ( WP_Filesystem() ) { global $wp_filesystem; $upload_dir = wp_upload_dir(); $list = $wp_filesystem->dirlist( $upload_dir['basedir'] . '/siteorigin-widgets/' ); if ( ! empty( $list ) ) { foreach ( $list as $file ) { if ( $file['lastmodunix'] < time() - $css_expire || $force_delete ) { // Delete the file. $wp_filesystem->delete( $upload_dir['basedir'] . '/siteorigin-widgets/' . $file['name'] ); // Alert other plugins that we've deleted a CSS file. do_action( 'siteorigin_widgets_stylesheet_deleted', $file['name'] ); } } } } // Set this transient so we know when to clear all the generated CSS. set_transient( 'sow:cleared', true, $css_expire ); } $done = true; } /** * Register some common scripts used in forms. */ public function admin_register_scripts() { wp_register_script( 'sowb-pikaday', plugin_dir_url( SOW_BUNDLE_BASE_FILE ) . 'js/lib/pikaday' . SOW_BUNDLE_JS_SUFFIX . '.js', array(), '1.5.1' ); wp_register_style( 'sowb-pikaday', plugin_dir_url( __FILE__ ) . 'js/lib/pikaday.css' ); wp_register_script( 'select2', plugin_dir_url( SOW_BUNDLE_BASE_FILE ) . 'js/lib/select2' . SOW_BUNDLE_JS_SUFFIX . '.js', array( 'jquery' ), '4.1.0-rc.0' ); wp_register_style( 'select2', plugin_dir_url( __FILE__ ) . 'css/lib/select2.css' ); } /** * Handler for activating and deactivating widgets. * * @action wp_ajax_so_widgets_bundle_manage */ public function admin_ajax_manage_handler() { if ( ! wp_verify_nonce( $_GET['_wpnonce'], 'manage_so_widget' ) ) { wp_die( __( 'Invalid request.', 'so-widgets-bundle' ), 403 ); } if ( ! current_user_can( apply_filters( 'siteorigin_widgets_admin_menu_capability', 'manage_options' ) ) ) { wp_die( __( 'Insufficient permissions.', 'so-widgets-bundle' ), 403 ); } if ( empty( $_POST['widget'] ) ) { wp_die( __( 'Invalid post.', 'so-widgets-bundle' ), 400 ); } if ( ! empty( $_POST['active'] ) ) { $this->activate_widget( $_POST['widget'] ); } else { $this->deactivate_widget( $_POST['widget'] ); } // Send a kind of dummy response. wp_send_json( array( 'done' => true ) ); } /** * Handler for displaying the Widget settings form. * * @action wp_ajax_so_widgets_setting_form */ public function admin_ajax_settings_form() { if ( ! wp_verify_nonce( $_GET['_wpnonce'], 'display-widget-form' ) ) { wp_die( __( 'Invalid request.', 'so-widgets-bundle' ), 403 ); } if ( ! current_user_can( apply_filters( 'siteorigin_widgets_admin_menu_capability', 'manage_options' ) ) ) { wp_die( __( 'Insufficient permissions.', 'so-widgets-bundle' ), 403 ); } $widget_objects = $this->get_widget_objects(); $widget_path = empty( $_GET['id'] ) ? false : wp_normalize_path( WP_CONTENT_DIR ) . $_GET['id']; $widget_object = empty( $widget_objects[ $widget_path ] ) ? false : $widget_objects[ $widget_path ]; if ( empty( $widget_object ) || ! $widget_object->has_form( 'settings' ) ) { wp_die( __( 'Invalid request.', 'so-widgets-bundle' ), 400 ); } unset( $widget_object->widget_options['has_preview'] ); $action_url = admin_url( 'admin-ajax.php' ); $action_url = add_query_arg( array( 'id' => $_GET['id'], 'action' => 'so_widgets_setting_save', ), $action_url ); $action_url = wp_nonce_url( $action_url, 'save-widget-settings' ); $value = $widget_object->get_global_settings(); ?>
get_widget_objects(); $widget_path = empty( $_GET['id'] ) ? false : wp_normalize_path( WP_CONTENT_DIR ) . $_GET['id']; $widget_object = empty( $widget_objects[ $widget_path ] ) ? false : $widget_objects[ $widget_path ]; if ( empty( $widget_object ) || ! $widget_object->has_form( 'settings' ) ) { wp_die( __( 'Invalid request.', 'so-widgets-bundle' ), 400 ); } $form_values = array_values( $_POST ); $form_values = array_shift( $form_values ); $widget_object->save_global_settings( stripslashes_deep( array_shift( $form_values ) ) ); wp_send_json_success(); } /** * Add the admin menu page. * * @action admin_menu */ public function admin_menu_init() { add_plugins_page( __( 'SiteOrigin Widgets', 'so-widgets-bundle' ), __( 'SiteOrigin Widgets', 'so-widgets-bundle' ), apply_filters( 'siteorigin_widgets_admin_menu_capability', 'manage_options' ), 'so-widgets-plugins', array( $this, 'admin_page' ) ); } /** * Display the admin page. */ public function admin_page() { $widgets = $this->get_widgets_list(); $widget_objects = $this->get_widget_objects(); if ( isset( $_GET['widget_action_done'] ) && ! empty( $_GET['widget_action'] ) && ! empty( $_GET['widget'] ) && ! empty( $widgets[ $_GET['widget'] . '/' . $_GET['widget'] . '.php' ] ) ) { ?>