define_constants(); spl_autoload_register(array($this, 'autoload')); $this->setup_actions(); $this->setup_filters(); $this->setup_shortcode(); $this->check_dependencies(); // Load in slideshow admin relates classes. $this->register_slide_types(); if (is_admin()) { $this->admin = new MetaSlider_Admin_Pages($this); } // Load in slideshow related classes require_once(METASLIDER_PATH . 'admin/slideshows/bootstrap.php'); $this->themes = MetaSlider_Themes::get_instance(); // Default to WP (4.4) REST API but backup with admin ajax require_once(METASLIDER_PATH . 'admin/routes/api.php'); $this->api = MetaSlider_Api::get_instance(); $this->api->setup(); $this->api->register_admin_ajax_hooks(); if (class_exists('WP_REST_Controller')) { new MetaSlider_REST_Controller(); } if (function_exists('register_block_type')) { $this->gutenberg = new MetaSlider_Gutenberg($this); } $capability = apply_filters('metaslider_capability', self::DEFAULT_CAPABILITY_EDIT_SLIDES); if (is_admin() && current_user_can($capability)) { $analytics = new MetaSlider_Analytics(); $analytics->load(); } // require_once(METASLIDER_PATH . 'admin/lib/temporary.php'); if (MetaSliderPlugin::should_load_extendify_sdk()) { require_once METASLIDER_PATH . 'admin/lib/extendify-notice.php'; } // require_once(METASLIDER_PATH . 'admin/lib/callout.php'); } /** * Define MetaSlider constants */ private function define_constants() { if (! defined('METASLIDER_VERSION')) { $assets_version = defined('SCRIPT_DEBUG') && SCRIPT_DEBUG ? uniqid() : $this->version; define('METASLIDER_VERSION', $this->version); define('METASLIDER_ASSETS_VERSION', $assets_version); define('METASLIDER_BASE_URL', plugin_dir_url(metaslider_plugin_is_installed('ml-slider'))); define('METASLIDER_ASSETS_URL', METASLIDER_BASE_URL . 'assets/'); define('METASLIDER_ADMIN_URL', METASLIDER_BASE_URL . 'admin/'); define('METASLIDER_ADMIN_ASSETS_URL', METASLIDER_ADMIN_URL . 'assets/'); define('METASLIDER_THEMES_PATH', METASLIDER_PATH . 'themes/'); define('METASLIDER_THEMES_URL', METASLIDER_BASE_URL . 'themes/'); } } /** * All MetaSlider classes */ private function plugin_classes() { return array( 'metaslider' => METASLIDER_PATH . 'inc/slider/metaslider.class.php', 'metacoinslider' => METASLIDER_PATH . 'inc/slider/metaslider.coin.class.php', 'metaflexslider' => METASLIDER_PATH . 'inc/slider/metaslider.flex.class.php', 'metanivoslider' => METASLIDER_PATH . 'inc/slider/metaslider.nivo.class.php', 'metaresponsiveslider' => METASLIDER_PATH . 'inc/slider/metaslider.responsive.class.php', 'metaslide' => METASLIDER_PATH . 'inc/slide/metaslide.class.php', 'metaimageslide' => METASLIDER_PATH . 'inc/slide/metaslide.image.class.php', 'metasliderimagehelper' => METASLIDER_PATH . 'inc/metaslider.imagehelper.class.php', 'metaslidersystemcheck' => METASLIDER_PATH . 'inc/metaslider.systemcheck.class.php', 'metaslider_widget' => METASLIDER_PATH . 'inc/metaslider.widget.class.php', 'simple_html_dom' => METASLIDER_PATH . 'inc/simple_html_dom.php', 'metaslider_notices' => METASLIDER_PATH . 'admin/Notices.php', 'metaslider_admin_pages' => METASLIDER_PATH . 'admin/Pages.php', 'metaslider_slideshows' => METASLIDER_PATH . 'admin/Slideshows/Slideshows.php', 'metaslider_settings' => METASLIDER_PATH . 'admin/Slideshows/Settings.php', 'metaslider_slide' => METASLIDER_PATH . 'admin/Slideshows/slides/Slide.php', 'metaslider_themes' => METASLIDER_PATH . 'admin/Slideshows/Themes.php', 'metaslider_image' => METASLIDER_PATH . 'admin/Slideshows/Image.php', 'metaslider_gutenberg' => METASLIDER_PATH . 'admin/Gutenberg.php', 'metaslider_analytics' => METASLIDER_PATH . 'admin/support/Analytics.php' ); } /** * Display a warning on the plugins page if a dependancy * is missing or a conflict might exist. * * @return void */ public function check_dependencies() { // MetaSlider pro is active but pre 2.13.0 (2.13.0 includes its own notice system) $slug = metaslider_plugin_is_installed('ml-slider-pro'); if (is_plugin_active($slug)) { $pro_data = get_file_data(trailingslashit(WP_PLUGIN_DIR) . $slug, array('Version' => 'Version')); $this->installed_pro_version = $pro_data['Version']; if ($this->installed_pro_version && version_compare($this->installed_pro_version, '2.13.0', '<')) { add_action('admin_notices', array($this, 'show_pro_is_outdated'), 10, 3); } } } /** * The warning message that is displayed * * @return void */ public function show_pro_is_outdated() { global $pagenow; $page = isset($_GET['page']) ? sanitize_key($_GET['page']) : ''; if ('update-core.php' !== $pagenow && 'plugins.php' !== $pagenow && 'metaslider' !== $page) { return; } ?>
plugin_classes(); $class_name = strtolower($class); if (isset($classes[$class_name]) && is_readable($classes[$class_name])) { require_once($classes[$class_name]); } } /** * Register the [metaslider] shortcode. */ private function setup_shortcode() { add_shortcode('metaslider', array($this, 'register_shortcode')); add_shortcode('ml-slider', array($this, 'register_shortcode')); // backwards compatibility } /** * Hook MetaSlider into WordPress */ private function setup_actions() { add_action('admin_menu', array($this, 'register_admin_pages'), 9553); add_action('init', array($this, 'register_post_types')); add_action('init', array($this, 'register_taxonomy')); add_action('init', array($this, 'load_plugin_textdomain')); add_action('admin_footer', array($this, 'admin_footer'), 11); add_action('widgets_init', array($this, 'register_metaslider_widget')); add_action('admin_post_metaslider_switch_view', array($this, 'switch_view')); add_action('admin_post_metaslider_delete_slide', array($this, 'delete_slide')); add_action('admin_post_metaslider_delete_slider', array($this, 'delete_slider')); add_action('admin_post_metaslider_create_slider', array($this, 'create_slider')); add_action('media_upload_vimeo', array($this, 'upgrade_to_pro_tab_vimeo')); add_action('media_upload_youtube', array($this, 'upgrade_to_pro_tab_youtube')); add_action('media_upload_post_feed', array($this, 'upgrade_to_pro_tab_post_feed')); add_action('media_upload_layer', array($this, 'upgrade_to_pro_tab_layer')); // TODO: Refactor to Slide class object add_action('wp_ajax_delete_slide', array($this, 'ajax_delete_slide')); add_action('wp_ajax_undelete_slide', array($this, 'ajax_undelete_slide')); // Set date showing the first activation and redirect if (! get_option('ms_was_installed_on')) { update_option('ms_was_installed_on', time()); } } /** * Hook MetaSlider into WordPress */ private function setup_filters() { add_filter('media_upload_tabs', array($this, 'custom_media_upload_tab_name'), 998); add_filter('media_view_strings', array($this, 'custom_media_uploader_tabs'), 5); add_action('media_buttons', array($this, 'insert_metaslider_button')); add_filter("plugin_row_meta", array($this, 'get_extra_meta_links'), 10, 4); add_action('admin_head', array($this, 'add_star_styles')); // html5 compatibility for stylesheets enqueued within add_filter('style_loader_tag', array($this, 'add_property_attribute_to_stylesheet_links'), 11, 2); } /** * Register MetaSlider widget */ public function register_metaslider_widget() { register_widget('MetaSlider_Widget'); } /** * Register ML Slider post type */ public function register_post_types() { $show_ui = false; $capability = apply_filters('metaslider_capability', self::DEFAULT_CAPABILITY_EDIT_SLIDES); if (is_admin() && current_user_can($capability) && (isset($_GET['show_ui']) || defined( "METASLIDER_DEBUG" ) && METASLIDER_DEBUG)) { $show_ui = true; } register_post_type( 'ml-slider', array( 'query_var' => false, 'rewrite' => false, 'public' => false, 'exclude_from_search' => true, 'publicly_queryable' => false, 'show_in_nav_menus' => false, 'show_ui' => $show_ui, 'labels' => array( 'name' => 'MetaSlider' ) ) ); register_post_type( 'ml-slide', array( 'query_var' => false, 'rewrite' => false, 'public' => false, 'exclude_from_search' => true, 'publicly_queryable' => false, 'show_in_nav_menus' => false, 'show_ui' => $show_ui, 'supports' => array('title', 'editor', 'author', 'thumbnail', 'excerpt'), 'labels' => array( 'name' => 'Meta Slides' ) ) ); } /** * Register taxonomy to store slider => slides relationship */ public function register_taxonomy() { $show_ui = false; $capability = apply_filters('metaslider_capability', self::DEFAULT_CAPABILITY_EDIT_SLIDES); if (is_admin() && current_user_can($capability) && (isset($_GET['show_ui']) || defined( "METASLIDER_DEBUG" ) && METASLIDER_DEBUG)) { $show_ui = true; } register_taxonomy( 'ml-slider', array('attachment', 'ml-slide'), array( 'hierarchical' => true, 'public' => false, 'query_var' => false, 'rewrite' => false, 'show_ui' => $show_ui, 'label' => "Slider" ) ); } /** * Register our slide types */ private function register_slide_types() { $image = new MetaImageSlide(); } /** * Add the menu pages */ public function register_admin_pages() { $title = metaslider_pro_is_active() ? 'MetaSlider Pro' : 'MetaSlider'; $this->admin->add_page($title, 'metaslider'); $this->admin->add_page(__('Settings & Help', 'ml-slider'), 'metaslider-settings', 'metaslider'); if (metaslider_user_sees_upgrade_page()) { $this->admin->add_page(__('Upgrade to Pro', 'ml-slider'), 'upgrade-metaslider', 'metaslider'); } } /** * Shortcode used to display slideshow * * @param string $atts attributes for short code * @return string HTML output of the shortcode */ public function register_shortcode($atts) { // TODO: remove extract. // phpcs:ignore WordPress.PHP.DontExtract.extract_extract extract( shortcode_atts(array( 'id' => false, 'title' => false, 'restrict_to' => false, 'theme' => null ), $atts, 'metaslider') ); // If no id and no title, exit here if (! $id && ! $title) { return false; } // If there is a title, get the id from the title if ($title) { global $wpdb; // Run a custom query because get_page_by_title() includes "trash" posts // Also, be sure just to get 1 post, in case they have multiple $id = $wpdb->get_var( $wpdb->prepare( " SELECT ID FROM $wpdb->posts WHERE post_title = %s AND post_type = 'ml-slider' AND post_status = 'publish' LIMIT 1 ", $title ) ); // If no posts were returned, $id will be NULL if (is_null($id) || ! (bool)$title) { return false; } } // handle [metaslider id=123 restrict_to=home] if ($restrict_to && ('home' === $restrict_to) && ! is_front_page()) { return false; } if ($restrict_to && ('home' !== $restrict_to) && ! is_page($restrict_to)) { return false; } // Attempt to get the ml-slider post object $slider = get_post($id); // check the slideshow is published and the ID is correct if (! $slider || 'publish' !== $slider->post_status || 'ml-slider' !== $slider->post_type) { return ""; } // Set up the slideshow and load the slideshow theme $this->set_slider($id, $atts); MetaSlider_Themes::get_instance()->load_theme($id, $theme); $this->slider->enqueue_scripts(); return $this->slider->render_public_slides(); } /** * Initialise translations */ public function load_plugin_textdomain() { // First, unload textdomain - Based on https://core.trac.wordpress.org/ticket/34213#comment:26 unload_textdomain('ml-slider'); // Call the core translations from plugins languages/ folder if (file_exists(METASLIDER_PATH . 'languages/' . 'ml-slider' . '-' . get_locale() . '.mo')) { load_textdomain( 'ml-slider', METASLIDER_PATH . 'languages/' . 'ml-slider' . '-' . get_locale() . '.mo' ); } if (function_exists('wp_set_script_translations')) { wp_set_script_translations( 'metaslider-admin-script', 'ml-slider', METASLIDER_PATH . 'languages' ); } } /** * Check our WordPress installation is compatible with MetaSlider * * @param int $slideshow_id The current slideshow ID */ public function do_system_check($slideshow_id) { $systemCheck = new MetaSliderSystemCheck($slideshow_id); $systemCheck->check(); } /** * Update the tab options in the media manager * * @param array $strings Array of settings for custom media tabs * @return array */ public function custom_media_uploader_tabs($strings) { // update strings if ((isset($_GET['page']) && $_GET['page'] == 'metaslider')) { $strings['insertMediaTitle'] = __("Image", "ml-slider"); $strings['insertIntoPost'] = __("Add to slideshow", "ml-slider"); // remove options $strings_to_remove = array( 'createVideoPlaylistTitle', 'createGalleryTitle', 'insertFromUrlTitle', 'createPlaylistTitle' ); foreach ($strings_to_remove as $string) { if (isset($strings[$string])) { unset($strings[$string]); } } } return $strings; } /** * Add extra tabs to the default wordpress Media Manager iframe * * @param array $tabs existing media manager tabs] * @return array */ public function custom_media_upload_tab_name($tabs) { $metaslider_tabs = array('post_feed', 'layer', 'youtube', 'vimeo'); // restrict our tab changes to the MetaSlider plugin page if ((isset($_GET['page']) && $_GET['page'] == 'metaslider') || (isset($_GET['tab']) && in_array( $_GET['tab'], $metaslider_tabs ))) { $newtabs = array(); if (function_exists('is_plugin_active') && ! is_plugin_active('ml-slider-pro/ml-slider-pro.php')) { $newtabs = array( 'post_feed' => __("Post Feed", "metaslider"), 'vimeo' => __("Vimeo", "metaslider"), 'youtube' => __("YouTube", "metaslider"), 'layer' => __("Layer Slide", "metaslider") ); } if (isset($tabs['nextgen'])) { unset($tabs['nextgen']); } if (is_array($tabs)) { return array_merge($tabs, $newtabs); } else { return $newtabs; } } return $tabs; } /** * Set the current slider * * @param int $id ID for slider * @param array $shortcode_settings Settings for slider */ public function set_slider($id, $shortcode_settings = array()) { $type = 'flex'; if (isset($shortcode_settings['type'])) { $type = $shortcode_settings['type']; } elseif ($settings = get_post_meta($id, 'ml-slider_settings', true)) { if (is_array($settings) && isset($settings['type'])) { $type = $settings['type']; } } if (! in_array($type, array('flex', 'coin', 'nivo', 'responsive'))) { $type = 'flex'; } $this->slider = $this->load_slider($type, $id, $shortcode_settings); } /** * Create a new slider based on the sliders type setting * * @param string $type Type of slide * @param int $id ID of slide * @param string $shortcode_settings Shortcode settings * @return array */ private function load_slider($type, $id, $shortcode_settings) { switch ($type) { case ('coin'): return new MetaCoinSlider($id, $shortcode_settings); case ('flex'): return new MetaFlexSlider($id, $shortcode_settings); case ('nivo'): return new MetaNivoSlider($id, $shortcode_settings); case ('responsive'): return new MetaResponsiveSlider($id, $shortcode_settings); default: return new MetaFlexSlider($id, $shortcode_settings); } } /** * Update the slider * * @return string a JSON string with success or failure (and errors) * @deprecated 3.13.0 use the API * */ public function update_slider() { return $this->api->save_slideshow(stripslashes_deep($_REQUEST)); } /** * Delete a slide via ajax. * * @return string Returns the status of the request */ public function ajax_undelete_slide() { if (! isset($_REQUEST['_wpnonce']) || ! wp_verify_nonce( sanitize_key($_REQUEST['_wpnonce']), 'metaslider_undelete_slide' )) { wp_send_json_error(array( 'message' => __('The security check failed. Please refresh the page and try again.', 'ml-slider') ), 401); } $capability = apply_filters('metaslider_capability', MetaSliderPlugin::DEFAULT_CAPABILITY_EDIT_SLIDES); if (! current_user_can($capability)) { wp_send_json_error( [ 'message' => __('Access denied', 'ml-slider') ], 403 ); } if (! isset($_POST['slide_id']) || ! isset($_POST['slider_id'])) { wp_send_json_error( [ 'message' => __('Bad request', 'ml-slider'), ], 400 ); } $result = $this->undelete_slide(absint($_POST['slide_id']), absint($_POST['slider_id'])); if (is_wp_error($result)) { wp_send_json_error(array( 'message' => $result->get_error_message() ), 409); } wp_send_json_success(array( 'message' => __('The slide was successfully restored', 'ml-slider'), ), 200); } /** * Undeletes a slide. * * @param int $slide_id The ID of the slide * @param int $slideshow_id The ID of the slideshow * @return mixed */ public function undelete_slide($slide_id, $slideshow_id) { if ('ml-slide' === get_post_type($slide_id)) { // Touch the slideshow post type to update the modified date wp_update_post(array('ID' => $slideshow_id)); return wp_update_post(array( 'ID' => $slide_id, 'post_status' => 'publish' ), new WP_Error( 'update_failed', __('The attempt to restore the slide failed.', 'ml-slider'), array('status' => 409) )); } /* * Legacy: This removes the relationship between the slider and slide * This restores the relationship between a slide and slider. * If using a newer version, this relationship is never lost on delete. * NB: this covers when a 'ml-slide' was an attachment with meta */ // Get the slider's term and apply it to the slide. $term = get_term_by('name', $slideshow_id, 'ml-slider'); return wp_set_object_terms($slide_id, $term->term_id, 'ml-slider'); } /** * Delete a slide via ajax. */ public function ajax_delete_slide() { if (! isset($_REQUEST['_wpnonce']) || ! wp_verify_nonce( sanitize_key($_REQUEST['_wpnonce']), 'metaslider_delete_slide' )) { wp_send_json_error(array( 'message' => __('The security check failed. Please refresh the page and try again.', 'ml-slider') ), 401); } $capability = apply_filters('metaslider_capability', MetaSliderPlugin::DEFAULT_CAPABILITY_EDIT_SLIDES); if (! current_user_can($capability)) { wp_send_json_error( [ 'message' => __('Access denied', 'ml-slider') ], 403 ); } if (! isset($_POST['slide_id']) || ! isset($_POST['slider_id'])) { wp_send_json_error( [ 'message' => __('Bad request', 'ml-slider'), ], 400 ); } $result = $this->delete_slide(absint($_POST['slide_id']), absint($_POST['slider_id'])); if (is_wp_error($result)) { wp_send_json_error(array( 'message' => $result->get_error_message() ), 409); } wp_send_json_success(array( 'message' => __('The slide was successfully trashed', 'ml-slider'), ), 200); } /** * Delete a slide by either trashing it or for * legacy reasons removing the taxonomy relationship. * * @param int $slide_id The ID of the slide * @param int $slideshow_id The ID of the slideshow * @return mixed Will return the terms or WP_Error */ public function delete_slide($slide_id, $slideshow_id) { if ('ml-slide' === get_post_type($slide_id)) { // Touch the slideshow post type to update the modified date wp_update_post(array('ID' => $slideshow_id)); return wp_update_post(array( 'ID' => $slide_id, 'post_status' => 'trash' ), new WP_Error('update_failed', 'The attempt to delete the slide failed.', array('status' => 409))); } /* * Legacy: This removes the relationship between the slider and slide * A slider with ID 216 might have a term_id of 7 * A slide with ID 217 could have a term_taxonomy_id of 7 * Multiple slides would have this term_taxonomy_id of 7 * NB: this covers when a 'ml-slide' was an attachment with meta */ // This returns the term_taxonomy_id (7 from example) $current_terms = wp_get_object_terms($slide_id, 'ml-slider', array('fields' => 'ids')); // This returns the term object, named after the slider ID // The $term->term_id would be 7 in the example above // It also includes the count of slides attached to the slider $term = get_term_by('name', $slideshow_id, 'ml-slider'); // I'm not sure why this is here. It seems this is only useful if // a slide was attached to multiple sliders. A slide should only // have one $current_terms (7 above) $new_terms = array(); foreach ($current_terms as $current_term) { if ($current_term != $term->term_id) { $new_terms[] = absint($current_term); } } // This only works becasue $new_terms is an empty array, // which deletes the relationship. I'm leaving the loop above // in case it's here for some legacy reason I'm unaware of. return wp_set_object_terms($slide_id, $new_terms, 'ml-slider'); } /** * Delete a slider (send it to trash) * * @return string - the json response from the API * @deprecated 3.11.0 use the API * */ public function delete_slider() { return $this->api->delete_slideshow($_REQUEST); } /** * Switch view * * @return null */ public function switch_view() { global $user_ID; if (! isset($_GET['view'])) { return; } $view = sanitize_key($_GET['view']); $allowed_views = array('tabs', 'dropdown'); if (! in_array($view, $allowed_views)) { return; } delete_user_meta($user_ID, "metaslider_view"); if ($view == 'dropdown') { add_user_meta($user_ID, "metaslider_view", "dropdown"); } wp_redirect(admin_url("admin.php?page=metaslider")); exit; } /** * Create a new slider */ public function create_slider() { check_admin_referer('metaslider_create_slider'); $capability = apply_filters('metaslider_capability', self::DEFAULT_CAPABILITY_EDIT_SLIDES); if (! current_user_can($capability)) { return; } $id = MetaSlider_Slideshows::create(); wp_redirect(admin_url("admin.php?page=metaslider&id={$id}")); exit; } /** * Find a single slider ID. For example, last edited, or first published. * * @param string $orderby field to order. * @param string $order direction (ASC or DESC). * @return int slider ID. */ private function find_slider($orderby, $order) { $args = array( 'force_no_custom_order' => true, 'post_type' => 'ml-slider', 'num_posts' => 1, 'post_status' => 'publish', 'suppress_filters' => 1, // wpml, ignore language filter 'orderby' => $orderby, 'order' => $order ); $the_query = new WP_Query($args); while ($the_query->have_posts()) { $the_query->the_post(); return $the_query->post->ID; } wp_reset_query(); return false; } /** * Get sliders. Returns a nicely formatted array of currently * published sliders. * * @param string $sort_key Specified sort key * @return array all published sliders */ public function all_meta_sliders($sort_key = 'date') { $sliders = array(); // list the tabs $args = array( 'post_type' => 'ml-slider', 'post_status' => 'publish', 'orderby' => $sort_key, 'suppress_filters' => 1, // wpml, ignore language filter 'order' => 'ASC', 'posts_per_page' => -1 ); $args = apply_filters('metaslider_all_meta_sliders_args', $args); // WP_Query causes issues with other plugins using admin_footer to insert scripts // use get_posts instead $all_sliders = get_posts($args); foreach ($all_sliders as $slideshow) { $active = $this->slider && ($this->slider->id == $slideshow->ID) ? true : false; $sliders[] = array( 'active' => $active, 'title' => $slideshow->post_title, 'id' => $slideshow->ID ); } return $sliders; } /** * Compare array values * * @param array $elem1 The first element to comapre * @param array $elem2 The second element to comapr * @return int */ private function compare_elems($elem1, $elem2) { if ($elem1['priority'] == $elem2['priority']) { return 0; } return $elem1['priority'] > $elem2['priority'] ? 1 : -1; } /** * Building setting rows * * @param array $settings array of fields to render * @return string */ public function build_settings_rows($settings) { // order the fields by priority uasort($settings, array($this, "compare_elems")); $output = ""; // loop through the array and build the settings HTML foreach ($settings as $id => $row) { $helptext = isset($row['helptext']) ? htmlentities2($row['helptext']) : ''; $after = ''; if (isset($row['after'])) { $after = '' . $row['after'] . ''; } $output .= '