Advertisement
benlevywebdesign

class-calp-events-helper.php

Dec 6th, 2012
107
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 49.79 KB | None | 0 0
  1. <?php
  2. //
  3. //  class-calp-events-helper.php
  4. //  calpress
  5. //
  6. //  Created by The Calpress on 2012-03-01.
  7. //
  8.  
  9. /**
  10.  * Calp_Events_Helper class
  11.  *
  12.  * @package Helpers
  13.  * @author The Calpress
  14.  **/
  15. class Calp_Events_Helper {
  16.     /**
  17.      * _instance class variable
  18.      *
  19.      * Class instance
  20.      *
  21.      * @var null | object
  22.      **/
  23.     private static $_instance = NULL;
  24.  
  25.     /**
  26.      * Constructor
  27.      *
  28.      * Default constructor
  29.      **/
  30.     private function __construct() { }
  31.  
  32.     /**
  33.      * get_instance function
  34.      *
  35.      * Return singleton instance
  36.      *
  37.      * @return object
  38.      **/
  39.     static function get_instance() {
  40.         if( self::$_instance === NULL ) {
  41.             self::$_instance = new self();
  42.         }
  43.  
  44.         return self::$_instance;
  45.     }
  46.  
  47.     /**
  48.      * get_event function
  49.      *
  50.      * Fetches the event object with the given post ID. Uses the WP cache to
  51.      * make this more efficient if possible.
  52.      *
  53.      * @param int $post_id  The ID of the post associated with the event
  54.      *
  55.      * @return Calp_Event  The associated event object
  56.      **/
  57.     static function get_event( $post_id )
  58.     {
  59.         $event = wp_cache_get( $post_id, CALP_POST_TYPE );
  60.         if( $event === false ) {
  61.             // try to get the event instance id, if it is not set get the post id
  62.             $instance_id = isset( $_REQUEST["instance_id"] ) ? (int) $_REQUEST["instance_id"] : false;
  63.             $event = new Calp_Event( $post_id, $instance_id );
  64.  
  65.             if( ! $event->post_id )
  66.                 throw new Calp_Event_Not_Found( "Event with ID '$post_id' could not be retrieved from the database." );
  67.  
  68.             // Cache the event data
  69.             wp_cache_add( $post_id, $event, CALP_POST_TYPE );
  70.         }
  71.         return $event;
  72.     }
  73.  
  74.     /**
  75.      * get_matching_event function
  76.      *
  77.      * Return event ID by iCalendar UID, feed url, start time and whether the
  78.      * event has recurrence rules (to differentiate between an event with a UID
  79.      * defining the recurrence pattern, and other events with with the same UID,
  80.      * which are just RECURRENCE-IDs).
  81.      *
  82.      * @param int $uid iCalendar UID property
  83.      * @param string $feed Feed URL
  84.      * @param int $start Start timestamp (GMT)
  85.      * @param bool $has_recurrence Whether the event has recurrence rules
  86.      * @param int|null $exclude_post_id Do not match against this post ID
  87.      *
  88.      * @return object|null Matching event's post ID, or null if no match
  89.      **/
  90.     function get_matching_event_id( $uid, $feed, $start, $has_recurrence = false, $exclude_post_id = null ) {
  91.         global $wpdb;
  92.  
  93.         $table_name = $wpdb->prefix . 'calp_events';
  94.         $query = "SELECT post_id FROM {$table_name} " .
  95.             "WHERE ical_feed_url = %s " .
  96.             "AND ical_uid = %s " .
  97.             "AND start = FROM_UNIXTIME( %d ) " .
  98.             ( $has_recurrence ? 'AND NOT ' : 'AND ' ) .
  99.             "( recurrence_rules IS NULL OR recurrence_rules = '' )";
  100.         $args = array( $feed, $uid, $start );
  101.         if( ! is_null( $exclude_post_id ) ) {
  102.             $query .= 'AND post_id <> %d';
  103.             $args[] = $exclude_post_id;
  104.         }
  105.  
  106.         return $wpdb->get_var( $wpdb->prepare( $query, $args ) );
  107.     }
  108.  
  109.     /**
  110.      * delete_event_cache function
  111.      *
  112.      * Delete cache of event
  113.      *
  114.      * @param int $pid Event post ID
  115.      *
  116.      * @return void
  117.      **/
  118.     function delete_event_cache( $pid ) {
  119.         global $wpdb;
  120.  
  121.         $table_name = $wpdb->prefix . 'calp_event_instances';
  122.         $wpdb->query( $wpdb->prepare( "DELETE FROM $table_name WHERE post_id = %d", $pid ) );
  123.     }
  124.  
  125.     /**
  126.      * cache_event function
  127.      *
  128.      * Creates a new entry in the cache table for each date that the event appears
  129.      * (and does not already have an explicit RECURRENCE-ID instance, given its
  130.      * iCalendar UID).
  131.      *
  132.      * @param object $event Event to generate cache table for
  133.      *
  134.      * @return void
  135.      **/
  136.     function cache_event( &$event ) {
  137.         global $wpdb;
  138.  
  139.         // Convert event's timestamps to local for correct calculations of
  140.         // recurrence. Need to also remove PHP timezone offset for each date for
  141.         // SG_iCal to calculate correct recurring instances.
  142.         $event->start = $this->gmt_to_local( $event->start ) - date( 'Z', $event->start );
  143.         $event->end = $this->gmt_to_local( $event->end ) - date( 'Z', $event->end );
  144.  
  145.         $evs = array();
  146.         $e   = array(
  147.             'post_id' => $event->post_id,
  148.             'start'     => $event->start,
  149.             'end'       => $event->end,
  150.         );
  151.         $duration = $event->getDuration();
  152.  
  153.         // Always cache initial instance
  154.         $evs[] = $e;
  155.  
  156.         if( $event->recurrence_rules )
  157.         {
  158.             $count  = 0;
  159.             $start  = $event->start;
  160.             $freq   = $event->getFrequency();
  161.  
  162.             $freq->firstOccurrence();
  163.             while( ( $next = $freq->nextOccurrence( $start ) ) > 0 &&
  164.                          $count < 1000 )
  165.             {
  166.                 $count++;
  167.                 $start      = $next;
  168.                 $e['start'] = $start;
  169.                 $e['end']   = $start + $duration;
  170.  
  171.                 $evs[] = $e;
  172.             }
  173.         }
  174.  
  175.         // Make entries unique (sometimes recurrence generator creates duplicates?)
  176.         $evs_unique = array();
  177.         foreach( $evs as $ev ) {
  178.             $evs_unique[ md5( serialize( $ev ) ) ] = $ev;
  179.         }
  180.  
  181.         foreach( $evs_unique as $e )
  182.         {
  183.             // Find out if this event instance is already accounted for by an
  184.             // overriding 'RECURRENCE-ID' of the same iCalendar feed (by comparing the
  185.             // UID, start date, recurrence). If so, then do not create duplicate
  186.             // instance of event.
  187.             $matching_event_id = $event->ical_uid ?
  188.                     $this->get_matching_event_id(
  189.                         $event->ical_uid,
  190.                         $event->ical_feed_url,
  191.                         $start = $this->local_to_gmt( $e['start'] ) - date( 'Z', $e['start'] ),
  192.                         false,  // Only search events that don't define recurrence (i.e. only search for RECURRENCE-ID events)
  193.                         $event->post_id
  194.                     )
  195.                 : null;
  196.  
  197.             // If no other instance was found
  198.             if( is_null( $matching_event_id ) )
  199.             {
  200.                 $start = getdate( $e['start'] );
  201.                 $end = getdate( $e['end'] );
  202.  
  203.                 /*
  204.                 // Commented out for now
  205.                 // If event spans a day and end time is not midnight, or spans more than
  206.                 // a day, then create instance for each spanning day
  207.                 if( ( $start['mday'] != $end['mday'] &&
  208.                             ( $end['hours'] || $end['minutes'] || $end['seconds'] ) )
  209.                         || $e['end'] - $e['start'] > 60 * 60 * 24 ) {
  210.                     $this->create_cache_table_entries( $e );
  211.                 // Else cache single instance of event
  212.                 } else {
  213.                     $this->insert_event_in_cache_table( $e );
  214.                 }
  215.                 */
  216.                 $this->insert_event_in_cache_table( $e );
  217.             }
  218.         }
  219.     }
  220.  
  221.     /**
  222.      * insert_event_in_cache_table function
  223.      *
  224.      * Inserts a new record in the cache table
  225.      *
  226.      * @param array $event Event array
  227.      *
  228.      * @return void
  229.      **/
  230.      function insert_event_in_cache_table( $event ) {
  231.          global $wpdb;
  232.  
  233.          // Return the start/end times to GMT zone
  234.          $event['start'] = $this->local_to_gmt( $event['start'] ) + date( 'Z', $event['start'] );
  235.          $event['end']   = $this->local_to_gmt( $event['end'] )   + date( 'Z', $event['end'] );
  236.  
  237.          $wpdb->query(
  238.              $wpdb->prepare(
  239.                  "INSERT INTO {$wpdb->prefix}calp_event_instances " .
  240.                  "       ( post_id,  start,               end                 ) " .
  241.                  "VALUES ( %d,       FROM_UNIXTIME( %d ), FROM_UNIXTIME( %d ) )",
  242.                  $event
  243.              )
  244.          );
  245.      }
  246.  
  247.      /**
  248.         * create_cache_table_entries function
  249.         *
  250.         * Create a new entry for each day that the event spans.
  251.         *
  252.         * @param array $e Event array
  253.         *
  254.         * @return void
  255.         **/
  256.         function create_cache_table_entries( $e )
  257.         {
  258.             global $calp_events_helper;
  259.  
  260.             // Decompose start dates into components
  261.             $start_bits = getdate( $e['start'] );
  262.  
  263.             // ============================================
  264.             // = Calculate the time for event's first day =
  265.             // ============================================
  266.             // Start time is event's original start time
  267.             $event_start = $e['start'];
  268.             // End time is beginning of next day
  269.             $event_end = mktime(
  270.                 0,                       // hour
  271.                 0,                       // minute
  272.                 0,                       // second
  273.                 $start_bits['mon'],      // month
  274.                 $start_bits['mday'] + 1, // day
  275.                 $start_bits['year']      // year
  276.             );
  277.             // Cache first day
  278.             $this->insert_event_in_cache_table( array( 'post_id' => $e['post_id'], 'start' => $event_start, 'end' => $event_end ) );
  279.  
  280.             // ====================================================
  281.             // = Calculate the time for event's intermediate days =
  282.             // ====================================================
  283.             // Start time is previous end time
  284.             $event_start = $event_end;
  285.             // End time one day ahead
  286.             $event_end += 60 * 60 * 24;
  287.             // Cache intermediate days
  288.             while( $event_end < $e['end'] ) {
  289.                 $this->insert_event_in_cache_table( array( 'post_id' => $e['post_id'], 'start' => $event_start, 'end' => $event_end ) );
  290.                 $event_start  = $event_end;    // Start time is previous end time
  291.                 $event_end    += 24 * 60 * 60; // Increment end time by 1 day
  292.             }
  293.  
  294.             // ===========================================
  295.             // = Calculate the time for event's last day =
  296.             // ===========================================
  297.             // Start time is already correct (previous end time)
  298.             // End time is event end time
  299.             // Only insert if the last event instance if span is > 0
  300.             $event_end = $e['end'];
  301.             if( $event_end > $event_start )
  302.                 // Cache last day
  303.                 $this->insert_event_in_cache_table( array( 'post_id' => $e['post_id'], 'start' => $event_start, 'end' => $event_end ) );
  304.         }
  305.  
  306.     /**
  307.      * Returns the various preset recurrence options available (e.g.,
  308.      * 'DAILY', 'WEEKENDS', etc.).
  309.      *
  310.      * @return string        An associative array of pattern names to English
  311.      *                       equivalents
  312.      */
  313.     function get_repeat_patterns() {
  314.         // Calling functions when creating an array does not seem to work when
  315.         // the assigned to variable is static. This is a workaround.
  316.         static $options;
  317.         if( !isset( $options ) ) {
  318.             $temp = array(
  319.                 ' ' => __( 'No repeat', CALP_PLUGIN_NAME ),
  320.                 '1' => __( 'Every day', CALP_PLUGIN_NAME ),
  321.                 '2' => __( 'Every week', CALP_PLUGIN_NAME ),
  322.                 '3' => __( 'Every month', CALP_PLUGIN_NAME ),
  323.                 '4' => __( 'Every year', CALP_PLUGIN_NAME ),
  324.                 '5' => '-----------',
  325.                 '6' => __( 'Custom...', CALP_PLUGIN_NAME ),
  326.             );
  327.             $options = $temp;
  328.         }
  329.         return $options;
  330.     }
  331.  
  332.     /**
  333.      * Generates and returns repeat dropdown
  334.      *
  335.      * @param Integer|NULL $selected Selected option
  336.      *
  337.      * @return String Repeat dropdown
  338.      */
  339.     function create_repeat_dropdown( $selected = null ) {
  340.         $options = array(
  341.             ' ' => __( 'No repeat', CALP_PLUGIN_NAME ),
  342.             1   => __( 'Every day', CALP_PLUGIN_NAME ),
  343.             2   => __( 'Every week', CALP_PLUGIN_NAME ),
  344.             3   => __( 'Every month', CALP_PLUGIN_NAME ),
  345.             4   => __( 'Every year', CALP_PLUGIN_NAME ),
  346.             5   => '-----------',
  347.             6   => __( 'Custom...', CALP_PLUGIN_NAME ),
  348.         );
  349.         return $this->create_select_element( 'calp_repeat', $options, $selected, array( 5 ) );
  350.     }
  351.  
  352.     /**
  353.      * Returns an associative array containing the following information:
  354.      *   string 'repeat' => pattern of repetition ('DAILY', 'WEEKENDS', etc.)
  355.      *   int    'count'  => end after 'count' times
  356.      *   int    'until'  => repeat until date (as UNIX timestamp)
  357.      * Elements are null if no such recurrence information is available.
  358.      *
  359.      * @param  Calp_Event  Event object to parse recurrence rules of
  360.      * @return array        Array structured as described above
  361.      **/
  362.     function parse_recurrence_rules( &$event )
  363.     {
  364.         $repeat   = null;
  365.         $count    = null;
  366.         $until    = null;
  367.         $end      = 0;
  368.         if( ! is_null( $event ) ) {
  369.             if( strlen( $event->recurrence_rules ) > 0 ) {
  370.                 $line = new SG_iCal_Line( $event->recurrence_rules );
  371.                 $rec = new SG_iCal_Recurrence( $line );
  372.                 switch( $rec->req ) {
  373.                     case 'DAILY':
  374.                         $by_day = $rec->getByDay();
  375.                         if( empty( $by_day ) ) {
  376.                             $repeat = 'DAILY';
  377.                         } elseif( $by_day[0] == 'SA+SU' ) {
  378.                             $repeat = 'WEEKENDS';
  379.                         } elseif( count( $by_day ) == 5 ) {
  380.                             $repeat = 'WEEKDAYS';
  381.                         } else {
  382.                             foreach( $by_day as $d ) {
  383.                                 $repeat .= $d . '+';
  384.                             }
  385.                             $repeat = substr( $repeat, 0, -1 );
  386.                         }
  387.                         break;
  388.                     case 'WEEKLY':
  389.                         $repeat = 'WEEKLY';
  390.                         break;
  391.                     case 'MONTHLY':
  392.                         $repeat = 'MONTHLY';
  393.                         break;
  394.                     case 'YEARLY':
  395.                         $repeat = 'YEARLY';
  396.                         break;
  397.                 }
  398.                 $count = $rec->getCount();
  399.                 $until = $rec->getUntil();
  400.                 if( $until ) {
  401.                     $until = strtotime( $rec->getUntil() );
  402.                     $until += date( 'Z', $until ); // Add timezone offset
  403.                     $end = 2;
  404.                 } elseif( $count )
  405.                     $end = 1;
  406.                 else
  407.                     $end = 0;
  408.             }
  409.         }
  410.         return array(
  411.             'repeat'  => $repeat,
  412.             'count'   => $count,
  413.             'until'   => $until,
  414.             'end'     => $end
  415.         );
  416.     }
  417.  
  418.     /**
  419.      * Generates and returns "End after X times" input
  420.      *
  421.      * @param Integer|NULL $count Initial value of range input
  422.      *
  423.      * @return String Repeat dropdown
  424.      */
  425.     function create_count_input( $name, $count = 100, $max = 365 ) {
  426.         ob_start();
  427.  
  428.         if( ! $count ) $count = 100;
  429.         ?>
  430.             <input type="range" name="<?php echo $name ?>" id="<?php echo $name ?>" min="1" max="<?php echo $max ?>"
  431.                 <?php if( $count ) echo 'value="' . $count . '"' ?> />
  432.         <?php
  433.         return ob_get_clean();
  434.     }
  435.  
  436.     /**
  437.      * create_select_element function
  438.      *
  439.      *
  440.      *
  441.      * @return void
  442.      **/
  443.     function create_select_element( $name, $options = array(), $selected = false, $disabled_keys = array() ) {
  444.         ob_start();
  445.         ?>
  446.         <select name="<?php echo $name ?>" id="<?php echo $name ?>">
  447.             <?php foreach( $options as $key => $val ): ?>
  448.                 <option value="<?php echo $key ?>" <?php echo $key === $selected ? 'selected="selected"' : '' ?><?php echo in_array( $key, $disabled_keys ) ? 'disabled="disabled"' : '' ?>>
  449.                     <?php echo $val ?>
  450.                 </option>
  451.             <?php endforeach ?>
  452.         </select>
  453.         <?php
  454.         return ob_get_clean();
  455.     }
  456.  
  457.     /**
  458.      * create_on_the_select function
  459.      *
  460.      *
  461.      *
  462.      * @return void
  463.      **/
  464.     function create_on_the_select( $f_selected = false, $s_selected = false ) {
  465.         $ret = "";
  466.  
  467.         $first_options = array(
  468.             '0' => __( 'first', CALP_PLUGIN_NAME ),
  469.             '1' => __( 'second', CALP_PLUGIN_NAME ),
  470.             '2' => __( 'third', CALP_PLUGIN_NAME ),
  471.             '3' => __( 'fourth', CALP_PLUGIN_NAME ),
  472.             '4' => '------',
  473.             '5' => __( 'last', CALP_PLUGIN_NAME )
  474.         );
  475.         $ret = $this->create_select_element( 'calp_monthly_each_select', $first_options, $f_selected, array( 4 ) );
  476.  
  477.         $second_options = array(
  478.             '0'   => __( 'Sunday', CALP_PLUGIN_NAME ),
  479.             '1'   => __( 'Monday', CALP_PLUGIN_NAME ),
  480.             '2'   => __( 'Tuesday', CALP_PLUGIN_NAME ),
  481.             '3'   => __( 'Wednesday', CALP_PLUGIN_NAME ),
  482.             '4'   => __( 'Thursday', CALP_PLUGIN_NAME ),
  483.             '5'   => __( 'Friday', CALP_PLUGIN_NAME ),
  484.             '6'   => __( 'Saturday', CALP_PLUGIN_NAME ),
  485.             '7'   => '--------',
  486.             '8'   => __( 'day', CALP_PLUGIN_NAME ),
  487.             '9'   => __( 'weekday', CALP_PLUGIN_NAME ),
  488.             '10'  => __( 'weekend day', CALP_PLUGIN_NAME )
  489.         );
  490.  
  491.         return $ret . $this->create_select_element( 'calp_monthly_on_the_select', $second_options, $s_selected, array( 7 ) );
  492.     }
  493.  
  494.     /**
  495.      * undocumented function
  496.      *
  497.      *
  498.      *
  499.      * @return void
  500.      **/
  501.     function create_list_element( $name, $options = array(), $selected = array() ) {
  502.         ob_start();
  503.         ?>
  504.         <ul class="calp_date_select <?php echo $name?>" id="<?php echo $name?>">
  505.             <?php foreach( $options as $key => $val ): ?>
  506.                 <li<?php echo in_array( $key, $selected ) ? 'class="calp_selected"' : '' ?>>
  507.                     <?php echo $val ?>
  508.                     <input type="hidden" name="<?php echo $name . '_' . $key ?>" value="<?php echo $key ?>" />
  509.                 </li>
  510.             <?php endforeach ?>
  511.         </ul>
  512.         <input type="hidden" name="<?php echo $name ?>" value="<?php echo implode( ',', $selected ) ?>" />
  513.         <?php
  514.         return ob_get_clean();
  515.     }
  516.  
  517.     /**
  518.      * create_montly_date_select function
  519.      *
  520.      *
  521.      *
  522.      * @return void
  523.      **/
  524.     function create_montly_date_select( $selected = array() ) {
  525.         $options = array();
  526.  
  527.         for( $i = 1; $i <= 31; ++$i )
  528.             $options[$i] = $i;
  529.  
  530.         return $this->create_list_element( 'calp_montly_date_select', $options, $selected );
  531.     }
  532.  
  533.     /**
  534.      * create_yearly_date_select function
  535.      *
  536.      *
  537.      *
  538.      * @return void
  539.      **/
  540.     function create_yearly_date_select( $selected = array() ) {
  541.         global $wp_locale;
  542.         $options = array();
  543.  
  544.         for( $i = 1; $i <= 12; ++$i ) {
  545.             $x = $i < 10 ? 0 . $i : $i;
  546.             $options[$i] = $wp_locale->month_abbrev[$wp_locale->month[$x]];
  547.         }
  548.  
  549.         return $this->create_list_element( 'calp_yearly_date_select', $options, $selected );
  550.     }
  551.  
  552.     function get_frequency( $index ) {
  553.         $frequency = array(
  554.             0 => __( 'Daily', CALP_PLUGIN_NAME ),
  555.             1 => __( 'Weekly', CALP_PLUGIN_NAME ),
  556.             2 => __( 'Monthly', CALP_PLUGIN_NAME ),
  557.             3 => __( 'Yearly', CALP_PLUGIN_NAME ),
  558.         );
  559.         return $frequency[$index];
  560.     }
  561.  
  562.     /**
  563.      * row_frequency function
  564.      *
  565.      *
  566.      *
  567.      * @return void
  568.      **/
  569.     function row_frequency( $visible = false, $selected = false ) {
  570.         global $calp_view_helper;
  571.  
  572.         $frequency = array(
  573.             0 => __( 'Daily', CALP_PLUGIN_NAME ),
  574.             1 => __( 'Weekly', CALP_PLUGIN_NAME ),
  575.             2 => __( 'Monthly', CALP_PLUGIN_NAME ),
  576.             3 => __( 'Yearly', CALP_PLUGIN_NAME ),
  577.         );
  578.  
  579.         $args = array(
  580.          'visible'    => $visible,
  581.          'frequency'  => $this->create_select_element( 'calp_frequency', $frequency, $selected )
  582.         );
  583.         return $calp_view_helper->get_view( 'row_frequency.php', $args );
  584.     }
  585.  
  586.     /**
  587.      * row_daily function
  588.      *
  589.      * Returns daily selector
  590.      *
  591.      * @return void
  592.      **/
  593.     function row_daily( $visible = false, $selected = 1 ) {
  594.         global $calp_view_helper;
  595.  
  596.         $args = array(
  597.          'visible'  => $visible,
  598.          'count'    => $this->create_count_input( 'calp_daily_count', $selected, 365 ) . __( 'day(s)', CALP_PLUGIN_NAME )
  599.         );
  600.         return $calp_view_helper->get_view( 'row_daily.php', $args );
  601.     }
  602.  
  603.     /**
  604.      * row_weekly function
  605.      *
  606.      * Returns weekly selector
  607.      *
  608.      * @return void
  609.      **/
  610.     function row_weekly( $visible = false, $count = 1, $selected = array() ) {
  611.         global $calp_view_helper, $wp_locale;
  612.         $start_of_week = get_option( 'start_of_week', 1 );
  613.  
  614.         $options = array();
  615.         // get days from start_of_week until the last day
  616.         for( $i = $start_of_week; $i <= 6; ++$i )
  617.             $options[$this->get_weekday_by_id( $i )] = $wp_locale->weekday_initial[$wp_locale->weekday[$i]];
  618.  
  619.         // get days from 0 until start_of_week
  620.         if( $start_of_week > 0 ) {
  621.             for( $i = 0; $i < $start_of_week; $i++ )
  622.                 $options[$this->get_weekday_by_id( $i )] = $wp_locale->weekday_initial[$wp_locale->weekday[$i]];
  623.         }
  624.  
  625.         $args = array(
  626.          'visible'    => $visible,
  627.          'count'      => $this->create_count_input( 'calp_weekly_count', $count, 52 ) . __( 'week(s)', CALP_PLUGIN_NAME ),
  628.          'week_days'  => $this->create_list_element( 'calp_weekly_date_select', $options, $selected )
  629.         );
  630.         return $calp_view_helper->get_view( 'row_weekly.php', $args );
  631.     }
  632.  
  633.     /**
  634.      * get_weekday_by_id function
  635.      *
  636.      * Returns weekday name in English
  637.      *
  638.      * @param int $day_id Day ID
  639.      *
  640.      * @return string
  641.      **/
  642.     function get_weekday_by_id( $day_id, $by_value = false ) {
  643.         // do not translate this !!!
  644.         $week_days = array(
  645.          0 => 'SU',
  646.          1 => 'MO',
  647.          2 => 'TU',
  648.          3 => 'WE',
  649.          4 => 'TH',
  650.          5 => 'FR',
  651.          6 => 'SA'
  652.         );
  653.  
  654.         if( $by_value ) {
  655.             while( $_name = current( $week_days ) ) {
  656.                     if( $_name == $day_id ) {
  657.                             return key( $week_days );
  658.                     }
  659.                     next( $week_days );
  660.             }
  661.             return false;
  662.         }
  663.         else
  664.             return $week_days[$day_id];
  665.     }
  666.  
  667.     /**
  668.      * row_monthly function
  669.      *
  670.      * Returns monthly selector
  671.      *
  672.      * @return void
  673.      **/
  674.     function row_monthly( $visible = false, $count = 1, $calp_monthly_each = 0, $calp_monthly_on_the = 0, $month = array(), $first = false, $second = false ) {
  675.         global $calp_view_helper;
  676.  
  677.         $args = array(
  678.          'visible'              => $visible,
  679.          'count'                => $this->create_count_input( 'calp_monthly_count', $count, 12 ) . __( 'month(s)', CALP_PLUGIN_NAME ),
  680.          'calp_monthly_each'   => $calp_monthly_each,
  681.          'calp_monthly_on_the' => $calp_monthly_on_the,
  682.          'month'                => $this->create_montly_date_select( $month ),
  683.          'on_the_select'        => $this->create_on_the_select( $first, $second )
  684.         );
  685.         return $calp_view_helper->get_view( 'row_monthly.php', $args );
  686.     }
  687.  
  688.     /**
  689.      * row_yearly function
  690.      *
  691.      * Returns yearly selector
  692.      *
  693.      * @return void
  694.      **/
  695.     function row_yearly( $visible = false, $count = 1, $year = array(), $first = false, $second = false ) {
  696.         global $calp_view_helper;
  697.  
  698.         $args = array(
  699.          'visible'              => $visible,
  700.          'count'                => $this->create_count_input( 'calp_yearly_count', $count, 10 ) . __( 'year(s)', CALP_PLUGIN_NAME ),
  701.          'year'                 => $this->create_yearly_date_select( $year ),
  702.          'on_the_select'        => $this->create_on_the_select( $first, $second )
  703.         );
  704.         return $calp_view_helper->get_view( 'row_yearly.php', $args );
  705.     }
  706.  
  707.     /**
  708.      * get_all_matching_posts function
  709.      *
  710.      * Gets existing event posts that are between the interval
  711.      *
  712.      * @param int $s_time Start time
  713.      * @param int $e_time End time
  714.      *
  715.      * @return Array of matching event posts
  716.      **/
  717.     function get_all_matching_posts( $s_time, $e_time ) {
  718.         global $calp_calendar_helper;
  719.         return $calp_calendar_helper->get_events_between( $s_time, $e_time );
  720.     }
  721.  
  722.     /**
  723.      * get_matching_events function
  724.      *
  725.      * Get events that match with the arguments provided.
  726.      *
  727.      * @param int | bool          $start      Events start before this (GMT) time
  728.      * @param int | bool          $end        Events end before this (GMT) time
  729.      * @param array $filter       Array of filters for the events returned.
  730.      *                            ['cat_ids']   => non-associatative array of category IDs
  731.      *                            ['tag_ids']   => non-associatative array of tag IDs
  732.      *                            ['post_ids']  => non-associatative array of post IDs
  733.      *
  734.      * @return array Matching events
  735.      **/
  736.     function get_matching_events( $start = false, $end = false, $filter = array() ) {
  737.         global $wpdb, $calp_calendar_helper;
  738.  
  739.         // holds event_categories sql
  740.         $c_sql = '';
  741.         $c_where_sql = '';
  742.         // holds event_tags sql
  743.         $t_sql = '';
  744.         $t_where_sql ='';
  745.         // holds posts sql
  746.         $p_where_sql = '';
  747.         // holds start sql
  748.         $start_where_sql = '';
  749.         // holds end sql
  750.         $end_where_sql = '';
  751.         // hold escape values
  752.         $args = array();
  753.  
  754.         // =============================
  755.         // = Generating start date sql =
  756.         // =============================
  757.         if( $start !== false ) {
  758.             $start_where_sql = "AND (e.start >= FROM_UNIXTIME( %d ) OR e.recurrence_rules != '')";
  759.             $args[] = $start;
  760.         }
  761.  
  762.         // ===========================
  763.         // = Generating end date sql =
  764.         // ===========================
  765.         if( $end !== false ) {
  766.             $end_where_sql = "AND (e.end <= FROM_UNIXTIME( %d ) OR e.recurrence_rules != '')";
  767.             $args[] = $end;
  768.         }
  769.  
  770.         // Get the Join (filter_join) and Where (filter_where) statements based on $filter elements specified
  771.         $calp_calendar_helper->_get_filter_sql( $filter );
  772.  
  773.         $query = $wpdb->prepare(
  774.             "SELECT *, e.post_id, UNIX_TIMESTAMP( e.start ) as start, UNIX_TIMESTAMP( e.end ) as end, e.allday, e.recurrence_rules, e.exception_rules,
  775.                 e.recurrence_dates, e.exception_dates, e.venue, e.country, e.address, e.city, e.province, e.postal_code,
  776.                 e.show_map, e.contact_name, e.contact_phone, e.contact_email, e.cost, e.ical_feed_url, e.ical_source_url,
  777.                 e.ical_organizer, e.ical_contact, e.ical_uid " .
  778.             "FROM $wpdb->posts " .
  779.                 "INNER JOIN {$wpdb->prefix}calp_events AS e ON e.post_id = ID " .
  780.                 $filter['filter_join'] .
  781.             "WHERE post_type = '" . CALP_POST_TYPE . "' " .
  782.                 "AND post_status = 'publish' " .
  783.                 $filter['filter_where'] .
  784.                 $start_where_sql .
  785.                 $end_where_sql,
  786.             $args );
  787.  
  788.         $events = $wpdb->get_results( $query, ARRAY_A );
  789.  
  790.         foreach( $events as &$event ) {
  791.             try{
  792.                 $event = new Calp_Event( $event );
  793.             } catch( Calp_Event_Not_Found $n ) {
  794.                 unset( $event );
  795.                 // The event is not found, continue to the next event
  796.                 continue;
  797.             }
  798.  
  799.             // if there are recurrence rules, include the event, else...
  800.             if( empty( $event->recurrence_rules ) ) {
  801.                 // if start time is set, and event start time is before the range
  802.                 // it, continue to the next event
  803.                 if( $start !== false && $event->start < $start ) {
  804.                     unset( $event );
  805.                     continue;
  806.                 }
  807.                 // if end time is set, and event end time is after
  808.                 // it, continue to the next event
  809.                 if( $end !== false && $ev->end < $end ) {
  810.                     unset( $event );
  811.                     continue;
  812.                 }
  813.             }
  814.         }
  815.  
  816.         return $events;
  817.     }
  818.  
  819.     /**
  820.      * fuzzy_string_compare function
  821.      *
  822.      * Compares string A to string B using fuzzy comparison algorithm
  823.      *
  824.      * @param String $a String to compare
  825.      * @param String $b String to compare
  826.      *
  827.      * @return boolean True if the two strings match, false otherwise
  828.      **/
  829.     function fuzzy_string_compare( $a, $b ) {
  830.         $percent = 0;
  831.         similar_text( $a, $b, $percent );
  832.         return ( $percent > 50 );
  833.     }
  834.  
  835.     /**
  836.      * get_short_time function
  837.      *
  838.      * Format a short-form time for use in compressed (e.g. month) views;
  839.      * this is also converted to the local timezone.
  840.      *
  841.      * @param int $timestamp
  842.      * @param bool $convert_from_gmt Whether to convert from GMT time to local
  843.      *
  844.      * @return string
  845.      **/
  846.     function get_short_time( $timestamp, $convert_from_gmt = true ) {
  847.         $time_format = get_option( 'time_format', 'g:ia' );
  848.         if( $convert_from_gmt )
  849.             $timestamp = $this->gmt_to_local( $timestamp );
  850.         return date_i18n( $time_format, $timestamp, true );
  851.     }
  852.  
  853.     /**
  854.      * get_short_date function
  855.      *
  856.      * Format a short-form date for use in compressed (e.g. month) views;
  857.      * this is also converted to the local timezone.
  858.      *
  859.      * @param int $timestamp
  860.      * @param bool $convert_from_gmt Whether to convert from GMT time to local
  861.      *
  862.      * @return string
  863.      **/
  864.     function get_short_date( $timestamp, $convert_from_gmt = true ) {
  865.         if( $convert_from_gmt )
  866.             $timestamp = $this->gmt_to_local( $timestamp );
  867.         //return date_i18n( 'M j', $timestamp, true );//
  868.         return '';
  869.     }
  870.  
  871.     /**
  872.      * get_medium_time function
  873.      *
  874.      * Format a medium-length time for use in other views (e.g., Agenda);
  875.      * this is also converted to the local timezone.
  876.      *
  877.      * @param int $timestamp
  878.      *
  879.      * @return string
  880.      **/
  881.     function get_medium_time( $timestamp, $convert_from_gmt = true ) {
  882.         $time_format = get_option( 'time_format', 'g:ia' );
  883.         if( $convert_from_gmt )
  884.             $timestamp = $this->gmt_to_local( $timestamp );
  885.         return date_i18n( $time_format, $timestamp, true );
  886.     }
  887.  
  888.     /**
  889.      * get_long_time function
  890.      *
  891.      * Format a long-length time for use in other views (e.g., single event);
  892.      * this is also converted to the local timezone.
  893.      *
  894.      * @param int $timestamp
  895.      * @param bool $convert_from_gmt Whether to convert from GMT time to local
  896.      *
  897.      * @return string
  898.      **/
  899.     function get_long_time( $timestamp, $convert_from_gmt = true ) {
  900.         $date_format = get_option( 'date_format', 'D, F j' );
  901.         $time_format = get_option( 'time_format', 'g:i' );
  902.         if( $convert_from_gmt )
  903.             $timestamp = $this->gmt_to_local( $timestamp );
  904.         return date_i18n( $date_format, $timestamp, true ) . ' @ ' . date_i18n( $time_format, $timestamp, true );
  905.     }
  906.  
  907.     /**
  908.      * get_long_date function
  909.      *
  910.      * Format a long-length date for use in other views (e.g., single event);
  911.      * this is also converted to the local timezone if desired.
  912.      *
  913.      * @param int $timestamp
  914.      * @param bool $convert_from_gmt Whether to convert from GMT time to local
  915.      *
  916.      * @return string
  917.      **/
  918.     function get_long_date( $timestamp, $convert_from_gmt = true ) {
  919.         $date_format = get_option( 'date_format', 'D, F j' );
  920.         if( $convert_from_gmt )
  921.             $timestamp = $this->gmt_to_local( $timestamp );
  922.         return date_i18n( $date_format, $timestamp, true );
  923.     }
  924.  
  925.     /**
  926.      * gmt_to_local function
  927.      *
  928.      * Returns the UNIX timestamp adjusted to the local timezone.
  929.      *
  930.      * @param int $timestamp
  931.      *
  932.      * @return int
  933.      **/
  934.     function gmt_to_local( $timestamp ) {
  935.         $offset = get_option( 'gmt_offset' );
  936.         $tz     = get_option( 'timezone_string', 'America/Los_Angeles' );
  937.  
  938.         $offset = $this->get_timezone_offset( 'UTC', $tz, $timestamp );
  939.  
  940.         if( ! $offset )
  941.             $offset = get_option( 'gmt_offset' ) * 3600;
  942.  
  943.         return $timestamp + $offset;
  944.     }
  945.  
  946.     /**
  947.      * local_to_gmt function
  948.      *
  949.      * Returns the UNIX timestamp adjusted from the local timezone to GMT.
  950.      *
  951.      * @param int $timestamp
  952.      *
  953.      * @return int
  954.      **/
  955.     function local_to_gmt( $timestamp ) {
  956.         $offset = get_option( 'gmt_offset' );
  957.         $tz     = get_option( 'timezone_string', 'America/Los_Angeles' );
  958.  
  959.         $offset = $this->get_timezone_offset( 'UTC', $tz, $timestamp );
  960.  
  961.         if( ! $offset )
  962.             $offset = get_option( 'gmt_offset' ) * 3600;
  963.  
  964.         return $timestamp - $offset;
  965.     }
  966.  
  967.     /**
  968.      * get_timezone_offset function
  969.      *
  970.      * Returns the offset from the origin timezone to the remote timezone, in seconds.
  971.      *
  972.      * @param string $remote_tz Remote TimeZone
  973.      * @param string $origin_tz Origin TimeZone
  974.      * @param string/int $timestamp Unix Timestamp or 'now'
  975.      *
  976.      * @return int
  977.      **/
  978.     /**
  979.      * get_timezone_offset function
  980.      *
  981.      * Returns the offset from the origin timezone to the remote timezone, in seconds.
  982.      *
  983.      * @param string $remote_tz Remote TimeZone
  984.      * @param string $origin_tz Origin TimeZone
  985.      * @param string/int $timestamp Unix Timestamp or 'now'
  986.      *
  987.      * @return int
  988.      **/
  989.     function get_timezone_offset( $remote_tz, $origin_tz = null, $timestamp = false ) {
  990.         // set timestamp to time now
  991.         if( $timestamp == false ) {
  992.             $timestamp = gmmktime();
  993.         }
  994.  
  995.         if( $origin_tz === null ) {
  996.             if( ! is_string( $origin_tz = date_default_timezone_get() ) ) {
  997.                 return false; // A UTC timestamp was returned -- bail out!
  998.             }
  999.         }
  1000.  
  1001.         try {
  1002.             $origin_dtz = new DateTimeZone( $origin_tz );
  1003.             $remote_dtz = new DateTimeZone( $remote_tz );
  1004.  
  1005.             // if DateTimeZone fails, throw exception
  1006.             if( $origin_dtz == false || $remote_dtz == false )
  1007.                 throw new Exception( 'DateTimeZone class failed' );
  1008.  
  1009.             $origin_dt  = new DateTime( gmdate( 'Y-m-d H:i:s', $timestamp ), $origin_dtz );
  1010.             $remote_dt  = new DateTime( gmdate( 'Y-m-d H:i:s', $timestamp ), $remote_dtz );
  1011.  
  1012.             // if DateTime fails, throw exception
  1013.             if( $origin_dt == false || $remote_dt == false )
  1014.                 throw new Exception( 'DateTime class failed' );
  1015.  
  1016.             $offset = $origin_dtz->getOffset( $origin_dt ) - $remote_dtz->getOffset( $remote_dt );
  1017.         } catch( Exception $e ) {
  1018.             return false;
  1019.         }
  1020.  
  1021.         return $offset;
  1022.     }
  1023.  
  1024.     /**
  1025.      * A GMT-version of PHP getdate().
  1026.      *
  1027.      * @param int $timestamp  UNIX timestamp
  1028.      * @return array          Same result as getdate(), but based in GMT time.
  1029.      **/
  1030.     function gmgetdate( $timestamp = null ) {
  1031.         if( ! $timestamp ) $timestamp = time();
  1032.         $bits = explode( ',', gmdate( 's,i,G,j,w,n,Y,z,l,F,U', $timestamp ) );
  1033.         $bits = array_combine(
  1034.             array( 'seconds', 'minutes', 'hours', 'mday', 'wday', 'mon', 'year', 'yday', 'weekday', 'month', 0 ),
  1035.             $bits
  1036.         );
  1037.         return $bits;
  1038.     }
  1039.  
  1040.     /**
  1041.      * time_to_gmt function
  1042.      *
  1043.      * Converts time to GMT
  1044.      *
  1045.      * @param int $timestamp
  1046.      *
  1047.      * @return int
  1048.      **/
  1049.     function time_to_gmt( $timestamp ) {
  1050.         return strtotime( gmdate( 'M d Y H:i:s', $timestamp ) );
  1051.     }
  1052.  
  1053.     /**
  1054.      * get_gmap_url function
  1055.      *
  1056.      * Returns the URL to the Google Map for the given event object.
  1057.      *
  1058.      * @param Calp_Event $event  The event object to display a map for
  1059.      *
  1060.      * @return string
  1061.      **/
  1062.     function get_gmap_url( &$event ) {
  1063.         $location_arg = urlencode( $event->address );
  1064.         $lang         = $this->get_lang();
  1065.  
  1066.         return "http://www.google.com/maps?f=q&hl=" . $lang . "&source=embed&q=" . $location_arg;
  1067.     }
  1068.  
  1069.     /**
  1070.      * get_lang function
  1071.      *
  1072.      * Returns the ISO-639 part of the configured locale. The default
  1073.      * language is English (en).
  1074.      *
  1075.      * @return string
  1076.      **/
  1077.     function get_lang() {
  1078.         $locale = explode( '_', get_locale() );
  1079.  
  1080.         return ( isset( $locale[0] ) && $locale[0] != '' ) ? $locale[0] : 'en';
  1081.     }
  1082.  
  1083.     /**
  1084.      * get_region function
  1085.      *
  1086.      * Returns the ISO-3166 part of the configured locale as a ccTLD.
  1087.      * Used for region biasing in the geo autocomplete plugin.
  1088.      *
  1089.      * @return string
  1090.      **/
  1091.     function get_region() {
  1092.         $locale = explode( '_', get_locale() );
  1093.  
  1094.         $region = ( isset( $locale[1] ) && $locale[1] != '' ) ? strtolower( $locale[1] ) : '';
  1095.  
  1096.         // Primary ccTLD for United Kingdom is uk.
  1097.         return ( $region == 'gb' ) ? 'uk' : $region;
  1098.     }
  1099.  
  1100.     /**
  1101.      * trim_excerpt function
  1102.      *
  1103.      * Generates an excerpt from the given content string. Adapted from
  1104.      * WordPress's wp_trim_excerpt function that is not useful for applying
  1105.      * to custom content.
  1106.      *
  1107.      * @param string $text The content to trim.
  1108.      *
  1109.      * @return string      The excerpt.
  1110.      **/
  1111.     function trim_excerpt( $text )
  1112.     {
  1113.         $raw_excerpt = $text;
  1114.  
  1115.         $text = strip_shortcodes( $text );
  1116.  
  1117.         $text = str_replace(']]>', ']]&gt;', $text);
  1118.         $text = strip_tags($text);
  1119.         $excerpt_length = apply_filters('excerpt_length', 55);
  1120.         $excerpt_more = apply_filters('excerpt_more', ' ' . '[...]');
  1121.         $words = preg_split("/[\n\r\t ]+/", $text, $excerpt_length + 1, PREG_SPLIT_NO_EMPTY);
  1122.         if ( count($words) > $excerpt_length ) {
  1123.             array_pop($words);
  1124.             $text = implode(' ', $words);
  1125.             $text = $text . $excerpt_more;
  1126.         } else {
  1127.             $text = implode(' ', $words);
  1128.         }
  1129.         return apply_filters('wp_trim_excerpt', $text, $raw_excerpt);
  1130.     }
  1131.  
  1132.     /**
  1133.      * filter_by_terms function
  1134.      *
  1135.      * Returns a subset of post IDs from the given set of post IDs that have any
  1136.      * of the given taxonomy term IDs. This is actually useful for all posts and
  1137.      * taxonomies in general, not just event posts and event-specific taxonomies.
  1138.      *
  1139.      * @param array|string $post_ids  Post IDs as an array of ints or
  1140.      *                                comma-separated string
  1141.      * @param array|string $term_ids  Term IDs as an array of ints or
  1142.      *                                comma-separated string
  1143.      *
  1144.      * @return array                  Filtered post IDs as an array of ints
  1145.      */
  1146.     function filter_by_terms( $post_ids, $term_ids )
  1147.     {
  1148.         global $wpdb;
  1149.  
  1150.         // ===============================================
  1151.         // = Sanitize provided IDs against SQL injection =
  1152.         // ===============================================
  1153.         if( ! is_array( $post_ids ) )
  1154.             $post_ids = explode( ',', $post_ids );
  1155.         foreach( $post_ids as &$post_id ) {
  1156.             $post_id = intval( $post_id );
  1157.         }
  1158.         $post_ids = join( ',', $post_ids );
  1159.  
  1160.         if( ! is_array( $term_ids ) )
  1161.             $term_ids = explode( ',', $term_ids );
  1162.         foreach( $term_ids as &$term_id ) {
  1163.             $term_id = intval( $term_id );
  1164.         }
  1165.         $term_ids = join( ',', $term_ids );
  1166.  
  1167.         $query =
  1168.             "SELECT DISTINCT p.ID " .
  1169.             "FROM $wpdb->posts p " .
  1170.                 "INNER JOIN $wpdb->term_relationships tr ON p.ID = tr.object_id " .
  1171.                 "INNER JOIN $wpdb->term_taxonomy tt ON tr.term_taxonomy_id = tt.term_taxonomy_id " .
  1172.             "WHERE p.ID IN ( " . $post_ids . " ) " .
  1173.                 "AND tt.term_id IN ( " . $term_ids . " )";
  1174.  
  1175.         return $wpdb->get_col( $query );
  1176.     }
  1177.  
  1178.     /**
  1179.      * get_category_color function
  1180.      *
  1181.      * Returns the color of the Event Category having the given term ID.
  1182.      *
  1183.      * @param int $term_id The ID of the Event Category
  1184.      * @return string
  1185.      */
  1186.     function get_category_color( $term_id ) {
  1187.         global $wpdb;
  1188.  
  1189.         $term_id = (int) $term_id;
  1190.         $table_name = $wpdb->prefix . 'calp_event_category_colors';
  1191.         $color = $wpdb->get_var( "SELECT term_color FROM {$table_name} WHERE term_id = {$term_id}" );
  1192.         return $color;
  1193.     }
  1194.  
  1195.     /**
  1196.      * get_category_color_square function
  1197.      *
  1198.      * Returns the HTML markup for the category color square of the given Event
  1199.      * Category term ID.
  1200.      *
  1201.      * @param int $term_id The Event Category's term ID
  1202.      * @return string
  1203.      **/
  1204.     function get_category_color_square( $term_id ) {
  1205.         $color = $this->get_category_color( $term_id );
  1206.         $cat = get_term( $term_id, 'events_categories' );
  1207.         if( ! is_null( $color ) && ! empty( $color ) )
  1208.             return '<div class="calp-category-color" style="background:' . $color . '" title="' . esc_attr( $cat->name ) . '"></div>';
  1209.  
  1210.         return '';
  1211.     }
  1212.  
  1213.     /**
  1214.      * get_event_category_color_style function
  1215.      *
  1216.      * Returns the style attribute assigning the category color style to an event.
  1217.      *
  1218.      * @param int $term_id The Event Category's term ID
  1219.      * @param bool $allday Whether the event is all-day
  1220.      * @return string
  1221.      **/
  1222.     function get_event_category_color_style( $term_id, $allday = false ) {
  1223.         $color = $this->get_category_color( $term_id );
  1224.         if( ! is_null( $color ) && ! empty( $color ) ) {
  1225.             return $color;
  1226.         }
  1227.  
  1228.         return '';
  1229.     }
  1230.  
  1231.     /**
  1232.      * get_event_category_faded_color function
  1233.      *
  1234.      * Returns a faded version of the event's category color in hex format.
  1235.      *
  1236.      * @param int $term_id The Event Category's term ID
  1237.      * @return string
  1238.      **/
  1239.     function get_event_category_faded_color( $term_id ) {
  1240.         $color = $this->get_category_color( $term_id );
  1241.         if( ! is_null( $color ) && ! empty( $color ) ) {
  1242.  
  1243.             $color1 = substr( $color, 1 );
  1244.             $color2 = 'ffffff';
  1245.  
  1246.             $c1_p1 = hexdec( substr( $color1, 0, 2 ) );
  1247.             $c1_p2 = hexdec( substr( $color1, 2, 2 ) );
  1248.             $c1_p3 = hexdec( substr( $color1, 4, 2 ) );
  1249.  
  1250.             $c2_p1 = hexdec( substr( $color2, 0, 2 ) );
  1251.             $c2_p2 = hexdec( substr( $color2, 2, 2 ) );
  1252.             $c2_p3 = hexdec( substr( $color2, 4, 2 ) );
  1253.  
  1254.             $m_p1 = dechex( round( $c1_p1 * 0.3 + $c2_p1 * 0.7 ) );
  1255.             $m_p2 = dechex( round( $c1_p2 * 0.3 + $c2_p2 * 0.7 ) );
  1256.             $m_p3 = dechex( round( $c1_p3 * 0.3 + $c2_p3 * 0.7 ) );
  1257.  
  1258.             return '#' . $m_p1 . $m_p2 . $m_p3;
  1259.         }
  1260.  
  1261.         return '';
  1262.     }
  1263.  
  1264.     /**
  1265.      * get_event_category_colors function
  1266.      *
  1267.      * Returns category color squares for the list of Event Category objects.
  1268.      *
  1269.      * @param array $cats The Event Category objects as returned by get_terms()
  1270.      * @return string
  1271.      **/
  1272.     function get_event_category_colors( $cats ) {
  1273.         $sqrs = '';
  1274.  
  1275.         foreach( $cats as $cat ) {
  1276.             $tmp = $this->get_category_color_square( $cat->term_id );
  1277.             if( ! empty( $tmp ) )
  1278.                 $sqrs .= $tmp;
  1279.         }
  1280.  
  1281.         return $sqrs;
  1282.     }
  1283.  
  1284.     /**
  1285.      * create_end_dropdown function
  1286.      *
  1287.      * Outputs the dropdown list for the recurrence end option.
  1288.      *
  1289.      * @param int $selected The index of the selected option, if any
  1290.      * @return void
  1291.      **/
  1292.     function create_end_dropdown( $selected = null ) {
  1293.         ob_start();
  1294.  
  1295.         $options = array(
  1296.             0 => __( 'Never', CALP_PLUGIN_NAME ),
  1297.             1 => __( 'After', CALP_PLUGIN_NAME ),
  1298.             2 => __( 'On date', CALP_PLUGIN_NAME )
  1299.         );
  1300.  
  1301.         ?>
  1302.         <select name="calp_end" id="calp_end">
  1303.             <?php foreach( $options as $key => $val ): ?>
  1304.                 <option value="<?php echo $key ?>" <?php if( $key === $selected ) echo 'selected="selected"' ?>>
  1305.                     <?php echo $val ?>
  1306.                 </option>
  1307.             <?php endforeach ?>
  1308.         </select>
  1309.         <?php
  1310.  
  1311.         $output = ob_get_contents();
  1312.         ob_end_clean();
  1313.  
  1314.         return $output;
  1315.     }
  1316.  
  1317.     /**
  1318.      * rrule_to_text function
  1319.      *
  1320.      *
  1321.      *
  1322.      * @return void
  1323.      **/
  1324.     function rrule_to_text( $rrule = '') {
  1325.         $txt = '';
  1326.         $rc = new SG_iCal_Recurrence( new SG_iCal_Line( 'RRULE:' . $rrule ) );
  1327.         switch( $rc->getFreq() ) {
  1328.             case 'DAILY':
  1329.                 $this->_get_interval( $txt, 'daily', $rc->getInterval() );
  1330.                 $this->_ending_sentence( $txt, $rc );
  1331.                 break;
  1332.             case 'WEEKLY':
  1333.                 $this->_get_interval( $txt, 'weekly', $rc->getInterval() );
  1334.                 $this->_get_sentence_by( $txt, 'weekly', $rc );
  1335.                 $this->_ending_sentence( $txt, $rc );
  1336.                 break;
  1337.             case 'MONTHLY':
  1338.                 $this->_get_interval( $txt, 'monthly', $rc->getInterval() );
  1339.                 $this->_get_sentence_by( $txt, 'monthly', $rc );
  1340.                 $this->_ending_sentence( $txt, $rc );
  1341.                 break;
  1342.             case 'YEARLY':
  1343.                 $this->_get_interval( $txt, 'yearly', $rc->getInterval() );
  1344.                 $this->_get_sentence_by( $txt, 'yearly', $rc );
  1345.                 $this->_ending_sentence( $txt, $rc );
  1346.                 break;
  1347.             default:
  1348.                 $txt = $rrule;
  1349.         }
  1350.         return $txt;
  1351.     }
  1352.  
  1353.     /**
  1354.      * _get_sentence_by function
  1355.      *
  1356.      * @internal
  1357.      *
  1358.      * @return void
  1359.      **/
  1360.     function _get_sentence_by( &$txt, $freq, $rc ) {
  1361.         global $wp_locale;
  1362.  
  1363.         switch( $freq ) {
  1364.             case 'weekly':
  1365.                 if( $rc->getByDay() ) {
  1366.                     if( count( $rc->getByDay() ) > 1 ) {
  1367.                         // if there are more than 3 days
  1368.                         // use days's abbr
  1369.                         if( count( $rc->getByDay() ) > 2 ) {
  1370.                             $_days = '';
  1371.                             foreach( $rc->getByDay() as $d ) {
  1372.                                 $day = $this->get_weekday_by_id( $d, true );
  1373.                                 $_days .= ' ' . $wp_locale->weekday_abbrev[$wp_locale->weekday[$day]] . ',';
  1374.                             }
  1375.                             // remove the last ' and'
  1376.                             $_days = substr( $_days, 0, -1 );
  1377.                             $txt .= ' ' . _x( 'on', 'Recurrence editor - weekly tab', CALP_PLUGIN_NAME ) . $_days;
  1378.                         } else {
  1379.                             $_days = '';
  1380.                             foreach( $rc->getByDay() as $d ) {
  1381.                                 $day = $this->get_weekday_by_id( $d, true );
  1382.                                 $_days .= ' ' . $wp_locale->weekday[$day] . ' ' . __( 'and', CALP_PLUGIN_NAME );
  1383.                             }
  1384.                             // remove the last ' and'
  1385.                             $_days = substr( $_days, 0, -4 );
  1386.                             $txt .= ' ' . _x( 'on', 'Recurrence editor - weekly tab', CALP_PLUGIN_NAME ) . $_days;
  1387.                         }
  1388.                     } else {
  1389.                         $_days = '';
  1390.                         foreach( $rc->getByDay() as $d ) {
  1391.                             $day = $this->get_weekday_by_id( $d, true );
  1392.                             $_days .= ' ' . $wp_locale->weekday[$day];
  1393.                         }
  1394.                         $txt .= ' ' . _x( 'on', 'Recurrence editor - weekly tab', CALP_PLUGIN_NAME ) . $_days;
  1395.                     }
  1396.                 }
  1397.                 break;
  1398.             case 'monthly':
  1399.                 if( $rc->getByMonthDay() ) {
  1400.                     // if there are more than 2 days
  1401.                     if( count( $rc->getByMonthDay() ) > 2 ) {
  1402.                         $_days = '';
  1403.                         foreach( $rc->getByMonthDay() as $m_day ) {
  1404.                             $_days .= ' ' . $this->_ordinal( $m_day ) . ',';
  1405.                         }
  1406.                         $_days = substr( $_days, 0, -1 );
  1407.                         $txt .= ' ' . _x( 'on', 'Recurrence editor - monthly tab', CALP_PLUGIN_NAME ) . $_days . ' ' . __( 'of the month', _PLUGIN_NAME );
  1408.                     } else if( count( $rc->getByMonthDay() ) > 1 ) {
  1409.                         $_days = '';
  1410.                         foreach( $rc->getByMonthDay() as $m_day ) {
  1411.                             $_days .= ' ' . $this->_ordinal( $m_day ) . ' ' . __( 'and', CALP_PLUGIN_NAME );
  1412.                         }
  1413.                         $_days = substr( $_days, 0, -4 );
  1414.                         $txt .= ' ' . _x( 'on', 'Recurrence editor - monthly tab', CALP_PLUGIN_NAME ) . $_days . ' ' . __( 'of the month', _PLUGIN_NAME );
  1415.                     } else {
  1416.                         $_days = '';
  1417.                         foreach( $rc->getByMonthDay() as $m_day ) {
  1418.                             $_days .= ' ' . $this->_ordinal( $m_day );
  1419.                         }
  1420.                         $txt .= ' ' . _x( 'on', 'Recurrence editor - monthly tab', CALP_PLUGIN_NAME ) . $_days . ' ' . __( 'of the month', _PLUGIN_NAME );
  1421.                     }
  1422.                 }
  1423.                 break;
  1424.             case 'yearly':
  1425.                 if( $rc->getByMonth() ) {
  1426.                     // if there are more than 2 months
  1427.                     if( count( $rc->getByMonth() ) > 2  ) {
  1428.                         $_months = '';
  1429.                         foreach( $rc->getByMonth() as $_m ) {
  1430.                             $_m = $_m < 10 ? 0 . $_m : $_m;
  1431.                             $_months .= ' ' . $wp_locale->month_abbrev[$wp_locale->month[$_m]] . ',';
  1432.                         }
  1433.                         $_months = substr( $_months, 0, -1 );
  1434.                         $txt .= ' ' . _x( 'on', 'Recurrence editor - yearly tab', CALP_PLUGIN_NAME ) . $_months;
  1435.                     } else if( count( $rc->getByMonth() ) > 1 ) {
  1436.                         $_months = '';
  1437.                         foreach( $rc->getByMonth() as $_m ) {
  1438.                             $_m = $_m < 10 ? 0 . $_m : $_m;
  1439.                             $_months .= ' ' . $wp_locale->month[$_m] . ' ' . __( 'and', CALP_PLUGIN_NAME );
  1440.                         }
  1441.                         $_months = substr( $_months, 0, -4 );
  1442.                         $txt .= ' ' . _x( 'on', 'Recurrence editor - yearly tab', CALP_PLUGIN_NAME ) . $_months;
  1443.                     } else {
  1444.                         $_months = '';
  1445.                         foreach( $rc->getByMonth() as $_m ) {
  1446.                             $_m = $_m < 10 ? 0 . $_m : $_m;
  1447.                             $_months .= ' ' . $wp_locale->month[$_m];
  1448.                         }
  1449.                         $txt .= ' ' . _x( 'on', 'Recurrence editor - yearly tab', CALP_PLUGIN_NAME ) . $_months;
  1450.                     }
  1451.                 }
  1452.                 break;
  1453.         }
  1454.     }
  1455.  
  1456.     /**
  1457.      * _ordinal function
  1458.      *
  1459.      * @internal
  1460.      *
  1461.      * @return void
  1462.      **/
  1463.     function _ordinal( $cdnl ) {
  1464.         $locale = explode( '_', get_locale() );
  1465.  
  1466.         if( isset( $locale[0] ) && $locale[0] != 'en' )
  1467.             return $cdnl;
  1468.  
  1469.         $test_c = abs($cdnl) % 10;
  1470.         $ext = ( ( abs( $cdnl ) % 100 < 21 && abs( $cdnl ) % 100 > 4 ) ? 'th'
  1471.                             : ( ( $test_c < 4 ) ? ( $test_c < 3 ) ? ( $test_c < 2 ) ? ( $test_c < 1 )
  1472.                             ? 'th' : 'st' : 'nd' : 'rd' : 'th' ) );
  1473.         return $cdnl.$ext;
  1474.     }
  1475.  
  1476.     /**
  1477.      * _get_interval function
  1478.      *
  1479.      * @internal
  1480.      *
  1481.      * @return void
  1482.      **/
  1483.     function _get_interval( &$txt, $freq, $interval ) {
  1484.         switch( $freq ) {
  1485.             case 'daily':
  1486.                 // check if interval is set
  1487.                 if( ! $interval || $interval == 1 ) {
  1488.                     $txt = __( 'Daily', CALP_PLUGIN_NAME );
  1489.                 } else {
  1490.                     if( $interval == 2 ) {
  1491.                         $txt = __( 'Every other day', CALP_PLUGIN_NAME );
  1492.                     } else {
  1493.                         $txt = sprintf( __( 'Every %d days', CALP_PLUGIN_NAME ), $interval );
  1494.                     }
  1495.                 }
  1496.                 break;
  1497.             case 'weekly':
  1498.                 // check if interval is set
  1499.                 if( ! $interval || $interval == 1 ) {
  1500.                     $txt = __( 'Weekly', CALP_PLUGIN_NAME );
  1501.                 } else {
  1502.                     if( $interval == 2 ) {
  1503.                         $txt = __( 'Every other week', CALP_PLUGIN_NAME );
  1504.                     } else {
  1505.                         $txt = sprintf( __( 'Every %d weeks', CALP_PLUGIN_NAME ), $interval );
  1506.                     }
  1507.                 }
  1508.                 break;
  1509.             case 'monthly':
  1510.                 // check if interval is set
  1511.                 if( ! $interval || $interval == 1 ) {
  1512.                     $txt = __( 'Monthly', CALP_PLUGIN_NAME );
  1513.                 } else {
  1514.                     if( $interval == 2 ) {
  1515.                         $txt = __( 'Every other month', CALP_PLUGIN_NAME );
  1516.                     } else {
  1517.                         $txt = sprintf( __( 'Every %d months', CALP_PLUGIN_NAME ), $interval );
  1518.                     }
  1519.                 }
  1520.                 break;
  1521.             case 'yearly':
  1522.                 // check if interval is set
  1523.                 if( ! $interval || $interval == 1 ) {
  1524.                     $txt = __( 'Yearly', CALP_PLUGIN_NAME );
  1525.                 } else {
  1526.                     if( $interval == 2 ) {
  1527.                         $txt = __( 'Every other year', CALP_PLUGIN_NAME );
  1528.                     } else {
  1529.                         $txt = sprintf( __( 'Every %d years', CALP_PLUGIN_NAME ), $interval );
  1530.                     }
  1531.                 }
  1532.                 break;
  1533.         }
  1534.     }
  1535.  
  1536.     /**
  1537.      * _ending_sentence function
  1538.      *
  1539.      * Ends rrule to text sentence
  1540.      *
  1541.      * @internal
  1542.      *
  1543.      * @return void
  1544.      **/
  1545.     function _ending_sentence( &$txt, &$rc ) {
  1546.         if( $until = $rc->getUntil() ) {
  1547.             if( ! is_int( $until ) )
  1548.                 $until = strtotime( $until );
  1549.             $txt .= ' ' . sprintf( __( 'until %s', CALP_PLUGIN_NAME ), date_i18n( get_option( 'date_format' ), $until ) );
  1550.         }
  1551.         else if( $count = $rc->getCount() )
  1552.             $txt .= ' ' . sprintf( __( 'for %d occurrences', CALP_PLUGIN_NAME ), $count );
  1553.         else
  1554.             $txt .= ' - ' . __( 'forever', CALP_PLUGIN_NAME );
  1555.     }
  1556.  
  1557.     /**
  1558.      * undocumented function
  1559.      *
  1560.      *
  1561.      *
  1562.      * @return void
  1563.      **/
  1564.     function convert_rrule_to_text() {
  1565.         $error = false;
  1566.         // check to see if RRULE is set
  1567.         if( isset( $_REQUEST["rrule"] ) ) {
  1568.  
  1569.             // check to see if rrule is empty
  1570.             if( empty( $_REQUEST["rrule"] ) ) {
  1571.                 $error = true;
  1572.                 $message = 'Recurrence rule cannot be empty!';
  1573.             } else {
  1574.                 // convert rrule to text
  1575.                 $message = $this->rrule_to_text( $_REQUEST["rrule"] );
  1576.             }
  1577.  
  1578.         } else {
  1579.             $error = true;
  1580.             $message = 'Recurrence rule is not provided!';
  1581.         }
  1582.  
  1583.         $output = array(
  1584.             "error"     => $error,
  1585.             "message"   => stripslashes( $message )
  1586.         );
  1587.  
  1588.         echo json_encode( $output );
  1589.         exit();
  1590.     }
  1591.  
  1592.     /**
  1593.      * post_type_link function
  1594.      *
  1595.      *
  1596.      *
  1597.      * @return void
  1598.      **/
  1599.     function post_type_link( $permalink, $post, $leavename ) {
  1600.         global $calp_app_helper, $calp_settings, $calp_calendar_helper;
  1601.         if( $post->post_type == CALP_POST_TYPE ) {
  1602.             $page_url = get_permalink( $calp_settings->calendar_page_id );
  1603.            
  1604.             $event = $calp_calendar_helper->get_event_by_postid( $post->ID );
  1605.             $instance = isset($event->instance_id)?$event->instance_id:0;
  1606.            
  1607.             return $page_url .  '#action=calp_agenda&calp_item_id='. $instance;
  1608.         }
  1609.  
  1610.         return $permalink;
  1611.     }
  1612.  
  1613.     /**
  1614.      * get_week_start_day_offset function
  1615.      *
  1616.      * Returns the day offset of the first day of the week given a weekday in
  1617.      * question.
  1618.      *
  1619.      * @param int $wday      The weekday to get information about
  1620.      * @return int           A value between -6 and 0 indicating the week start
  1621.      *                       day relative to the given weekday.
  1622.      */
  1623.     function get_week_start_day_offset( $wday ) {
  1624.         global $calp_settings;
  1625.  
  1626.         return - ( 7 - ( $calp_settings->week_start_day - $wday ) ) % 7;
  1627.     }
  1628.      
  1629.     /**
  1630.      * get_month_weeks function
  1631.      *
  1632.      * Returns the month offset.
  1633.      *
  1634.      * @param $timestamp     timestamp (GMT)
  1635.      * @param $offset        Current day offset
  1636.      * @return array         An array of month days with their offset
  1637.      *                       day relative to the given weekday.
  1638.      */
  1639.     function get_month_weeks( $timestamp, $offset ) {
  1640.         global $calp_settings, $calp_events_helper;
  1641.         // days in month
  1642.         $first_timestamp = $calp_events_helper->gmgetdate( gmmktime( 0, 0, 0, gmdate( 'm', $timestamp ), 1, gmdate( 'Y', $timestamp ) ) );
  1643.         $last_day = gmdate( 't', $timestamp );
  1644.         $current_date = gmdate( 'd', $timestamp );
  1645.        // Figure out index of first table cell
  1646.         $first_cell_index = $first_timestamp['wday'];
  1647.         // Modify weekday based on start of week setting
  1648.         $first_cell_index = ( 7 + $first_cell_index - $calp_settings->week_start_day ) % 7;
  1649.         // Get the last day of the month
  1650.         $last_day = gmdate( 't', $timestamp );
  1651.        
  1652.         $weeks = array();
  1653.         $week = 0;
  1654.         $weeks[$week] = array();
  1655.        
  1656.         // Insert any needed blank cells into first week
  1657.         for( $i = 0; $i < $first_cell_index; $i++ ) {
  1658.             $weeks[$week][] = array( 'date' => null );
  1659.         }
  1660.        
  1661.         // Insert each month's day with offset
  1662.         for( $i = 1; $i <= $last_day; $i++ ) {
  1663.             $weeks[$week][] = array(
  1664.                 'date'   => $i,
  1665.                 'today'  => $i == $current_date,
  1666.                 'offset' => $i - $current_date + $offset
  1667.             );
  1668.             // If reached the end of the week, increment week
  1669.             if( count( $weeks[$week] ) == 7 )
  1670.                 $week++;
  1671.         }
  1672.        
  1673.         return $weeks;
  1674.     }
  1675.    
  1676.     /**
  1677.       * check_event_update function
  1678.       * @param object   $event                  New event
  1679.       * @param int      $recurrence_start       Start time of recurring event from the seria
  1680.       * @param bool     $ics                    IS ICS import or not
  1681.       *
  1682.       * @return void
  1683.     **/
  1684.     public function remove_recurring_instance($event, $recurrence_start)
  1685.     {
  1686.         global $wpdb, $calp_settings;
  1687.  
  1688.         $table_name = $wpdb->prefix . 'calp_events';
  1689.         $query = "SELECT post_id FROM {$table_name} " .
  1690.             "WHERE ical_feed_url = %s " .
  1691.             "AND ical_uid = %s " .
  1692.             "AND ( recurrence_rules IS NOT NULL AND recurrence_rules != '' )";
  1693.         $args = array( $event->ical_feed_url, $event->ical_uid );
  1694.         $post_id = $wpdb->get_var( $wpdb->prepare( $query, $args ) );
  1695.         if ( !empty($post_id) ) {
  1696.             $table_name = $wpdb->prefix . 'calp_event_instances';
  1697.             $query = "DELETE FROM {$table_name} " .
  1698.             "WHERE post_id = %d " .
  1699.             "AND start = FROM_UNIXTIME( %d ) ";
  1700.             $args = array( $post_id, $recurrence_start );
  1701.             $wpdb->query($wpdb->prepare( $query, $args ));
  1702.         }
  1703.        
  1704.     }
  1705.    
  1706. }
  1707. // END class
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement