1. <?php
  2. /*
  3. Plugin Name: WP-Cycle
  4. Plugin URI: http://www.nathanrice.net/plugins/wp-cycle/
  5. Description: This plugin creates an image slideshow from the images you upload using the jQuery Cycle plugin. You can upload/delete images via the administration panel, and display the images in your theme by using the <code>wp_cycle();</code> template tag, which will generate all the necessary HTML for outputting the rotating images.
  6. Version: 0.1.12
  7. Author: Nathan Rice
  8. Author URI: http://www.nathanrice.net/
  9.  
  10. This plugin inherits the GPL license from it's parent system, WordPress.
  11. */
  12.  
  13. /*
  14. ///////////////////////////////////////////////
  15. This section defines the variables that
  16. will be used throughout the plugin
  17. \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
  18. */
  19. //  define our defaults (filterable)
  20. $wp_cycle_defaults = apply_filters('wp_cycle_defaults', array(
  21.     'rotate' => 1,
  22.     'effect' => 'fade',
  23.     'delay' => 3,
  24.     'duration' => 1,
  25.     'img_width' => 300,
  26.     'img_height' => 200,
  27.     'div' => 'rotator'
  28. ));
  29.  
  30. //  pull the settings from the db
  31. $wp_cycle_settings = get_option('wp_cycle_settings');
  32. $wp_cycle_images = get_option('wp_cycle_images');
  33.  
  34. //  fallback
  35. $wp_cycle_settings = wp_parse_args($wp_cycle_settings, $wp_cycle_defaults);
  36.  
  37.  
  38. /*
  39. ///////////////////////////////////////////////
  40. This section hooks the proper functions
  41. to the proper actions in WordPress
  42. \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
  43. */
  44.  
  45. //  this function registers our settings in the db
  46. add_action('admin_init', 'wp_cycle_register_settings');
  47. function wp_cycle_register_settings() {
  48.     register_setting('wp_cycle_images', 'wp_cycle_images', 'wp_cycle_images_validate');
  49.     register_setting('wp_cycle_settings', 'wp_cycle_settings', 'wp_cycle_settings_validate');
  50. }
  51. //  this function adds the settings page to the Appearance tab
  52. add_action('admin_menu', 'add_wp_cycle_menu');
  53. function add_wp_cycle_menu() {
  54.     add_submenu_page('upload.php', 'WP-Cycle Settings', 'WP-Cycle', 'upload_files', 'wp-cycle', 'wp_cycle_admin_page');
  55. }
  56.  
  57. //  add "Settings" link to plugin page
  58. add_filter('plugin_action_links_' . plugin_basename(__FILE__) , 'wp_cycle_plugin_action_links');
  59. function wp_cycle_plugin_action_links($links) {
  60.     $wp_cycle_settings_link = sprintf( '<a href="%s">%s</a>', admin_url( 'upload.php?page=wp-cycle' ), __('Settings') );
  61.     array_unshift($links, $wp_cycle_settings_link);
  62.     return $links;
  63. }
  64.  
  65.  
  66. /*
  67. ///////////////////////////////////////////////
  68. this function is the code that gets loaded when the
  69. settings page gets loaded by the browser.  It calls
  70. functions that handle image uploads and image settings
  71. changes, as well as producing the visible page output.
  72. \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
  73. */
  74. function wp_cycle_admin_page() {
  75.     echo '<div class="wrap">';
  76.    
  77.         //  handle image upload, if necessary
  78.         if($_REQUEST['action'] == 'wp_handle_upload')
  79.             wp_cycle_handle_upload();
  80.        
  81.         //  delete an image, if necessary
  82.         if(isset($_REQUEST['delete']))
  83.             wp_cycle_delete_upload($_REQUEST['delete']);
  84.        
  85.         //  the image management form
  86.         wp_cycle_images_admin();
  87.        
  88.         //  the settings management form
  89.         wp_cycle_settings_admin();
  90.  
  91.     echo '</div>';
  92. }
  93.  
  94.  
  95. /*
  96. ///////////////////////////////////////////////
  97. this section handles uploading images, adding
  98. the image data to the database, deleting images,
  99. and deleting image data from the database.
  100. \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
  101. */
  102. //  this function handles the file upload,
  103. //  resize/crop, and adds the image data to the db
  104. function wp_cycle_handle_upload() {
  105.     global $wp_cycle_settings, $wp_cycle_images;
  106.    
  107.     //  upload the image
  108.     $upload = wp_handle_upload($_FILES['wp_cycle'], 0);
  109.    
  110.     //  extract the $upload array
  111.     extract($upload);
  112.    
  113.     //  the URL of the directory the file was loaded in
  114.     $upload_dir_url = str_replace(basename($file), '', $url);
  115.    
  116.     //  get the image dimensions
  117.     list($width, $height) = getimagesize($file);
  118.    
  119.     //  if the uploaded file is NOT an image
  120.     if(strpos($type, 'image') === FALSE) {
  121.         unlink($file); // delete the file
  122.         echo '<div class="error" id="message"><p>Sorry, but the file you uploaded does not seem to be a valid image. Please try again.</p></div>';
  123.         return;
  124.     }
  125.    
  126.     //  if the image doesn't meet the minimum width/height requirements ...
  127.     if($width < $wp_cycle_settings['img_width'] || $height < $wp_cycle_settings['img_height']) {
  128.         unlink($file); // delete the image
  129.         echo '<div class="error" id="message"><p>Sorry, but this image does not meet the minimum height/width requirements. Please upload another image</p></div>';
  130.         return;
  131.     }
  132.    
  133.     //  if the image is larger than the width/height requirements, then scale it down.
  134.     if($width > $wp_cycle_settings['img_width'] || $height > $wp_cycle_settings['img_height']) {
  135.         //  resize the image
  136.         $resized = image_resize($file, $wp_cycle_settings['img_width'], $wp_cycle_settings['img_height'], true, 'resized');
  137.         $resized_url = $upload_dir_url . basename($resized);
  138.         //  delete the original
  139.         unlink($file);
  140.         $file = $resized;
  141.         $url = $resized_url;
  142.     }
  143.    
  144.     //  make the thumbnail
  145.     $thumb_height = round((100 * $wp_cycle_settings['img_height']) / $wp_cycle_settings['img_width']);
  146.     if(isset($upload['file'])) {
  147.         $thumbnail = image_resize($file, 100, $thumb_height, true, 'thumb');
  148.         $thumbnail_url = $upload_dir_url . basename($thumbnail);
  149.     }
  150.    
  151.     //  use the timestamp as the array key and id
  152.     $time = date('YmdHis');
  153.    
  154.     //  add the image data to the array
  155.     $wp_cycle_images[$time] = array(
  156.         'id' => $time,
  157.         'file' => $file,
  158.         'file_url' => $url,
  159.         'thumbnail' => $thumbnail,
  160.         'thumbnail_url' => $thumbnail_url,
  161.         'image_links_to' => '',
  162.         'alt_text' => ''
  163.     );
  164.    
  165.     //  add the image information to the database
  166.     $wp_cycle_images['update'] = 'Added';
  167.     update_option('wp_cycle_images', $wp_cycle_images);
  168. }
  169.  
  170. //  this function deletes the image,
  171. //  and removes the image data from the db
  172. function wp_cycle_delete_upload($id) {
  173.     global $wp_cycle_images;
  174.    
  175.     //  if the ID passed to this function is invalid,
  176.     //  halt the process, and don't try to delete.
  177.     if(!isset($wp_cycle_images[$id])) return;
  178.    
  179.     //  delete the image and thumbnail
  180.     unlink($wp_cycle_images[$id]['file']);
  181.     unlink($wp_cycle_images[$id]['thumbnail']);
  182.    
  183.     //  indicate that the image was deleted
  184.     $wp_cycle_images['update'] = 'Deleted';
  185.    
  186.     //  remove the image data from the db
  187.     unset($wp_cycle_images[$id]);
  188.     update_option('wp_cycle_images', $wp_cycle_images);
  189. }
  190.  
  191.  
  192. /*
  193. ///////////////////////////////////////////////
  194. these two functions check to see if an update
  195. to the data just occurred. if it did, then they
  196. will display a notice, and reset the update option.
  197. \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
  198. */
  199. //  this function checks to see if we just updated the settings
  200. //  if so, it displays the "updated" message.
  201. function wp_cycle_settings_update_check() {
  202.     global $wp_cycle_settings;
  203.     if(isset($wp_cycle_settings['update'])) {
  204.         echo '<div class="updated fade" id="message"><p>WP-Cycle Settings <strong>'.$wp_cycle_settings['update'].'</strong></p></div>';
  205.         unset($wp_cycle_settings['update']);
  206.         update_option('wp_cycle_settings', $wp_cycle_settings);
  207.     }
  208. }
  209. //  this function checks to see if we just added a new image
  210. //  if so, it displays the "updated" message.
  211. function wp_cycle_images_update_check() {
  212.     global $wp_cycle_images;
  213.     if($wp_cycle_images['update'] == 'Added' || $wp_cycle_images['update'] == 'Deleted' || $wp_cycle_images['update'] == 'Updated') {
  214.         echo '<div class="updated fade" id="message"><p>Image(s) '.$wp_cycle_images['update'].' Successfully</p></div>';
  215.         unset($wp_cycle_images['update']);
  216.         update_option('wp_cycle_images', $wp_cycle_images);
  217.     }
  218. }
  219.  
  220.  
  221. /*
  222. ///////////////////////////////////////////////
  223. these two functions display the front-end code
  224. on the admin page. it's mostly form markup.
  225. \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
  226. */
  227. //  display the images administration code
  228. function wp_cycle_images_admin() { ?>
  229.     <?php global $wp_cycle_images; ?>
  230.     <?php wp_cycle_images_update_check(); ?>
  231.     <h2><?php _e('WP-Cycle Images', 'wp_cycle'); ?></h2>
  232.    
  233.     <table class="form-table">
  234.         <tr valign="top"><th scope="row">Upload New Image</th>
  235.             <td>
  236.             <form enctype="multipart/form-data" method="post" action="?page=wp-cycle">
  237.                 <input type="hidden" name="post_id" id="post_id" value="0" />
  238.                 <input type="hidden" name="action" id="action" value="wp_handle_upload" />
  239.                
  240.                 <label for="wp_cycle">Select a File: </label>
  241.                 <input type="file" name="wp_cycle" id="wp_cycle" />
  242.                 <input type="submit" class="button-primary" name="html-upload" value="Upload" />
  243.             </form>
  244.             </td>
  245.         </tr>
  246.     </table><br />
  247.    
  248.     <?php if(!empty($wp_cycle_images)) : ?>
  249.     <table class="widefat fixed" cellspacing="0">
  250.         <thead>
  251.             <tr>
  252.                 <th scope="col" class="column-slug">Image</th>
  253.                 <th scope="col">Image Links To</th>
  254.                 <th scope="col">Alt Text</th>
  255.                 <th scope="col" class="column-slug">Actions</th>
  256.             </tr>
  257.         </thead>
  258.        
  259.         <tfoot>
  260.             <tr>
  261.                 <th scope="col" class="column-slug">Image</th>
  262.                 <th scope="col">Image Links To</th>
  263.                 <th scope="col">Alt Text</th>
  264.                 <th scope="col" class="column-slug">Actions</th>
  265.             </tr>
  266.         </tfoot>
  267.        
  268.         <tbody>
  269.        
  270.         <form method="post" action="options.php">
  271.         <?php settings_fields('wp_cycle_images'); ?>
  272.         <?php foreach((array)$wp_cycle_images as $image => $data) : ?>
  273.             <tr>
  274.                 <input type="hidden" name="wp_cycle_images[<?php echo $image; ?>][id]" value="<?php echo $data['id']; ?>" />
  275.                 <input type="hidden" name="wp_cycle_images[<?php echo $image; ?>][file]" value="<?php echo $data['file']; ?>" />
  276.                 <input type="hidden" name="wp_cycle_images[<?php echo $image; ?>][file_url]" value="<?php echo $data['file_url']; ?>" />
  277.                 <input type="hidden" name="wp_cycle_images[<?php echo $image; ?>][thumbnail]" value="<?php echo $data['thumbnail']; ?>" />
  278.                 <input type="hidden" name="wp_cycle_images[<?php echo $image; ?>][thumbnail_url]" value="<?php echo $data['thumbnail_url']; ?>" />
  279.                 <th scope="row" class="column-slug"><img src="<?php echo $data['thumbnail_url']; ?>" /></th>
  280.                 <td><input type="text" name="wp_cycle_images[<?php echo $image; ?>][image_links_to]" value="<?php echo $data['image_links_to']; ?>" size="35" /></td>
  281.                 <td class="column-slug"><input type="text" name="wp_cycle_images[<?php echo $image; ?>][alt_text]" value="<?php echo $data['alt_text'];?>" size="35"/></td>
  282.                 <td class="column-slug"><input type="submit" class="button-primary" value="Update" /> <a href="?page=wp-cycle&amp;delete=<?php echo $image; ?>" class="button">Delete</a></td>
  283.             </tr>
  284.         <?php endforeach; ?>
  285.         <input type="hidden" name="wp_cycle_images[update]" value="Updated" />
  286.         </form>
  287.        
  288.         </tbody>
  289.     </table>
  290.     <?php endif; ?>
  291.  
  292. <?php
  293. }
  294.  
  295. //  display the settings administration code
  296. function wp_cycle_settings_admin() { ?>
  297.  
  298.     <?php wp_cycle_settings_update_check(); ?>
  299.     <h2><?php _e('WP-Cycle Settings', 'wp-cycle'); ?></h2>
  300.     <form method="post" action="options.php">
  301.     <?php settings_fields('wp_cycle_settings'); ?>
  302.     <?php global $wp_cycle_settings; $options = $wp_cycle_settings; ?>
  303.     <table class="form-table">
  304.  
  305.         <tr valign="top"><th scope="row">Transition Enabled</th>
  306.         <td><input name="wp_cycle_settings[rotate]" type="checkbox" value="1" <?php checked('1', $options['rotate']); ?> /> <label for="wp_cycle_settings[rotate]">Check this box if you want to enable the transition effects</td>
  307.         </tr>
  308.        
  309.         <tr><th scope="row">Transition Effect</th>
  310.         <td>Please select the effect you would like to use when your images rotate (if applicable):<br />
  311.             <select name="wp_cycle_settings[effect]">
  312.                 <option value="fade" <?php selected('fade', $options['effect']); ?>>fade</option>
  313.                 <option value="wipe" <?php selected('wipe', $options['effect']); ?>>wipe</option>
  314.                 <option value="scrollUp" <?php selected('scrollUp', $options['effect']); ?>>scrollUp</option>
  315.                 <option value="scrollDown" <?php selected('scrollDown', $options['effect']); ?>>scrollDown</option>
  316.                 <option value="scrollLeft" <?php selected('scrollLeft', $options['effect']); ?>>scrollLeft</option>
  317.                 <option value="scrollRight" <?php selected('scrollRight', $options['effect']); ?>>scrollRight</option>
  318.                 <option value="cover" <?php selected('cover', $options['effect']); ?>>cover</option>
  319.                 <option value="shuffle" <?php selected('shuffle', $options['effect']); ?>>shuffle</option>
  320.             </select>
  321.         </td></tr>
  322.        
  323.         <tr><th scope="row">Transition Delay</th>
  324.         <td>Length of time (in seconds) you would like each image to be visible:<br />
  325.             <input type="text" name="wp_cycle_settings[delay]" value="<?php echo $options['delay'] ?>" size="4" />
  326.             <label for="wp_cycle_settings[delay]">second(s)</label>
  327.         </td></tr>
  328.        
  329.         <tr><th scope="row">Transition Length</th>
  330.         <td>Length of time (in seconds) you would like the transition length to be:<br />
  331.             <input type="text" name="wp_cycle_settings[duration]" value="<?php echo $options['duration'] ?>" size="4" />
  332.             <label for="wp_cycle_settings[duration]">second(s)</label>
  333.         </td></tr>
  334.  
  335.         <tr><th scope="row">Image Dimensions</th>
  336.         <td>Please input the width of the image rotator:<br />
  337.             <input type="text" name="wp_cycle_settings[img_width]" value="<?php echo $options['img_width'] ?>" size="4" />
  338.             <label for="wp_cycle_settings[img_width]">px</label>
  339.             <br /><br />
  340.             Please input the height of the image rotator:<br />
  341.             <input type="text" name="wp_cycle_settings[img_height]" value="<?php echo $options['img_height'] ?>" size="4" />
  342.             <label for="wp_cycle_settings[img_height]">px</label>
  343.         </td></tr>
  344.        
  345.         <tr><th scope="row">Rotator DIV ID</th>
  346.         <td>Please indicate what you would like the rotator DIV ID to be:<br />
  347.             <input type="text" name="wp_cycle_settings[div]" value="<?php echo $options['div'] ?>" />
  348.         </td></tr>
  349.        
  350.         <input type="hidden" name="wp_cycle_settings[update]" value="UPDATED" />
  351.    
  352.     </table>
  353.     <p class="submit">
  354.     <input type="submit" class="button-primary" value="<?php _e('Save Settings') ?>" />
  355.     </form>
  356.    
  357.     <!-- The Reset Option -->
  358.     <form method="post" action="options.php">
  359.     <?php settings_fields('wp_cycle_settings'); ?>
  360.     <?php global $wp_cycle_defaults; // use the defaults ?>
  361.     <?php foreach((array)$wp_cycle_defaults as $key => $value) : ?>
  362.     <input type="hidden" name="wp_cycle_settings[<?php echo $key; ?>]" value="<?php echo $value; ?>" />
  363.     <?php endforeach; ?>
  364.     <input type="hidden" name="wp_cycle_settings[update]" value="RESET" />
  365.     <input type="submit" class="button" value="<?php _e('Reset Settings') ?>" />
  366.     </form>
  367.     <!-- End Reset Option -->
  368.     </p>
  369.  
  370. <?php
  371. }
  372.  
  373.  
  374. /*
  375. ///////////////////////////////////////////////
  376. these two functions sanitize the data before it
  377. gets stored in the database via options.php
  378. \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
  379. */
  380. //  this function sanitizes our settings data for storage
  381. function wp_cycle_settings_validate($input) {
  382.     $input['rotate'] = ($input['rotate'] == 1 ? 1 : 0);
  383.     $input['effect'] = wp_filter_nohtml_kses($input['effect']);
  384.     $input['img_width'] = intval($input['img_width']);
  385.     $input['img_height'] = intval($input['img_height']);
  386.     $input['div'] = wp_filter_nohtml_kses($input['div']);
  387.    
  388.     return $input;
  389. }
  390. //  this function sanitizes our image data for storage
  391. function wp_cycle_images_validate($input) {
  392.     foreach((array)$input as $key => $value) {
  393.         if($key != 'update') {
  394.             $input[$key]['file_url'] = clean_url($value['file_url']);
  395.             $input[$key]['thumbnail_url'] = clean_url($value['thumbnail_url']);
  396.            
  397.             if($value['image_links_to'])
  398.             $input[$key]['image_links_to'] = clean_url($value['image_links_to']);
  399.             $input[$key]['alt_text'] = esc_textarea($value['alt_text']);
  400.         }
  401.     }
  402.     return $input;
  403. }
  404.  
  405. /*
  406. ///////////////////////////////////////////////
  407. this final section generates all the code that
  408. is displayed on the front-end of the WP Theme
  409. \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
  410. */
  411. function wp_cycle($args = array(), $content = null) {
  412.     global $wp_cycle_settings, $wp_cycle_images;
  413.    
  414.     // possible future use
  415.     $args = wp_parse_args($args, $wp_cycle_settings);
  416.    
  417.     $newline = "\n"; // line break
  418.    
  419.     echo '<div id="'.$wp_cycle_settings['div'].'">'.$newline;
  420.    
  421.     foreach((array)$wp_cycle_images as $image => $data) {
  422.         if($data['image_links_to']){
  423.             echo '<a href="'.$data['image_links_to'].'">';
  424.         }
  425.         echo '<img src="'.$data['file_url'].'" width="'.$wp_cycle_settings['img_width'].'" height="'.$wp_cycle_settings['img_height'].'" class="'.$data['id'].'"';
  426.         if($data['alt_text']){
  427.             echo 'alt="' .$data['alt_text'].'"';
  428.         }
  429.        
  430.         echo ' />';
  431.         if($data['image_links_to']){
  432.             echo '</a>';
  433.         }
  434.         echo $newline;
  435.     }
  436.     echo '</div>'.$newline;
  437. }
  438.  
  439. //  create the shortcode [wp_cycle]
  440. add_shortcode('wp_cycle', 'wp_cycle_shortcode');
  441. function wp_cycle_shortcode($atts) {
  442.    
  443.     // Temp solution, output buffer the echo function.
  444.     ob_start();
  445.     wp_cycle();
  446.     $output = ob_get_clean();
  447.    
  448.     return $output;
  449.    
  450. }
  451.  
  452. add_action('wp_print_scripts', 'wp_cycle_scripts');
  453. function wp_cycle_scripts() {
  454.     if(!is_admin())
  455.     wp_enqueue_script('cycle', WP_CONTENT_URL.'/plugins/wp-cycle/jquery.cycle.all.min.js', array('jquery'), '', true);
  456. }
  457.  
  458. add_action('wp_footer', 'wp_cycle_args', 15);
  459. function wp_cycle_args() {
  460.     global $wp_cycle_settings; ?>
  461.  
  462. <?php if($wp_cycle_settings['rotate']) : ?>
  463. <script type="text/javascript">
  464. jQuery(document).ready(function($) {
  465.     $("#<?php echo $wp_cycle_settings['div']; ?>").cycle({
  466.         fx: '<?php echo $wp_cycle_settings['effect']; ?>',
  467.         timeout: <?php echo ($wp_cycle_settings['delay'] * 1000); ?>,
  468.         speed: <?php echo ($wp_cycle_settings['duration'] * 1000); ?>,
  469.         pause: 1,
  470.         fit: 1
  471.     });
  472. });
  473. </script>
  474. <?php endif; ?>
  475.  
  476. <?php }
  477.  
  478. add_action( 'wp_head', 'wp_cycle_style' );
  479. function wp_cycle_style() {
  480.     global $wp_cycle_settings;
  481. ?>
  482.    
  483. <style type="text/css" media="screen">
  484.     #<?php echo $wp_cycle_settings['div']; ?> {
  485.         position: relative;
  486.         width: <?php echo $wp_cycle_settings['img_width']; ?>px;
  487.         height: <?php echo $wp_cycle_settings['img_height']?>px;
  488.         margin: 0; padding: 0;
  489.         overflow: hidden;
  490.     }
  491. </style>
  492.    
  493. <?php }