PageRenderTime 159ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/wp-content/plugins/ml-slider/ml-slider.php

https://bitbucket.org/minhnguyen19942/batdongsan
PHP | 2068 lines | 1367 code | 339 blank | 362 comment | 170 complexity | 1bcc66715391183fff3e4696af0b37f7 MD5 | raw file
Possible License(s): GPL-3.0, MIT, GPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. // @codingStandardsIgnoreLine
  3. /*
  4. * MetaSlider. Slideshow plugin for WordPress.
  5. *
  6. * Plugin Name: MetaSlider
  7. * Plugin URI: https://www.metaslider.com
  8. * Description: Easy to use slideshow plugin. Create SEO optimised responsive slideshows with Nivo Slider, Flex Slider, Coin Slider and Responsive Slides.
  9. * Version: 3.7.2
  10. * Author: Team Updraft
  11. * Author URI: https://www.metaslider.com
  12. * License: GPL-2.0+
  13. * Copyright: 2017- Simba Hosting Ltd
  14. *
  15. * Text Domain: ml-slider
  16. * Domain Path: /languages
  17. */
  18. if ( ! defined( 'ABSPATH' ) ) {
  19. exit; // disable direct access
  20. }
  21. if ( ! class_exists( 'MetaSliderPlugin' ) ) :
  22. /**
  23. * Register the plugin.
  24. *
  25. * Display the administration panel, insert JavaScript etc.
  26. */
  27. class MetaSliderPlugin {
  28. /**
  29. * Meta slider version number
  30. *
  31. * @var string
  32. */
  33. public $version = '3.7.2';
  34. /**
  35. * The lowest tier price for upgrades
  36. *
  37. * @var string
  38. */
  39. public $pro_price = '39';
  40. /**
  41. * Specific SLider
  42. *
  43. * @var MetaSlider
  44. */
  45. public $slider = null;
  46. /**
  47. * Init
  48. */
  49. public static function init() {
  50. $metaslider = new self();
  51. }
  52. /**
  53. * Constructor
  54. */
  55. public function __construct() {
  56. $this->define_constants();
  57. $this->includes();
  58. $this->setup_actions();
  59. $this->setup_filters();
  60. $this->setup_shortcode();
  61. $this->register_slide_types();
  62. $this->admin = new MetaSlider_Admin_Pages($this);
  63. }
  64. /**
  65. * Define MetaSlider constants
  66. */
  67. private function define_constants() {
  68. define('METASLIDER_VERSION', $this->version);
  69. define('METASLIDER_BASE_URL', trailingslashit(plugins_url('ml-slider')));
  70. define('METASLIDER_ASSETS_URL', trailingslashit(METASLIDER_BASE_URL . 'assets'));
  71. define('METASLIDER_ADMIN_URL', trailingslashit(METASLIDER_BASE_URL . 'admin'));
  72. define('METASLIDER_PATH', plugin_dir_path(__FILE__));
  73. define('METASLIDER_PRO_PRICE', $this->pro_price);
  74. }
  75. /**
  76. * All MetaSlider classes
  77. */
  78. private function plugin_classes() {
  79. return array(
  80. 'metaslider' => METASLIDER_PATH . 'inc/slider/metaslider.class.php',
  81. 'metacoinslider' => METASLIDER_PATH . 'inc/slider/metaslider.coin.class.php',
  82. 'metaflexslider' => METASLIDER_PATH . 'inc/slider/metaslider.flex.class.php',
  83. 'metanivoslider' => METASLIDER_PATH . 'inc/slider/metaslider.nivo.class.php',
  84. 'metaresponsiveslider' => METASLIDER_PATH . 'inc/slider/metaslider.responsive.class.php',
  85. 'metaslide' => METASLIDER_PATH . 'inc/slide/metaslide.class.php',
  86. 'metaimageslide' => METASLIDER_PATH . 'inc/slide/metaslide.image.class.php',
  87. 'metasliderimagehelper' => METASLIDER_PATH . 'inc/metaslider.imagehelper.class.php',
  88. 'metaslidersystemcheck' => METASLIDER_PATH . 'inc/metaslider.systemcheck.class.php',
  89. 'metaslider_widget' => METASLIDER_PATH . 'inc/metaslider.widget.class.php',
  90. 'simple_html_dom' => METASLIDER_PATH . 'inc/simple_html_dom.php',
  91. 'metaslider_notices' => METASLIDER_PATH . 'admin/Notices.php',
  92. 'metaslider_admin_pages' => METASLIDER_PATH . 'admin/Pages.php',
  93. 'metaslider_tour' => METASLIDER_PATH . 'admin/Tour.php'
  94. );
  95. }
  96. /**
  97. * Load required classes
  98. */
  99. private function includes() {
  100. require_once(METASLIDER_PATH . 'admin/lib/helpers.php');
  101. $autoload_is_disabled = defined( 'METASLIDER_AUTOLOAD_CLASSES' ) && METASLIDER_AUTOLOAD_CLASSES === false;
  102. if ( function_exists( "spl_autoload_register" ) && ! ( $autoload_is_disabled ) ) {
  103. // >= PHP 5.2 - Use auto loading
  104. if ( function_exists( "__autoload" ) ) {
  105. spl_autoload_register( "__autoload" );
  106. }
  107. spl_autoload_register( array( $this, 'autoload' ) );
  108. } else {
  109. // < PHP5.2 - Require all classes
  110. foreach ( $this->plugin_classes() as $id => $path ) {
  111. if ( is_readable( $path ) && ! class_exists( $id ) ) {
  112. require_once( $path );
  113. }
  114. }
  115. }
  116. }
  117. /**
  118. * Autoload MetaSlider classes to reduce memory consumption
  119. *
  120. * @param string $class Class name
  121. */
  122. public function autoload( $class ) {
  123. $classes = $this->plugin_classes();
  124. $class_name = strtolower( $class );
  125. if ( isset( $classes[$class_name] ) && is_readable( $classes[$class_name] ) ) {
  126. require_once( $classes[$class_name] );
  127. }
  128. }
  129. /**
  130. * Register the [metaslider] shortcode.
  131. */
  132. private function setup_shortcode() {
  133. add_shortcode( 'metaslider', array( $this, 'register_shortcode' ) );
  134. add_shortcode( 'ml-slider', array( $this, 'register_shortcode' ) ); // backwards compatibility
  135. }
  136. /**
  137. * Hook MetaSlider into WordPress
  138. */
  139. private function setup_actions() {
  140. add_action('admin_menu', array($this, 'register_admin_pages'), 9553);
  141. add_action('init', array($this, 'register_post_types'));
  142. add_action('init', array($this, 'register_taxonomy'));
  143. add_action('init', array($this, 'load_plugin_textdomain'));
  144. add_action('admin_footer', array($this, 'admin_footer'), 11);
  145. add_action('widgets_init', array($this, 'register_metaslider_widget'));
  146. add_action('admin_post_metaslider_preview', array($this, 'do_preview'));
  147. add_action('admin_post_metaslider_switch_view', array($this, 'switch_view'));
  148. add_action('admin_post_metaslider_delete_slide', array($this, 'delete_slide'));
  149. add_action('admin_post_metaslider_delete_slider', array($this, 'delete_slider'));
  150. add_action('admin_post_metaslider_create_slider', array($this, 'create_slider'));
  151. add_action('admin_post_metaslider_update_slider', array($this, 'update_slider'));
  152. add_action('media_upload_vimeo', array($this, 'upgrade_to_pro_tab'));
  153. add_action('media_upload_youtube', array($this, 'upgrade_to_pro_tab'));
  154. add_action('media_upload_post_feed', array($this, 'upgrade_to_pro_tab'));
  155. add_action('media_upload_layer', array($this, 'upgrade_to_pro_tab'));
  156. // TODO: Refactor to Slide class object
  157. add_action('wp_ajax_delete_slide', array($this, 'ajax_delete_slide'));
  158. add_action('wp_ajax_undelete_slide', array($this, 'ajax_undelete_slide'));
  159. // TODO: Make this work
  160. // register_activation_hook(plugin_basename(__FILE__), array($this, 'after_activation'));
  161. }
  162. /**
  163. * Hook MetaSlider into WordPress
  164. */
  165. private function setup_filters() {
  166. add_filter('media_upload_tabs', array($this, 'custom_media_upload_tab_name'), 998);
  167. add_filter('media_view_strings', array($this, 'custom_media_uploader_tabs'), 5);
  168. add_filter('media_buttons_context', array($this, 'insert_metaslider_button'));
  169. add_filter("plugin_row_meta", array($this, 'get_extra_meta_links'), 10, 4);
  170. add_action('admin_head', array($this, 'add_star_styles'));
  171. add_action('admin_head', array($this, 'add_tour_nonce_to_activation_page'));
  172. // html5 compatibility for stylesheets enqueued within <body>
  173. add_filter('style_loader_tag', array($this, 'add_property_attribute_to_stylesheet_links'), 11, 2);
  174. }
  175. /**
  176. * Register MetaSlider widget
  177. */
  178. public function register_metaslider_widget() {
  179. register_widget('MetaSlider_Widget');
  180. }
  181. /**
  182. * Register ML Slider post type
  183. */
  184. public function register_post_types() {
  185. $show_ui = false;
  186. $capability = apply_filters( 'metaslider_capability', 'edit_others_posts' );
  187. if ( is_admin() && current_user_can( $capability ) && ( isset($_GET['show_ui']) || defined("METASLIDER_DEBUG") && METASLIDER_DEBUG ) ) {
  188. $show_ui = true;
  189. }
  190. register_post_type( 'ml-slider', array(
  191. 'query_var' => false,
  192. 'rewrite' => false,
  193. 'public' => false,
  194. 'exclude_from_search' => true,
  195. 'publicly_queryable' => false,
  196. 'show_in_nav_menus' => false,
  197. 'show_ui' => $show_ui,
  198. 'labels' => array(
  199. 'name' => 'MetaSlider'
  200. )
  201. )
  202. );
  203. register_post_type( 'ml-slide', array(
  204. 'query_var' => false,
  205. 'rewrite' => false,
  206. 'public' => false,
  207. 'exclude_from_search' => true,
  208. 'publicly_queryable' => false,
  209. 'show_in_nav_menus' => false,
  210. 'show_ui' => $show_ui,
  211. 'supports' => array( 'title', 'editor', 'author', 'thumbnail', 'excerpt'),
  212. 'labels' => array(
  213. 'name' => 'Meta Slides'
  214. )
  215. )
  216. );
  217. }
  218. /**
  219. * Register taxonomy to store slider => slides relationship
  220. */
  221. public function register_taxonomy() {
  222. $show_ui = false;
  223. $capability = apply_filters( 'metaslider_capability', 'edit_others_posts' );
  224. if (is_admin() && current_user_can( $capability ) && ( isset($_GET['show_ui']) || defined("METASLIDER_DEBUG") && METASLIDER_DEBUG ) ) {
  225. $show_ui = true;
  226. }
  227. register_taxonomy( 'ml-slider', array('attachment', 'ml-slide'), array(
  228. 'hierarchical' => true,
  229. 'public' => false,
  230. 'query_var' => false,
  231. 'rewrite' => false,
  232. 'show_ui' => $show_ui,
  233. 'label' => "Slider"
  234. )
  235. );
  236. }
  237. /**
  238. * Register our slide types
  239. */
  240. private function register_slide_types() {
  241. $image = new MetaImageSlide();
  242. }
  243. /**
  244. * Add the menu pages
  245. */
  246. public function register_admin_pages() {
  247. if (metaslider_pro_is_active()) {
  248. $this->admin->add_page('MetaSlider Pro', 'metaslider');
  249. } else {
  250. $this->admin->add_page('MetaSlider');
  251. }
  252. if (metaslider_user_sees_upgrade_page()) {
  253. $this->admin->add_page(__('Add-ons', 'ml-slider'), 'upgrade', 'metaslider');
  254. }
  255. }
  256. /**
  257. * Shortcode used to display slideshow
  258. *
  259. * @param string $atts attributes for short code
  260. * @return string HTML output of the shortcode
  261. */
  262. public function register_shortcode( $atts ) {
  263. extract( shortcode_atts( array(
  264. 'id' => false,
  265. 'restrict_to' => false
  266. ), $atts, 'metaslider' ) );
  267. if ( ! $id ) {
  268. return false;
  269. }
  270. // handle [metaslider id=123 restrict_to=home]
  271. if ($restrict_to && $restrict_to == 'home' && ! is_front_page()) {
  272. return;
  273. }
  274. if ($restrict_to && $restrict_to != 'home' && ! is_page( $restrict_to ) ) {
  275. return;
  276. }
  277. // we have an ID to work with
  278. $slider = get_post( $id );
  279. // check the slider is published and the ID is correct
  280. if ( ! $slider || $slider->post_status != 'publish' || $slider->post_type != 'ml-slider' ) {
  281. return "<!-- MetaSlider {$atts['id']} not found -->";
  282. }
  283. // lets go
  284. $this->set_slider( $id, $atts );
  285. $this->slider->enqueue_scripts();
  286. return $this->slider->render_public_slides();
  287. }
  288. /**
  289. * Set first activation option to database
  290. */
  291. public function after_activation() {
  292. // Set date showing the first activation and redirect
  293. if (!get_option('ms_was_installed_on')) {
  294. update_option('ms_was_installed_on', time());
  295. }
  296. }
  297. /**
  298. * Initialise translations
  299. */
  300. public function load_plugin_textdomain() {
  301. load_plugin_textdomain( 'ml-slider', false, dirname( plugin_basename( __FILE__ ) ) . '/languages/' );
  302. }
  303. /**
  304. * Outputs a blank page containing a slideshow preview (for use in the 'Preview' iFrame)
  305. */
  306. public function do_preview() {
  307. remove_action('wp_footer', 'wp_admin_bar_render', 1000);
  308. if ( isset( $_GET['slider_id'] ) && absint( $_GET['slider_id'] ) > 0 ) {
  309. $id = absint( $_GET['slider_id'] );
  310. ?>
  311. <!DOCTYPE html>
  312. <html>
  313. <head>
  314. <style type='text/css'>
  315. body, html {
  316. overflow: hidden;
  317. margin: 0;
  318. padding: 0;
  319. }
  320. </style>
  321. <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
  322. <meta http-equiv="Pragma" content="no-cache" />
  323. <meta http-equiv="Expires" content="0" />
  324. </head>
  325. <body>
  326. <?php echo do_shortcode("[metaslider id={$id}]"); ?>
  327. <?php wp_footer(); ?>
  328. </body>
  329. </html>
  330. <?php
  331. }
  332. die();
  333. }
  334. /**
  335. * Check our WordPress installation is compatible with MetaSlider
  336. */
  337. public function do_system_check() {
  338. $systemCheck = new MetaSliderSystemCheck();
  339. $systemCheck->check();
  340. }
  341. /**
  342. * Update the tab options in the media manager
  343. *
  344. * @param array $strings Array of settings for custom media tabs
  345. * @return array
  346. */
  347. public function custom_media_uploader_tabs( $strings ) {
  348. // update strings
  349. if ( ( isset( $_GET['page'] ) && $_GET['page'] == 'metaslider' ) ) {
  350. $strings['insertMediaTitle'] = __( "Image", "ml-slider" );
  351. $strings['insertIntoPost'] = __( "Add to slideshow", "ml-slider" );
  352. // remove options
  353. $strings_to_remove = array(
  354. 'createVideoPlaylistTitle',
  355. 'createGalleryTitle',
  356. 'insertFromUrlTitle',
  357. 'createPlaylistTitle'
  358. );
  359. foreach ($strings_to_remove as $string) {
  360. if (isset($strings[$string])) {
  361. unset($strings[$string]);
  362. }
  363. }
  364. }
  365. return $strings;
  366. }
  367. /**
  368. * Add extra tabs to the default wordpress Media Manager iframe
  369. *
  370. * @param array $tabs existing media manager tabs]
  371. * @return array
  372. */
  373. public function custom_media_upload_tab_name( $tabs ) {
  374. $metaslider_tabs = array( 'post_feed', 'layer', 'youtube', 'vimeo' );
  375. // restrict our tab changes to the MetaSlider plugin page
  376. if ( ( isset( $_GET['page'] ) && $_GET['page'] == 'metaslider' ) || ( isset( $_GET['tab'] ) && in_array( $_GET['tab'], $metaslider_tabs ) ) ) {
  377. $newtabs = array();
  378. if ( function_exists( 'is_plugin_active' ) && ! is_plugin_active( 'ml-slider-pro/ml-slider-pro.php' ) ) {
  379. $newtabs = array(
  380. 'post_feed' => __( "Post Feed", "metaslider" ),
  381. 'vimeo' => __( "Vimeo", "metaslider" ),
  382. 'youtube' => __( "YouTube", "metaslider" ),
  383. 'layer' => __( "Layer Slide", "metaslider" )
  384. );
  385. }
  386. if ( isset( $tabs['nextgen'] ) )
  387. unset( $tabs['nextgen'] );
  388. if ( is_array( $tabs ) ) {
  389. return array_merge( $tabs, $newtabs );
  390. } else {
  391. return $newtabs;
  392. }
  393. }
  394. return $tabs;
  395. }
  396. /**
  397. * Set the current slider
  398. *
  399. * @param int $id ID for slider
  400. * @param array $shortcode_settings Settings for slider
  401. */
  402. public function set_slider( $id, $shortcode_settings = array() ) {
  403. $type = 'flex';
  404. if ( isset( $shortcode_settings['type'] ) ) {
  405. $type = $shortcode_settings['type'];
  406. } else if ( $settings = get_post_meta( $id, 'ml-slider_settings', true ) ) {
  407. if ( is_array( $settings ) && isset( $settings['type'] ) ) {
  408. $type = $settings['type'];
  409. }
  410. }
  411. if ( ! in_array( $type, array( 'flex', 'coin', 'nivo', 'responsive' ) ) ) {
  412. $type = 'flex';
  413. }
  414. $this->slider = $this->load_slider( $type, $id, $shortcode_settings );
  415. }
  416. /**
  417. * Create a new slider based on the sliders type setting
  418. *
  419. * @param string $type Type of slide
  420. * @param int $id ID of slide
  421. * @param string $shortcode_settings Shortcode settings
  422. * @return array
  423. */
  424. private function load_slider( $type, $id, $shortcode_settings ) {
  425. switch ( $type ) {
  426. case( 'coin' ):
  427. return new MetaCoinSlider( $id, $shortcode_settings );
  428. case( 'flex' ):
  429. return new MetaFlexSlider( $id, $shortcode_settings );
  430. case( 'nivo' ):
  431. return new MetaNivoSlider( $id, $shortcode_settings );
  432. case( 'responsive' ):
  433. return new MetaResponsiveSlider( $id, $shortcode_settings );
  434. default:
  435. return new MetaFlexSlider( $id, $shortcode_settings );
  436. }
  437. }
  438. /**
  439. * Update the slider
  440. *
  441. * @return null
  442. */
  443. public function update_slider() {
  444. check_admin_referer( "metaslider_update_slider" );
  445. $capability = apply_filters( 'metaslider_capability', 'edit_others_posts' );
  446. if ( ! current_user_can( $capability ) ) {
  447. return;
  448. }
  449. $slider_id = absint( $_POST['slider_id'] );
  450. if ( ! $slider_id ) {
  451. return;
  452. }
  453. // update settings
  454. if ( isset( $_POST['settings'] ) ) {
  455. $new_settings = $_POST['settings'];
  456. $old_settings = get_post_meta( $slider_id, 'ml-slider_settings', true );
  457. // convert submitted checkbox values from 'on' or 'off' to boolean values
  458. $checkboxes = apply_filters( "metaslider_checkbox_settings", array( 'noConflict', 'fullWidth', 'hoverPause', 'links', 'reverse', 'random', 'printCss', 'printJs', 'smoothHeight', 'center', 'carouselMode', 'autoPlay' ) );
  459. foreach ( $checkboxes as $checkbox ) {
  460. if ( isset( $new_settings[$checkbox] ) && $new_settings[$checkbox] == 'on' ) {
  461. $new_settings[$checkbox] = "true";
  462. } else {
  463. $new_settings[$checkbox] = "false";
  464. }
  465. }
  466. $settings = array_merge( (array)$old_settings, $new_settings );
  467. // update the slider settings
  468. update_post_meta( $slider_id, 'ml-slider_settings', $settings );
  469. }
  470. // update slideshow title
  471. if ( isset( $_POST['title'] ) ) {
  472. $slide = array(
  473. 'ID' => $slider_id,
  474. 'post_title' => esc_html( $_POST['title'] )
  475. );
  476. wp_update_post( $slide );
  477. }
  478. // update individual slides
  479. if ( isset( $_POST['attachment'] ) ) {
  480. foreach ( $_POST['attachment'] as $slide_id => $fields ) {
  481. do_action( "metaslider_save_{$fields['type']}_slide", $slide_id, $slider_id, $fields );
  482. }
  483. }
  484. }
  485. /**
  486. * Delete a slide via ajax.
  487. *
  488. * @return string Returns the status of the request
  489. */
  490. public function ajax_undelete_slide() {
  491. if (!wp_verify_nonce($_REQUEST['_wpnonce'], 'metaslider_undelete_slide')) {
  492. return wp_send_json_error(array(
  493. 'message' => __('The security check failed. Please refresh the page and try again.', 'ml-slider')
  494. ), 401);
  495. }
  496. $result = $this->undelete_slide(absint($_POST['slide_id']), absint($_POST['slider_id']));
  497. if (is_wp_error($result)) {
  498. return wp_send_json_error(array(
  499. 'message' => $result->get_error_message()
  500. ), 409);
  501. }
  502. return wp_send_json_success(array(
  503. 'message' => __('The slide was successfully restored', 'ml-slider'),
  504. ), 200);
  505. }
  506. /**
  507. * Undeletes a slide.
  508. *
  509. * @param int $slide_id The ID of the slide
  510. * @param int $slider_id The ID of the slider (for legacy purposes)
  511. * @return mixed
  512. */
  513. public function undelete_slide($slide_id, $slider_id) {
  514. if ('ml-slide' === get_post_type($slide_id)) {
  515. return wp_update_post(array(
  516. 'ID' => $slide_id,
  517. 'post_status' => 'publish'
  518. ), new WP_Error('update_failed', __('The attempt to restore the slide failed.', 'ml-slider'), array('status' => 409)));
  519. }
  520. /*
  521. * Legacy: This removes the relationship between the slider and slide
  522. * This restores the relationship between a slide and slider.
  523. * If using a newer version, this relationship is never lost on delete.
  524. */
  525. // Get the slider's term and apply it to the slide.
  526. $term = get_term_by('name', $slider_id, 'ml-slider');
  527. return wp_set_object_terms($slide_id, $term->term_id, 'ml-slider');
  528. }
  529. /**
  530. * Delete a slide via ajax.
  531. */
  532. public function ajax_delete_slide() {
  533. if (!wp_verify_nonce($_REQUEST['_wpnonce'], 'metaslider_delete_slide')) {
  534. return wp_send_json_error(array(
  535. 'message' => __('The security check failed. Please refresh the page and try again.', 'ml-slider')
  536. ), 401);
  537. }
  538. $result = $this->delete_slide(absint($_POST['slide_id']), absint($_POST['slider_id']));
  539. if (is_wp_error($result)) {
  540. return wp_send_json_error(array(
  541. 'message' => $result->get_error_message()
  542. ), 409);
  543. }
  544. return wp_send_json_success(array(
  545. 'message' => __('The slide was successfully trashed', 'ml-slider'),
  546. ), 200);
  547. }
  548. /**
  549. * Delete a slide by either trashing it or for
  550. * legacy reasons removing the taxonomy relationship.
  551. *
  552. * @param int $slide_id The ID of the slide
  553. * @param int $slider_id The ID of the slider
  554. * @return mixed Will return the terms or WP_Error
  555. */
  556. public function delete_slide($slide_id, $slider_id) {
  557. if ('ml-slide' === get_post_type($slide_id)) {
  558. return wp_update_post(array(
  559. 'ID' => $slide_id,
  560. 'post_status' => 'trash'
  561. ), new WP_Error('update_failed', 'The attempt to delete the slide failed.', array('status' => 409)));
  562. }
  563. /*
  564. * Legacy: This removes the relationship between the slider and slide
  565. * A slider with ID 216 might have a term_id of 7
  566. * A slide with ID 217 could have a term_taxonomy_id of 7
  567. * Multiple slides would have this term_taxonomy_id of 7
  568. */
  569. // This returns the term_taxonomy_id (7 from example)
  570. $current_terms = wp_get_object_terms($slide_id, 'ml-slider', array('fields' => 'ids'));
  571. // This returns the term object, named after the slider ID
  572. // The $term->term_id would be 7 in the example above
  573. // It also includes the count of slides attached to the slider
  574. $term = get_term_by('name', $slider_id, 'ml-slider');
  575. // I'm not sure why this is here. It seems this is only useful if
  576. // a slide was attached to multiple sliders. A slide should only
  577. // have one $current_terms (7 above)
  578. $new_terms = array();
  579. foreach ($current_terms as $current_term) {
  580. if ($current_term != $term->term_id) {
  581. $new_terms[] = absint($current_term);
  582. }
  583. }
  584. // This only works becasue $new_terms is an empty array,
  585. // which deletes the relationship. I'm leaving the loop above
  586. // in case it's here for some legacy reason I'm unaware of.
  587. return wp_set_object_terms($slide_id, $new_terms, 'ml-slider');
  588. }
  589. /**
  590. * Delete a slider (send it to trash)
  591. */
  592. public function delete_slider() {
  593. // check nonce
  594. check_admin_referer( "metaslider_delete_slider" );
  595. $capability = apply_filters( 'metaslider_capability', 'edit_others_posts' );
  596. if ( ! current_user_can( $capability ) ) {
  597. return;
  598. }
  599. $slider_id = absint( $_GET['slider_id'] );
  600. if ( get_post_type( $slider_id ) != 'ml-slider' ) {
  601. wp_redirect( admin_url( "admin.php?page=metaslider" ) );
  602. wp_die();
  603. }
  604. // send the post to trash
  605. $id = wp_update_post( array(
  606. 'ID' => $slider_id,
  607. 'post_status' => 'trash'
  608. )
  609. );
  610. $this->delete_all_slides_from_slider($slider_id);
  611. $slider_id = $this->find_slider( 'modified', 'DESC' );
  612. wp_redirect( admin_url( "admin.php?page=metaslider&id={$slider_id}" ) );
  613. }
  614. /**
  615. * Trashes all new format slides for a given slideshow ID
  616. *
  617. * @param int $slider_id Specified Slider ID
  618. * @return int - The ID of the slideshow from which the slides were removed
  619. */
  620. private function delete_all_slides_from_slider($slider_id) {
  621. // find slides and trash them
  622. $args = array(
  623. 'force_no_custom_order' => true,
  624. 'orderby' => 'menu_order',
  625. 'order' => 'ASC',
  626. 'post_type' => array('ml-slide'),
  627. 'post_status' => array('publish'),
  628. 'lang' => '', // polylang, ingore language filter
  629. 'suppress_filters' => 1, // wpml, ignore language filter
  630. 'posts_per_page' => -1,
  631. 'tax_query' => array(
  632. array(
  633. 'taxonomy' => 'ml-slider',
  634. 'field' => 'slug',
  635. 'terms' => $slider_id
  636. )
  637. )
  638. );
  639. $query = new WP_Query( $args );
  640. while ( $query->have_posts() ) {
  641. $query->next_post();
  642. $id = $query->post->ID;
  643. $id = wp_update_post( array(
  644. 'ID' => $id,
  645. 'post_status' => 'trash'
  646. )
  647. );
  648. }
  649. return $slider_id;
  650. }
  651. /**
  652. * Switch view
  653. *
  654. * @return null
  655. */
  656. public function switch_view() {
  657. global $user_ID;
  658. $view = $_GET['view'];
  659. $allowed_views = array('tabs', 'dropdown');
  660. if ( ! in_array( $view, $allowed_views ) ) {
  661. return;
  662. }
  663. delete_user_meta( $user_ID, "metaslider_view" );
  664. if ( $view == 'dropdown' ) {
  665. add_user_meta( $user_ID, "metaslider_view", "dropdown");
  666. }
  667. wp_redirect( admin_url( "admin.php?page=metaslider" ) );
  668. }
  669. /**
  670. * Create a new slider
  671. */
  672. public function create_slider() {
  673. // check nonce
  674. check_admin_referer( "metaslider_create_slider" );
  675. $capability = apply_filters( 'metaslider_capability', 'edit_others_posts' );
  676. if ( ! current_user_can( $capability ) ) {
  677. return;
  678. }
  679. $defaults = array();
  680. // if possible, take a copy of the last edited slider settings in place of default settings
  681. if ( $last_modified = $this->find_slider( 'modified', 'DESC' ) ) {
  682. $defaults = get_post_meta( $last_modified, 'ml-slider_settings', true );
  683. }
  684. // insert the post
  685. $id = wp_insert_post( array(
  686. 'post_title' => __("New Slideshow", "ml-slider"),
  687. 'post_status' => 'publish',
  688. 'post_type' => 'ml-slider'
  689. )
  690. );
  691. // use the default settings if we can't find anything more suitable.
  692. if ( empty( $defaults ) ) {
  693. $slider = new MetaSlider( $id, array() );
  694. $defaults = $slider->get_default_parameters();
  695. }
  696. // insert the post meta
  697. add_post_meta( $id, 'ml-slider_settings', $defaults, true );
  698. // create the taxonomy term, the term is the ID of the slider itself
  699. wp_insert_term( $id, 'ml-slider' );
  700. wp_redirect( admin_url( "admin.php?page=metaslider&id={$id}" ) );
  701. }
  702. /**
  703. * Find a single slider ID. For example, last edited, or first published.
  704. *
  705. * @param string $orderby field to order.
  706. * @param string $order direction (ASC or DESC).
  707. * @return int slider ID.
  708. */
  709. private function find_slider( $orderby, $order ) {
  710. $args = array(
  711. 'force_no_custom_order' => true,
  712. 'post_type' => 'ml-slider',
  713. 'num_posts' => 1,
  714. 'post_status' => 'publish',
  715. 'suppress_filters' => 1, // wpml, ignore language filter
  716. 'orderby' => $orderby,
  717. 'order' => $order
  718. );
  719. $the_query = new WP_Query( $args );
  720. while ( $the_query->have_posts() ) {
  721. $the_query->the_post();
  722. return $the_query->post->ID;
  723. }
  724. wp_reset_query();
  725. return false;
  726. }
  727. /**
  728. * Get sliders. Returns a nicely formatted array of currently
  729. * published sliders.
  730. *
  731. * @param string $sort_key Specified sort key
  732. * @return array all published sliders
  733. */
  734. public function all_meta_sliders( $sort_key = 'date' ) {
  735. $sliders = array();
  736. // list the tabs
  737. $args = array(
  738. 'post_type' => 'ml-slider',
  739. 'post_status' => 'publish',
  740. 'orderby' => $sort_key,
  741. 'suppress_filters' => 1, // wpml, ignore language filter
  742. 'order' => 'ASC',
  743. 'posts_per_page' => -1
  744. );
  745. $args = apply_filters( 'metaslider_all_meta_sliders_args', $args );
  746. // WP_Query causes issues with other plugins using admin_footer to insert scripts
  747. // use get_posts instead
  748. $all_sliders = get_posts( $args );
  749. foreach( $all_sliders as $slideshow ) {
  750. $active = $this->slider && ( $this->slider->id == $slideshow->ID ) ? true : false;
  751. $sliders[] = array(
  752. 'active' => $active,
  753. 'title' => $slideshow->post_title,
  754. 'id' => $slideshow->ID
  755. );
  756. }
  757. return $sliders;
  758. }
  759. /**
  760. * Compare array values
  761. *
  762. * @param array $elem1 The first element to comapre
  763. * @param array $elem2 The second element to comapr
  764. * @return bool
  765. */
  766. private function compare_elems( $elem1, $elem2 ) {
  767. return $elem1['priority'] > $elem2['priority'];
  768. }
  769. /**
  770. * Building setting rows
  771. *
  772. * @param array $aFields array of field to render
  773. * @return string
  774. */
  775. public function build_settings_rows( $aFields ) {
  776. // order the fields by priority
  777. uasort( $aFields, array( $this, "compare_elems" ) );
  778. $return = "";
  779. // loop through the array and build the settings HTML
  780. foreach ( $aFields as $id => $row ) {
  781. // checkbox input type
  782. if ( $row['type'] == 'checkbox' ) {
  783. $return .= "<tr><td class='tipsy-tooltip' title=\"{$row['helptext']}\">{$row['label']}</td><td><input class='option {$row['class']} {$id}' type='checkbox' name='settings[{$id}]' {$row['checked']} />";
  784. if ( isset( $row['after'] ) ) {
  785. $return .= "<span class='after'>{$row['after']}</span>";
  786. }
  787. $return .= "</td></tr>";
  788. }
  789. // navigation row
  790. if ( $row['type'] == 'navigation' ) {
  791. $navigation_row = "<tr class='{$row['type']}'><td class='tipsy-tooltip' title=\"{$row['helptext']}\">{$row['label']}</td><td><ul>";
  792. foreach ( $row['options'] as $k => $v ) {
  793. $tease = isset($v['addon_required']) ? 'disabled' : '';
  794. if ( $row['value'] === true && $k === 'true' ) {
  795. $checked = checked( true, true, false );
  796. } else if ( $row['value'] === false && $k === 'false' ) {
  797. $checked = checked( true, true, false );
  798. } else {
  799. $checked = checked( $k, $row['value'], false );
  800. }
  801. $disabled = $k == 'thumbnails' ? 'disabled' : '';
  802. $navigation_row .= "<li><label class='{$tease}'><input {$tease} type='radio' name='settings[{$id}]' value='{$k}' {$checked} {$disabled}/>{$v['label']}</label>";
  803. if (isset($v['addon_required']) && $v['addon_required']) {
  804. $navigation_row .= sprintf(" <a target='_blank' class='get-addon' href='%s' title='%s'>%s</a>", metaslider_get_upgrade_link(), __('Get the add-on pack today!', 'ml-slider'), __('Learn More', 'ml-slider'));
  805. }
  806. $navigation_row .= "</li>";
  807. }
  808. $navigation_row .= "</ul></td></tr>";
  809. $return .= apply_filters( 'metaslider_navigation_options', $navigation_row, $this->slider );
  810. }
  811. // navigation row
  812. if ( $row['type'] == 'radio' ) {
  813. $navigation_row = "<tr class='{$row['type']}'><td class='tipsy-tooltip' title=\"{$row['helptext']}\">{$row['label']}</td><td><ul>";
  814. foreach ( $row['options'] as $k => $v ) {
  815. $checked = checked( $k, $row['value'], false );
  816. $class = isset( $v['class'] ) ? $v['class'] : "";
  817. $navigation_row .= "<li><label><input type='radio' name='settings[{$id}]' value='{$k}' {$checked} class='radio {$class}'/>{$v['label']}</label></li>";
  818. }
  819. $navigation_row .= "</ul></td></tr>";
  820. $return .= apply_filters( 'metaslider_navigation_options', $navigation_row, $this->slider );
  821. }
  822. // header/divider row
  823. if ( $row['type'] == 'divider' ) {
  824. $return .= "<tr class='{$row['type']}'><td colspan='2' class='divider'><b>{$row['value']}</b></td></tr>";
  825. }
  826. // slideshow select row
  827. if ( $row['type'] == 'slider-lib' ) {
  828. $return .= "<tr class='{$row['type']}'><td colspan='2' class='slider-lib-row'>";
  829. foreach ( $row['options'] as $k => $v ) {
  830. $checked = checked( $k, $row['value'], false );
  831. $return .= "<input class='select-slider' id='{$k}' rel='{$k}' type='radio' name='settings[type]' value='{$k}' {$checked} />
  832. <label tabindex='0' for='{$k}'>{$v['label']}</label>";
  833. }
  834. $return .= "</td></tr>";
  835. }
  836. // number input type
  837. if ( $row['type'] == 'number' ) {
  838. $return .= "<tr class='{$row['type']}'><td class='tipsy-tooltip' title=\"{$row['helptext']}\">{$row['label']}</td><td><input class='option {$row['class']} {$id}' type='number' min='{$row['min']}' max='{$row['max']}' step='{$row['step']}' name='settings[{$id}]' value='" . absint( $row['value'] ) . "' /><span class='after'>{$row['after']}</span></td></tr>";
  839. }
  840. // select drop down
  841. if ( $row['type'] == 'select' ) {
  842. $return .= "<tr class='{$row['type']}'><td class='tipsy-tooltip' title=\"{$row['helptext']}\">{$row['label']}</td><td><select class='option {$row['class']} {$id}' name='settings[{$id}]'>";
  843. foreach ( $row['options'] as $k => $v ) {
  844. $selected = selected( $k, $row['value'], false );
  845. $return .= "<option class='{$v['class']}' value='{$k}' {$selected}>{$v['label']}</option>";
  846. }
  847. $return .= "</select></td></tr>";
  848. }
  849. // theme drop down
  850. if ( $row['type'] == 'theme' ) {
  851. $return .= "<tr class='{$row['type']}'><td class='tipsy-tooltip' title=\"{$row['helptext']}\">{$row['label']}</td><td><select class='option {$row['class']} {$id}' name='settings[{$id}]'>";
  852. $themes = "";
  853. foreach ( $row['options'] as $k => $v ) {
  854. $selected = selected( $k, $row['value'], false );
  855. $themes .= "<option class='{$v['class']}' value='{$k}' {$selected}>{$v['label']}</option>";
  856. }
  857. $return .= apply_filters( 'metaslider_get_available_themes', $themes, $this->slider->get_setting( 'theme' ) );
  858. $return .= "</select></td></tr>";
  859. }
  860. // text input type
  861. if ( $row['type'] == 'text' ) {
  862. $return .= "<tr class='{$row['type']}'><td class='tipsy-tooltip' title=\"{$row['helptext']}\">{$row['label']}</td><td><input class='option {$row['class']} {$id}' type='text' name='settings[{$id}]' value='" . esc_attr( $row['value'] ) . "' /></td></tr>";
  863. }
  864. // text input type
  865. if ( $row['type'] == 'textarea' ) {
  866. $return .= "<tr class='{$row['type']}'><td class='tipsy-tooltip' title=\"{$row['helptext']}\" colspan='2'>{$row['label']}</td></tr><tr><td colspan='2'><textarea class='option {$row['class']} {$id}' name='settings[{$id}]' />{$row['value']}</textarea></td></tr>";
  867. }
  868. // text input type
  869. if ( $row['type'] == 'title' ) {
  870. $return .= "<tr class='{$row['type']}'><td class='tipsy-tooltip' title=\"{$row['helptext']}\">{$row['label']}</td><td><input class='option {$row['class']} {$id}' type='text' name='{$id}' value='" . esc_attr( $row['value'] ) . "' /></td></tr>";
  871. }
  872. }
  873. return $return;
  874. }
  875. /**
  876. * Return an indexed array of all easing options
  877. *
  878. * @return array
  879. */
  880. private function get_easing_options() {
  881. $options = array(
  882. 'linear', 'swing', 'jswing', 'easeInQuad', 'easeOutQuad', 'easeInOutQuad',
  883. 'easeInCubic', 'easeOutCubic', 'easeInOutCubic', 'easeInQuart',
  884. 'easeOutQuart', 'easeInOutQuart', 'easeInQuint', 'easeOutQuint',
  885. 'easeInOutQuint', 'easeInSine', 'easeOutSine', 'easeInOutSine',
  886. 'easeInExpo', 'easeOutExpo', 'easeInOutExpo', 'easeInCirc', 'easeOutCirc',
  887. 'easeInOutCirc', 'easeInElastic', 'easeOutElastic', 'easeInOutElastic',
  888. 'easeInBack', 'easeOutBack', 'easeInOutBack', 'easeInBounce', 'easeOutBounce',
  889. 'easeInOutBounce'
  890. );
  891. foreach ( $options as $option ) {
  892. $return[$option] = array(
  893. 'label' => ucfirst( preg_replace( '/(\w+)([A-Z])/U', '\\1 \\2', $option ) ),
  894. 'class' => ''
  895. );
  896. }
  897. return $return;
  898. }
  899. /**
  900. * Output the slideshow selector.
  901. *
  902. * Show tabs or a dropdown list depending on the users saved preference.
  903. */
  904. public function print_slideshow_selector() {
  905. global $user_ID;
  906. // First check if we have any slideshows yet
  907. if ($tabs = $this->all_meta_sliders()) {
  908. // Next check if they have the tabs view selected
  909. if ('tabs' == $this->get_view()) {
  910. // Render the tabs
  911. echo "<div class='nav-tab-wrapper'>";
  912. foreach ($tabs as $tab) {
  913. if ( $tab['active'] ) {
  914. echo "<div class='nav-tab nav-tab-active'><input class='no_last_pass' type='text' name='title' value='" . esc_attr($tab['title']) . "'></div>";
  915. } else {
  916. echo "<a href='?page=metaslider&amp;id={$tab['id']}' title= '" . esc_attr($tab['title']) . "' class='nav-tab'>" . esc_html( $tab['title'] ) . "</a>";
  917. }
  918. }
  919. echo $this->get_add_slideshow_button("New", 'nav-tab');
  920. echo "</div>";
  921. // This will render the select dropdown view
  922. // TODO make this resemble the WP Nav menu UI perhaps
  923. } else {
  924. echo "<div class='manage-menus'><label for='select-slideshow' class='selected-menu'>" . __("Select Slideshow", "ml-slider") . ": </label>";
  925. echo "<select name='select-slideshow' onchange='if (this.value) window.location.href=this.value'>";
  926. $tabs = $this->all_meta_sliders('title');
  927. foreach ($tabs as $tab) {
  928. $selected = $tab['active'] ? " selected" : "";
  929. if ($tab['active']) {
  930. $title = $tab['title'];
  931. }
  932. echo "<option value='?page=metaslider&amp;id={$tab['id']}'{$selected}>{$tab['title']}</option>";
  933. }
  934. echo "</select>";
  935. echo "<span class='add-new-menu-action'> " . __( 'or', "ml-slider" ) . " ";
  936. echo "<a href='". wp_nonce_url(admin_url("admin-post.php?action=metaslider_create_slider"), "metaslider_create_slider") ."' id='create_new_tab' class='' title='" . __('Create a New Slideshow', 'ml-slider') . "'>create a new slideshow</a>";
  937. echo "</span></div>";
  938. }
  939. // This section is shown when there are no slideshows
  940. } else {
  941. echo "<div class='nav-tab-wrapper'>";
  942. echo "<div class='fake-tabs nav-tab nav-tab-active'><span class='blurred-out'>" . __('New Slideshow', 'ml-slider') ."</span></div>";
  943. echo $this->get_add_slideshow_button("New", 'nav-tab');
  944. echo "</div>";
  945. }
  946. }
  947. /**
  948. * Return a button to sadd a new slideshow.
  949. *
  950. * @param string $text text for the button
  951. * @param string $classes Specify calsses for the button
  952. * @return sring HTMl Button
  953. */
  954. protected function get_add_slideshow_button($text = '', $classes = '') {
  955. $add_url = wp_nonce_url(admin_url("admin-post.php?action=metaslider_create_slider"), "metaslider_create_slider");
  956. if ('' == $text) {
  957. $text = __('Add a New Slideshow', 'ml-slider');
  958. }
  959. return "<a href='{$add_url}' id='create_new_tab' class='ml-add-new {$classes}' title='" . __('Add a New Slideshow', 'ml-slider') . "'><i><svg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' class='feather feather-plus-circle'><circle cx='12' cy='12' r='10'/><line x1='12' y1='8' x2='12' y2='16'/><line x1='8' y1='12' x2='16' y2='12'/></svg></i> {$text}</a>";
  960. }
  961. /**
  962. * Return the users saved view preference.
  963. */
  964. public function get_view() {
  965. global $user_ID;
  966. if ( get_user_meta( $user_ID, "metaslider_view", true ) ) {
  967. return get_user_meta( $user_ID, "metaslider_view", true );
  968. }
  969. return 'tabs';
  970. }
  971. /**
  972. * Render the admin page (tabs, slides, settings)
  973. */
  974. public function render_admin_page() {
  975. // Default to the most recently modified slider
  976. $slider_id = $this->find_slider('modified', 'DESC');
  977. // If the id parameter exists, verify and use that.
  978. if (isset($_REQUEST['id']) && $id = $_REQUEST['id']) {
  979. if (in_array(get_post_status(absint($id)), array('publish', 'inherit'))) {
  980. $slider_id = (int)$id;
  981. }
  982. }
  983. // "Set the slider"
  984. // TODO figure out what this does and if it can be better stated
  985. // Perhaps maybe "apply_settings()" or something.
  986. if ($slider_id) {
  987. $this->set_slider($slider_id);
  988. }
  989. echo "<div class='wrap metaslider-ui-top' style='margin-top:0;'>";
  990. echo $this->documentation_button();
  991. echo $this->toggle_layout_button();
  992. if (metaslider_user_sees_call_to_action()) {
  993. echo $this->addons_page_button();
  994. echo $this->upgrade_to_pro_top_button();
  995. }
  996. echo "</div>";
  997. $this->do_system_check();
  998. $slider_id = $this->slider ? $this->slider->id : 0;
  999. ?>
  1000. <script>
  1001. var metaslider_slider_id = <?php echo $slider_id; ?>;
  1002. </script>
  1003. <div class="wrap metaslider metaslider-ui">
  1004. <h1 class="wp-heading-inline metaslider-title">
  1005. <img width=50 height=50 src="<?php echo METASLIDER_ADMIN_URL ?>images/metaslider_logo_large.png" alt="MetaSlider">
  1006. MetaSlider
  1007. <?php if (metaslider_pro_is_active()) {
  1008. echo ' Pro';
  1009. } ?>
  1010. </h1>
  1011. <?php if (metaslider_user_sees_notices($this)) {
  1012. echo $this->notices->do_notice(false, 'header', true);
  1013. } ?>
  1014. <form accept-charset="UTF-8" action="<?php echo admin_url( 'admin-post.php'); ?>" method="post">
  1015. <input type="hidden" name="action" value="metaslider_update_slider">
  1016. <input type="hidden" name="slider_id" value="<?php echo $slider_id; ?>">
  1017. <?php wp_nonce_field( 'metaslider_update_slider' ); ?>
  1018. <?php $this->print_slideshow_selector(); ?>
  1019. <?php if ( ! $this->slider ) return; ?>
  1020. <div id='poststuff' class="metaslider-inner wp-clearfix">
  1021. <div id='post-body' class='metabox-holder columns-2'>
  1022. <div id='post-body-content'>
  1023. <div class="left">
  1024. <?php do_action( "metaslider_admin_table_before", $this->slider->id ); ?>
  1025. <table class="widefat sortable metaslider-slides-container">
  1026. <thead>
  1027. <tr>
  1028. <?php if (metaslider_viewing_trashed_slides($this->slider->id)) {
  1029. // If they are on the trash page, show them?>
  1030. <th class="trashed-header">
  1031. <h3><i><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-trash-2"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/><line x1="10" y1="11" x2="10" y2="17"/><line x1="14" y1="11" x2="14" y2="17"/></svg></i> <?php _e('Trashed Slides', 'ml-slider'); ?></h3>
  1032. <small> <?php printf(__('<a href="%s">view active</a>', 'ml-slider'), admin_url("?page=metaslider&id={$this->slider->id}")); ?></small>
  1033. </th>
  1034. <?php } else { ?>
  1035. <th class="slider-title" colspan="2">
  1036. <h3 class="alignleft"><?php echo get_the_title($this->slider->id) ?></h3>
  1037. <?php if (!metaslider_viewing_trashed_slides($this->slider->id)) {
  1038. // Remove the actions on trashed view?>
  1039. <button class='ml-button ml-has-icon ml-skinless-button alignright add-slide' data-editor='content' title='<?php _e( "Add a New Slide", "ml-slider" ) ?>'>
  1040. <i style="top:0;"><svg xmlns="http://www.w3.org/2000/svg" width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-plus-circle"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="16"/><line x1="8" y1="12" x2="16" y2="12"/></svg></i>
  1041. <span><?php _e("Add Slide", "ml-slider") ?></span>
  1042. </button>
  1043. <?php } ?>
  1044. <?php do_action( "metaslider_admin_table_header_right", $this->slider->id ); ?>
  1045. </th>
  1046. <?php } ?>
  1047. </tr>
  1048. </thead>
  1049. <tbody>
  1050. <?php
  1051. $this->slider->render_admin_slides();
  1052. ?>
  1053. </tbody>
  1054. </table>
  1055. <?php do_action( "metaslider_admin_table_after", $this->slider->id ); ?>
  1056. </div>
  1057. </div>
  1058. <div id="postbox-container-1" class="postbox-container ml-sidebar metaslider-settings-area">
  1059. <div class='right'>
  1060. <?php if (metaslider_viewing_trashed_slides($this->slider->id)) {
  1061. // Show a notice explaining the trash?>
  1062. <div class="ms-postbox trashed-notice">
  1063. <div class="notice-info"><?php printf(__('You are viewing slides that have been trashed, which will be automatically deleted in %s days. Click <a href="%s">here</a> to view active slides.', 'ml-slider'), EMPTY_TRASH_DAYS, admin_url("?page=metaslider&id={$this->slider->id}")); ?></div>

Large files files are truncated, but you can click here to view the full file