/**
  * Register a license for status checks.
  *
  * @access public
  * @since  8.5.28
  *
  * @param string $file The full path and filename of the file.
  * @param array  $data {
  *     @type int    $item_id   The plugin ID.
  *                             Optional if $item_name provided otherwise it is required.
  *     @type string $item_name The plugin name exactly as in the store.
  *                             Optional if the $item_id is provided otherwise it is required.
  *     @type string $author    The plugin author name.
  *     @type string $version   The current plugin version; not, the latest version.
  *                             Required.
  *     @type string $license   The license key. Optional.
  * }
  *
  * @return bool|WP_Error  TRUE on success, WP_Error on failure.
  */
 public static function register($file, array $data)
 {
     $defaults = array('item_id' => 0, 'item_name' => '', 'author' => '', 'version' => '', 'license' => '');
     $plugin = cnSanitize::args($data, $defaults);
     if (empty($plugin['item_name']) && empty($plugin['item_id'])) {
         return new WP_Error('plugin_id_or_name_not_provided', esc_html__('Plugin name or ID is required.', 'connections'), $plugin);
     }
     if (empty($plugin['version'])) {
         return new WP_Error('plugin_version_not_provided', esc_html__('Plugin version is required.', 'connections'), $plugin);
     }
     //$plugin['file']     = $file;
     $plugin['basename'] = plugin_basename($file);
     //$plugin['slug']     = basename( $file, '.php' );
     $plugin['slug'] = self::get_slug($plugin['item_name']);
     $plugin['item_id'] = absint($plugin['item_id']);
     self::$licenses[$plugin['basename']] = $plugin;
     return TRUE;
 }
 /**
  * Callback function to sanitize the image settings.
  *
  * @access private
  * @since  0.7.7
  *
  * @param array $settings
  *
  * @return array
  */
 public static function sanitizeImageSettings($settings)
 {
     $defaults = array('quality' => 80, 'height' => 150, 'width' => 225, 'ratio' => 'crop');
     $settings = cnSanitize::args($settings, $defaults);
     // Ensure positive int values
     $settings['quality'] = absint($settings['quality']);
     $settings['height'] = absint($settings['height']);
     $settings['width'] = absint($settings['width']);
     // If the values is empty, set a default.
     $settings['quality'] = empty($settings['quality']) ? 80 : $settings['quality'];
     $settings['height'] = empty($settings['height']) ? 150 : $settings['height'];
     $settings['width'] = empty($settings['width']) ? 225 : $settings['width'];
     // The valid ratio options
     $ratio = array('crop', 'fill', 'fit', 'none');
     // Make sure the value is one of the permitted options and if it is not, set it to the 'crop' value.
     $settings['ratio'] = in_array($settings['ratio'], $ratio) ? $settings['ratio'] : 'crop';
     return $settings;
 }
 /**
  * Email the system info.
  *
  * @access private
  * @since  8.3
  * @static
  *
  * @uses   add_filter()
  * @uses   cnEmail()
  * @uses   sanitize_email()
  * @uses   sanitize_text_field()
  * @uses   esc_html()
  * @uses   cnSystem_Info::get()
  * @uses   remove_filter()
  *
  * @param array $atts {
  *     @type string $from_email The "from" email address.
  *     @type string $from_name  The "from" name.
  *     @type string $to_email   The "to" email address.
  *     @type string $to_name    The "to" name.
  *     @type string $subject    The email subject.
  *     @type string $message    The message to precede the system info.
  * }
  *
  * @return bool
  */
 public static function email($atts)
 {
     $defaults = array('from_email' => '', 'from_name' => '', 'to_name' => '', 'to_email' => '', 'subject' => '', 'message' => '');
     $atts = cnSanitize::args($atts, $defaults);
     $email = new cnEmail();
     // Set email to be sent as HTML.
     $email->HTML();
     // Set from whom.
     $email->from(sanitize_email($atts['from_email']), sanitize_text_field($atts['from_name']));
     // Set to whom.
     $email->to(sanitize_email($atts['to_email']));
     // Set the subject.
     $email->subject(sanitize_text_field($atts['subject']));
     $message = sanitize_text_field($atts['message']);
     $message .= PHP_EOL . PHP_EOL;
     $message .= '<pre>' . esc_html(self::get()) . '</pre>';
     // Set the message.
     $email->message($message);
     add_filter('cn_email_header', array(__CLASS__, 'setEmailHeader'));
     $response = $email->send();
     remove_filter('cn_email_header', array(__CLASS__, 'setEmailHeader'));
     return $response;
 }
 /**
  * Retrieve category parents with separator.
  *
  * NOTE: This is the Connections equivalent of @see get_category_parents() in WordPress core ../wp-includes/category-template.php
  *
  * @access public
  * @since  8.5.18
  * @static
  *
  * @param int    $id        Category ID.
  * @param array  $atts      The attributes array. {
  *
  *     @type bool   $link       Whether to format as link or as a string.
  *                              Default: FALSE
  *     @type string $separator  How to separate categories.
  *                              Default: '/'
  *     @type bool   $nicename   Whether to use nice name for display.
  *                              Default: FALSE
  *     @type array  $visited    Already linked to categories to prevent duplicates.
  *                              Default: array()
  *     @type bool   $force_home Default: FALSE
  *     @type int    $home_id    Default: The page set as the directory home page.
  * }
  *
  * @return string|WP_Error A list of category parents on success, WP_Error on failure.
  */
 public static function getCategoryParents($id, $atts = array())
 {
     $defaults = array('link' => FALSE, 'separator' => '/', 'nicename' => FALSE, 'visited' => array(), 'force_home' => FALSE, 'home_id' => cnSettingsAPI::get('connections', 'connections_home_page', 'page_id'));
     $atts = cnSanitize::args($atts, $defaults);
     $chain = '';
     $parent = cnTerm::get($id, 'category');
     if (is_wp_error($parent)) {
         return $parent;
     }
     if ($atts['nicename']) {
         $name = $parent->slug;
     } else {
         $name = $parent->name;
     }
     if ($parent->parent && $parent->parent != $parent->term_id && !in_array($parent->parent, $atts['visited'])) {
         $atts['visited'][] = $parent->parent;
         $chain .= self::getCategoryParents($parent->parent, $atts);
     }
     if ($atts['link']) {
         $chain .= '<a href="' . esc_url(cnTerm::permalink($parent->term_id, 'category', $atts)) . '">' . $name . '</a>' . $atts['separator'];
     } else {
         $chain .= $name . esc_html($atts['separator']);
     }
     return $chain;
 }
 /**
  * @access public
  * @since  8.5.15
  *
  * @global wpdb $wpdb
  *
  * @param array  $atts
  *
  * @return string
  */
 public static function where($atts = array())
 {
     global $wpdb;
     $defaults = array('table' => CN_ENTRY_TABLE, 'field' => '', 'value' => '', 'format' => '%s', 'relation' => 'AND', 'delimiter' => '|');
     $atts = cnSanitize::args($atts, $defaults);
     $where = '';
     $atts['relation'] = in_array($atts['relation'], array('AND', 'OR')) ? strtoupper($atts['relation']) : 'AND';
     if (0 < strlen($atts['field']) && 0 < count($atts['value'])) {
         $value = cnFunction::parseStringList($atts['value'], $atts['delimiter']);
         $count = count($value);
         if (1 < $count) {
             $where = $atts['relation'] . ' ' . $atts['table'] . '.' . $atts['field'] . ' ' . self::in($value, $atts['format']);
         } elseif (1 == $count) {
             $where = $wpdb->prepare($atts['relation'] . ' ' . $atts['table'] . '.' . $atts['field'] . ' = ' . $atts['format'], $value);
         }
     }
     return $where;
 }
 /**
  * Set up the options.
  *
  * @access public
  * @since  8.2.5
  *
  * @param array $atts
  */
 public function __construct($atts = array())
 {
     $defaults = array('url' => 'connections-pro.com', 'width' => 200, 'link' => TRUE, 'title' => '', 'alt' => '', 'target' => '', 'follow' => FALSE, 'before' => '', 'after' => '', 'return' => FALSE);
     $atts = cnSanitize::args($atts, $defaults);
     $validTargets = array('_blank', '_self', '_parent', '_top');
     $this->setURL($atts['url']);
     $this->setWidth($atts['width']);
     $this->link = is_bool($atts['link']) ? $atts['link'] : TRUE;
     $this->setTitle($atts['title']);
     $this->setAlt($atts['alt']);
     $this->follow = is_bool($atts['follow']) ? $atts['follow'] : FALSE;
     $this->target = in_array($atts['target'], $validTargets) ? $atts['target'] : '_blank';
     $this->before = is_string($atts['before']) && 0 < strlen($atts['before']) ? $atts['before'] : '';
     $this->after = is_string($atts['after']) && 0 < strlen($atts['after']) ? $atts['after'] : '';
     $this->return = is_bool($atts['return']) ? $atts['return'] : FALSE;
 }
 /**
  * Returns an indexed array of objects the addresses per the defined options.
  *
  * @param $atts {
  *     @type string       $fields    The fields to return.
  *                                   Default: all
  *                                   Accepts: all, ids, locality, regions, postal-code, country
  *     @type int          $id        The entry ID in which to retrieve the addresses for.
  *     @type bool         $preferred Whether or not to return only the preferred address.
  *                                   Default: false
  *     @type array|string $type      The address types to return.
  *                                   Default: array() which will return all registered address types.
  *                                   Accepts: home, work, school, other and any other registered types.
  *     @type array|string $city      Return address in the defined cities.
  *     @type array|string $state     Return address in the defined states.
  *     @type array|string $country   Return address in the defined countries.
  *     @type array        $coordinates {
  *         Return the addresses at the specific coordinates.
  *         @type float $latitude
  *         @type float $longitude
  *     }
  * }
  *
  * @return array
  */
 public function addresses($atts = array())
 {
     /** @var wpdb $wpdb */
     global $wpdb;
     $where = array('WHERE 1=1');
     /*
      * // START -- Set the default attributes array. \\
      */
     $defaults = array('fields' => 'all', 'id' => NULL, 'preferred' => FALSE, 'type' => array(), 'city' => array(), 'state' => array(), 'zipcode' => array(), 'country' => array(), 'coordinates' => array(), 'limit' => NULL);
     $atts = cnSanitize::args($atts, $defaults);
     /*
      * // END -- Set the default attributes array if not supplied. \\
      */
     /**
      * @var int          $id
      * @var bool         $preferred
      * @var array|string $type
      * @var array|string $city
      * @var array|string $state
      * @var array|string $zipcode
      * @var array|string $country
      * @var array        $coordinates
      * @var null|int     $limit
      */
     extract($atts);
     /*
      * Convert these to values to an array if they were supplied as a comma delimited string
      */
     /** @var array $type */
     cnFunction::parseStringList($type);
     /** @var array $city */
     cnFunction::parseStringList($city);
     /** @var array $state */
     cnFunction::parseStringList($state);
     /** @var array $zipcode */
     cnFunction::parseStringList($zipcode);
     /** @var array $country */
     cnFunction::parseStringList($country);
     switch ($atts['fields']) {
         case 'ids':
             $select = array('a.id', 'a.entry_id');
             break;
         case 'locality':
             $select = array('a.city');
             break;
         case 'region':
             $select = array('a.state');
             break;
         case 'postal-code':
             $select = array('a.zipcode');
             break;
         case 'country':
             $select = array('a.country');
             break;
         default:
             $select = array('a.*');
     }
     if (!empty($id)) {
         $where[] = $wpdb->prepare('AND `entry_id` = %d', $id);
     }
     if (!empty($preferred)) {
         $where[] = $wpdb->prepare('AND `preferred` = %d', (bool) $preferred);
     }
     if (!empty($type)) {
         $where[] = $wpdb->prepare('AND `type` IN (' . cnFormatting::prepareINPlaceholders($type) . ')', $type);
     }
     if (!empty($city)) {
         $where[] = $wpdb->prepare('AND `city` IN (' . cnFormatting::prepareINPlaceholders($city) . ')', $city);
     }
     if (!empty($state)) {
         $where[] = $wpdb->prepare('AND `state` IN (' . cnFormatting::prepareINPlaceholders($state) . ')', $state);
     }
     if (!empty($zipcode)) {
         $where[] = $wpdb->prepare('AND `zipcode` IN (' . cnFormatting::prepareINPlaceholders($zipcode) . ')', $zipcode);
     }
     if (!empty($country)) {
         $where[] = $wpdb->prepare('AND `country` IN (' . cnFormatting::prepareINPlaceholders($country) . ')', $country);
     }
     if (!empty($coordinates)) {
         if (!empty($coordinates['latitude']) && !empty($coordinates['longitude'])) {
             $where[] = $wpdb->prepare('AND `latitude` = %f', $coordinates['latitude']);
             $where[] = $wpdb->prepare('AND `longitude` = %f', $coordinates['longitude']);
         }
     }
     // Limit the characters that are queried based on if the current user can view public, private or unlisted entries.
     $where = self::setQueryVisibility($where, array('table' => 'a'));
     $limit = is_null($atts['limit']) ? '' : sprintf(' LIMIT %d', $atts['limit']);
     $sql = sprintf('SELECT %1$s FROM %2$s AS a %3$s ORDER BY `order`%4$s', implode(', ', $select), CN_ENTRY_ADDRESS_TABLE, implode(' ', $where), $limit);
     $results = $wpdb->get_results($sql);
     return $results;
 }
 /**
  * Displays the category list in a HTML list or custom format
  *
  * @TODO: Implement $parents.
  *
  * Accepted option for the $atts property are:
  *   list == string -- The list type to output. Accepted values are ordered || unordered.
  *   separator == string -- The category separator.
  *   before == string -- HTML to output before the category list.
  *   after == string -- HTML to output after the category list.
  *   label == string -- String to display after the before attribute but before the category list.
  *   parents == bool -- Display the parents
  *   return == TRUE || FALSE -- Return string if set to TRUE instead of echo string.
  *
  * @access public
  * @since  unknown
  *
  * @param array $atts
  *
  * @return string
  */
 public function getCategoryBlock($atts = array())
 {
     $defaults = array('list' => 'unordered', 'separator' => NULL, 'before' => '', 'after' => '', 'label' => __('Categories:', 'connections') . ' ', 'parents' => FALSE, 'return' => FALSE);
     $defaults = apply_filters('cn_output_default_atts_category', $defaults);
     $atts = cnSanitize::args($atts, $defaults);
     $out = '';
     $categories = $this->getCategory();
     if (empty($categories)) {
         return $out;
     }
     $out .= '<div class="cn-categories">';
     $out .= $atts['before'];
     if (!empty($atts['label'])) {
         $out .= '<span class="cn_category_label">' . $atts['label'] . '</span> ';
     }
     if (is_null($atts['separator'])) {
         $out .= $atts['list'] === 'unordered' ? '<ul class="cn_category_list">' : '<ol class="cn_category_list">';
         foreach ($categories as $category) {
             $out .= '<li class="cn_category" id="cn_category_' . $category->term_id . '">' . $category->name . '</li>';
         }
         $out .= $atts['list'] === 'unordered' ? '</ul>' : '</ol>';
     } else {
         $count = count($categories);
         $i = 1;
         foreach ($categories as $category) {
             // The `cn_category` class is named with an underscore for backward compatibility.
             $out .= sprintf('<span class="cn-category-name cn_category" id="cn-category-%1$d">%2$s%3$s</span>', $category->term_id, esc_html($category->name), $count > $i++ && !is_null($atts['separator']) ? $atts['separator'] : '');
         }
     }
     $out .= $atts['after'];
     $out .= '</div>';
     return $this->echoOrReturn($atts['return'], $out);
 }
 /**
  * Displays the category list in a HTML list or custom format
  *
  * @TODO: Implement $parents.
  *
  * Accepted option for the $atts property are:
  *   list == string -- The list type to output. Accepted values are ordered || unordered.
  *   separator == string -- The category separator.
  *   before == string -- HTML to output before the category list.
  *   after == string -- HTML to output after the category list.
  *   label == string -- String to display after the before attribute but before the category list.
  *   parents == bool -- Display the parents
  *   return == TRUE || FALSE -- Return string if set to TRUE instead of echo string.
  *
  * @access public
  * @since  unknown
  *
  * @param array $atts
  *
  * @return string
  */
 public function getCategoryBlock($atts = array())
 {
     $defaults = array('list' => 'unordered', 'separator' => NULL, 'before' => '', 'after' => '', 'label' => __('Categories:', 'connections') . ' ', 'parents' => FALSE, 'return' => FALSE);
     $defaults = apply_filters('cn_output_default_atts_category', $defaults);
     $atts = cnSanitize::args($atts, $defaults);
     $out = '';
     $categories = $this->getCategory();
     if (empty($categories)) {
         return $out;
     }
     $out .= $atts['before'];
     if (!empty($atts['label'])) {
         $out .= '<span class="cn_category_label">' . $atts['label'] . '</span>';
     }
     if (empty($atts['separator'])) {
         $atts['list'] === 'unordered' ? $out .= '<ul class="cn_category_list">' : ($out .= '<ol class="cn_category_list">');
         foreach ($categories as $category) {
             $out .= '<li class="cn_category" id="cn_category_' . $category->term_id . '">' . $category->name . '</li>';
         }
         $atts['list'] === 'unordered' ? $out .= '</ul>' : ($out .= '</ol>');
     } else {
         $i = 1;
         foreach ($categories as $category) {
             $out .= '<span class="cn_category" id="cn_category_' . $category->term_id . '">' . $category->name . (count($categories) > $i++ && !empty($atts['separator']) ? $atts['separator'] : '') . '</span>';
         }
     }
     $out .= $atts['after'];
     return $this->echoOrReturn($atts['return'], $out);
 }
 /**
  * Caches the dates for use and preps for saving and updating.
  *
  * Valid values as follows.
  *
  * $date['id'] (int) Stores the date ID if it was retrieved from the db.
  * $date['preferred'] (bool) If the date is the preferred date or not.
  * $date['type'] (string) Stores the date type.
  * $date['date'] (string) Stores date.
  * $date['visibility'] (string) Stores the date visibility.
  *
  * @TODO Consider using strtotime on $date['date'] to help ensure date_create() does not return FALSE.
  *
  * @access public
  * @since 0.7.3
  * @version 1.0
  * @param array   $dates
  * @return void
  */
 public function setDates($dates)
 {
     $userPreferred = NULL;
     /*
      * These will be used to store the first anniversary and birthday entered by the user.
      */
     $anniversary = array();
     $birthday = array();
     $validFields = array('id' => NULL, 'preferred' => NULL, 'type' => NULL, 'date' => NULL, 'visibility' => NULL);
     if (!empty($dates)) {
         $order = 0;
         $preferred = '';
         if (isset($dates['preferred'])) {
             $preferred = $dates['preferred'];
             unset($dates['preferred']);
         }
         foreach ($dates as $key => $date) {
             // First validate the supplied data.
             $date = cnSanitize::args($date, $validFields);
             // If the date is empty, no need to store it.
             if (empty($date['date'])) {
                 unset($dates[$key]);
                 continue;
             }
             // Store the order attribute as supplied in the date array.
             $dates[$key]['order'] = $order;
             isset($preferred) && $preferred == $key ? $dates[$key]['preferred'] = TRUE : ($dates[$key]['preferred'] = FALSE);
             /*
              * If the user set a preferred date, save the $key value.
              * This is going to be needed because if a date that the user
              * does not have permission to edit is set to preferred, that date
              * will have preference.
              */
             if ($dates[$key]['preferred']) {
                 $userPreferred = $key;
             }
             /*
              * Format the supplied date correctly for the table column:  YYYY-MM-DD
              * @TODO Consider using strtotime on $date['date'] to help ensure date_create() does not return FALSE.
              */
             $currentDate = date_create($date['date']);
             /*
              * Make sure the date object created correctly.
              */
             if (FALSE === $currentDate) {
                 continue;
             }
             $dates[$key]['date'] = date_format($currentDate, 'Y-m-d');
             /*
              * Check to see if the date is an anniversary or birthday and store them.
              * These will then be sent and saved using the legacy methods for backward compatibility
              * with version 0.7.2.6 and older.
              */
             switch ($date['type']) {
                 case 'anniversary':
                     if (empty($anniversary)) {
                         $anniversary['month'] = date_format($currentDate, 'm');
                         $anniversary['day'] = date_format($currentDate, 'd');
                         $this->setAnniversary($anniversary['day'], $anniversary['month']);
                     }
                     break;
                 case 'birthday':
                     if (empty($birthday)) {
                         $birthday['month'] = date_format($currentDate, 'm');
                         $birthday['day'] = date_format($currentDate, 'd');
                         $this->setBirthday($birthday['day'], $birthday['month']);
                     }
                     break;
             }
             $order++;
         }
     }
     /*
      * If no anniversary or birthday date types were set, ensure the dates stored are emptied
      * for backward compatibility with version 0.7.2.6 and older.
      */
     if (empty($anniversary)) {
         $this->anniversary = '';
     }
     if (empty($birthday)) {
         $this->birthday = '';
     }
     /*
      * Before storing the data, add back into the array from the cache the dates
      * the user may not have had permission to edit so the cache stays current.
      */
     $cached = unserialize($this->dates);
     if (!empty($cached)) {
         foreach ($cached as $date) {
             /*
              * // START -- Compatibility for previous versions.
              */
             if (!isset($date['visibility']) || empty($date['visibility'])) {
                 $date['visibility'] = 'public';
             }
             /*
              * // END -- Compatibility for previous versions.
              */
             /** This filter is documented in ../includes/entry/class.entry-data.php */
             $date = apply_filters('cn_date-pre_setup', $date);
             if (!$this->validate->userPermitted($date['visibility'])) {
                 //$dates[] = $date;
                 // If the date is preferred, it takes precedence, so the user's choice is overridden.
                 if (!empty($preferred) && $date['preferred']) {
                     $dates[$userPreferred]['preferred'] = FALSE;
                     // Throw the user a message so they know why their choice was overridden.
                     cnMessage::set('error', 'entry_preferred_overridden_date');
                 }
             }
         }
     }
     $this->dates = !empty($dates) ? serialize($dates) : '';
 }
 /**
  * Total record count based on current user permissions.
  *
  * @access public
  * @since  unknown
  *
  * @global $wpdb
  * @global $connections
  *
  * @uses   wp_parse_args()
  * @uses   is_user_logged_in()
  * @uses   current_user_can()
  * @uses   $wpdb->get_var()
  *
  * @param  (array)
  *
  * @return int
  */
 public static function recordCount($atts)
 {
     /**  @var wpdb $wpdb */
     global $wpdb;
     $where[] = 'WHERE 1=1';
     $defaults = array('public_override' => TRUE, 'private_override' => TRUE, 'status' => array());
     $atts = cnSanitize::args($atts, $defaults);
     $where = self::setQueryVisibility($where, $atts);
     $where = self::setQueryStatus($where, $atts);
     $results = $wpdb->get_var('SELECT COUNT(`id`) FROM ' . CN_ENTRY_TABLE . ' ' . implode(' ', $where));
     return !empty($results) ? $results : 0;
 }
 /**
  * Generates a permalink for a taxonomy term.
  *
  * Filters:
  *    cn_term_link
  *        Passes: (string) $link, (object) $term, (string) $taxonomy
  *        Return: $link
  *
  * NOTE: This is the Connections equivalent of get_term_link() in WordPress core ../wp-includes/taxonomy.php
  *
  * @access public
  * @since  8.1.6
  * @static
  *
  * @uses   cnTerm::get()
  * @uses   cnTerm::getBy()
  * @uses   is_wp_error()
  * @uses   cnTerm::getAncestors()
  * @uses   cnURL::permalink()
  * @uses   apply_filters()
  *
  * @param object|int|string $term
  * @param string            $taxonomy (optional if $term is object)
  * @param array             $atts
  *
  * @return string|WP_Error URL  to taxonomy term on success, WP_Error if term does not exist.
  */
 public static function permalink($term, $taxonomy = '', $atts = array())
 {
     /** @var $wp_rewrite WP_Rewrite */
     //global $wp_rewrite;
     $defaults = array('force_home' => FALSE, 'home_id' => cnSettingsAPI::get('connections', 'connections_home_page', 'page_id'));
     $atts = cnSanitize::args($atts, $defaults);
     if (!is_object($term)) {
         if (is_int($term)) {
             $term = self::get($term, $taxonomy);
         } else {
             $term = self::getBy('slug', $term, $taxonomy);
         }
     }
     if (!is_object($term)) {
         $term = new WP_Error('invalid_term', __('Empty Term', 'connections'));
     }
     if (is_wp_error($term)) {
         return $term;
     }
     $taxonomy = $term->taxonomy;
     //$link = $wp_rewrite->get_extra_permastruct( $taxonomy );
     //$slug = $term->slug;
     //$t    = get_taxonomy( $taxonomy );
     //if ( empty( $link ) ) {
     //if ( 'category' == $taxonomy ) {
     //$link = '?cat=' . $term->term_id;
     //} elseif ( $t->query_var ) {
     //
     //	$term_link = "?$t->query_var=$slug";
     //} else {
     //	$link = "?taxonomy=$taxonomy&term=$slug";
     //}
     //$link = home_url( $link );
     //} else {
     //if ( $t->rewrite['hierarchical'] ) {
     $slugs = array();
     $ancestors = self::getAncestors($term->term_id, $taxonomy);
     foreach ((array) $ancestors as $ancestor) {
         $ancestor_term = self::get($ancestor, $taxonomy);
         $slugs[] = $ancestor_term->slug;
     }
     $slugs = array_reverse($slugs);
     $slugs[] = $term->slug;
     $link = cnURL::permalink(array('type' => 'category', 'slug' => implode('/', $slugs), 'title' => $term->name, 'text' => $term->name, 'data' => 'url', 'force_home' => $atts['force_home'], 'home_id' => $atts['home_id'], 'return' => TRUE));
     //} else {
     //
     //	$term_link = str_replace( "%$taxonomy%", $slug, $term_link );
     //}
     //$link = home_url( user_trailingslashit( $link, 'category' ) );
     //}
     /**
      * Filter the term link.
      *
      * @since 8.1.6
      *
      * @param string $link Term link URL.
      * @param object $term     Term object.
      * @param string $taxonomy Taxonomy slug.
      */
     return apply_filters('cn_term_link', $link, $term, $taxonomy);
 }
 /**
  * Displays the category list in a HTML list or custom format.
  *
  * NOTE: This is the Connections equivalent of @see get_the_category_list() in WordPress core ../wp-includes/category-template.php
  *
  * @access public
  * @since  unknown
  *
  * @param array $atts {
  * Optional. An array of arguments.
  *
  *     @type string $container_tag    The HTML tag to be used for the container element.
  *                                    Default: div
  *     @type string $label_tag        The HTML tag to be used for the category label element.
  *                                    Default: span
  *     @type string $item_tag         The HTML tag to be used for the category element.
  *                                    Default: span
  *     @type string $type             The display type to be used to display the categories.
  *                                    Accepts: block|list
  *                                    Default: block
  *     @type string $list             If the $type is list, which type?
  *                                    Accepts: ordered|unordered
  *                                    Default: unordered
  *     @type string $label            The label to be displayed before the categories.
  *                                    Default: Categories:
  *     @type string $separator        The category separator used when separating categories when $type == list
  *                                    Default: ', '
  *     @type string $parent_separator The separator to be used when displaying the category's hierarchy.
  *                                    Default: ' &raquo; '
  *     @type string $before           String content to display before the categories.
  *     @type string $after            String content to display after the categories.
  *     @type bool   $link             Whether or not render the categories as permalinks.
  *                                    Default: false
  *     @type bool   $parents          Whether or not to display the category hierarchy.
  *                                    Default: false
  *     @type bool   $return           Whether or not to echo or return the HTML.
  *                                    Default: false
  * }
  *
  * @return string
  */
 public function getCategoryBlock($atts = array())
 {
     global $wp_rewrite;
     $defaults = array('container_tag' => 'div', 'label_tag' => 'span', 'item_tag' => 'span', 'type' => 'block', 'list' => 'unordered', 'label' => __('Categories:', 'connections') . ' ', 'separator' => ', ', 'parent_separator' => ' &raquo; ', 'before' => '', 'after' => '', 'link' => FALSE, 'parents' => FALSE, 'return' => FALSE);
     /**
      * All extensions to filter the method default and supplied args.
      *
      * @since 8.5.18
      */
     $atts = cnSanitize::args(apply_filters('cn_output_atts_category', $atts), apply_filters('cn_output_default_atts_category', $defaults));
     $categories = $this->getCategory();
     $count = count($categories);
     $html = '';
     $label = '';
     $items = array();
     if (empty($categories)) {
         return $html;
     }
     if ('list' == $atts['type']) {
         $atts['item_tag'] = 'li';
     }
     if (0 < strlen($atts['label'])) {
         $label = sprintf('<%1$s class="cn_category_label">%2$s</%1$s> ', $atts['label_tag'], esc_html($atts['label']));
     }
     $i = 1;
     foreach ($categories as $category) {
         $text = '';
         if ($atts['parents']) {
             // If the term is a root parent, skip.
             if (0 !== $category->parent) {
                 $text .= cnTemplatePart::getCategoryParents($category->parent, array('link' => $atts['link'], 'separator' => $atts['parent_separator'], 'force_home' => $this->directoryHome['force_home'], 'home_id' => $this->directoryHome['page_id']));
             }
         }
         if ($atts['link']) {
             $rel = is_object($wp_rewrite) && $wp_rewrite->using_permalinks() ? 'rel="category tag"' : 'rel="category"';
             $url = cnTerm::permalink($category, 'category', array('force_home' => $this->directoryHome['force_home'], 'home_id' => $this->directoryHome['page_id']));
             $text .= '<a href="' . $url . '" ' . $rel . '>' . esc_html($category->name) . '</a>';
         } else {
             $text .= esc_html($category->name);
         }
         $items[] = apply_filters('cn_entry_output_category_item', sprintf('<%1$s class="cn-category-name cn_category cn-category-%2$d">%3$s%4$s</%1$s>', $atts['item_tag'], $category->term_id, $text, $count > $i && 'list' !== $atts['type'] ? esc_html($atts['separator']) : ''), $category, $count, $i, $atts, $this);
         $i++;
         // Increment here so the correct value is passed to the filter.
     }
     /*
      * Remove NULL, FALSE and empty strings (""), but leave values of 0 (zero).
      * Filter our these in case someone hooks into the `cn_entry_output_category_item` filter and removes a category
      * by returning an empty value.
      */
     $items = array_filter($items, 'strlen');
     if ('list' == $atts['type']) {
         $html .= sprintf('<%1$s class="cn-category-list">%2$s</%1$s>', 'unordered' === $atts['list'] ? 'ul' : 'ol', implode('', $items));
     } else {
         $html .= implode('', $items);
     }
     $html = apply_filters('cn_entry_output_category_container', sprintf('<%1$s class="cn-categories">%2$s</%1$s>' . PHP_EOL, $atts['container_tag'], $atts['before'] . $label . $html . $atts['after']), $atts);
     return $this->echoOrReturn($atts['return'], $html);
 }
/**
 * Display the upcoming list.
 *
 * @access public
 * @since  unknown
 *
 * @param array  $atts
 * @param string $content [optional]
 * @param string $tag     [optional] When called as the callback for add_shortcode, the shortcode tag is passed
 *                        automatically. Manually setting the shortcode tag so the function can be called
 *                        independently.
 *
 * @return string
 */
function _upcoming_list($atts, $content = NULL, $tag = 'upcoming_list')
{
    global $connections, $wpdb;
    // $template =& $connections->template;
    $out = '';
    $alternate = '';
    $templateTypeDefaults = array('list_type' => 'birthday', 'template' => NULL);
    $templateType = cnSanitize::args($atts, $templateTypeDefaults);
    /*
     * If a list type was specified in the shortcode, load the template based on that type.
     * However, if a specific template was specified, that should preempt the template to be loaded based on the list type if it was specified..
     */
    if (!empty($atts['template'])) {
        $template = cnTemplateFactory::getTemplate($templateType['template']);
    } else {
        $templateSlug = $connections->options->getActiveTemplate($templateType['list_type']);
        $template = cnTemplateFactory::getTemplate($templateSlug);
    }
    // No template found return error message.
    if ($template === FALSE) {
        return cnTemplatePart::loadTemplateError($templateType);
    }
    $defaults = array('list_type' => 'birthday', 'days' => '30', 'include_today' => TRUE, 'private_override' => FALSE, 'name_format' => '', 'date_format' => 'F jS', 'show_lastname' => FALSE, 'show_title' => TRUE, 'list_title' => NULL, 'template' => NULL, 'content' => '', 'force_home' => TRUE, 'home_id' => cnSettingsAPI::get('connections', 'home_page', 'page_id'));
    $defaults = apply_filters('cn_list_atts_permitted', $defaults);
    $defaults = apply_filters('cn_list_atts_permitted-' . $template->getSlug(), $defaults);
    $atts = shortcode_atts($defaults, $atts, $tag);
    $atts = apply_filters('cn_list_atts', $atts);
    $atts = apply_filters('cn_list_atts-' . $template->getSlug(), $atts);
    /*
     * Convert some of the $atts values in the array to boolean.
     */
    cnFormatting::toBoolean($atts['include_today']);
    cnFormatting::toBoolean($atts['private_override']);
    cnFormatting::toBoolean($atts['show_lastname']);
    cnFormatting::toBoolean($atts['repeat_alphaindex']);
    cnFormatting::toBoolean($atts['show_title']);
    if (0 == strlen($atts['name_format'])) {
        $atts['name_format'] = $atts['show_lastname'] ? '%first% %last%' : '%first%';
    }
    /** @var cnTemplate $template */
    do_action('cn_register_legacy_template_parts');
    do_action('cn_action_include_once-' . $template->getSlug());
    do_action('cn_action_js-' . $template->getSlug());
    /*
     * This filter adds the current template paths to cnLocate so when template
     * part file overrides are being searched for, it'll also search in template
     * specific paths. This filter is then removed at the end of the shortcode.
     */
    add_filter('cn_locate_file_paths', array($template, 'templatePaths'));
    cnShortcode::addFilterRegistry('cn_locate_file_paths');
    do_action('cn_template_include_once-' . $template->getSlug());
    do_action('cn_template_enqueue_js-' . $template->getSlug());
    /*
     * Set the query vars and run query.
     */
    // Show only public or private [if permitted] entries.
    if (is_user_logged_in() || $atts['private_override'] != FALSE) {
        $visibilityfilter = " AND (visibility='private' OR visibility='public') AND (" . $atts['list_type'] . " != '')";
    } else {
        $visibilityfilter = " AND (visibility='public') AND (`" . $atts['list_type'] . "` != '')";
    }
    // Get the current date from WP which should have the current time zone offset.
    $wpCurrentDate = date('Y-m-d', $connections->options->wpCurrentTime);
    // Whether or not to include the event occurring today or not.
    $atts['include_today'] ? $includeToday = '<=' : ($includeToday = '<');
    $newSQL = "SELECT * FROM " . CN_ENTRY_TABLE . " WHERE" . "  (YEAR(DATE_ADD('{$wpCurrentDate}', INTERVAL " . $atts['days'] . " DAY))" . " - YEAR(DATE_ADD(FROM_UNIXTIME(`" . $atts['list_type'] . "`), INTERVAL " . $connections->options->sqlTimeOffset . " SECOND)) )" . " - ( MID(DATE_ADD('{$wpCurrentDate}', INTERVAL " . $atts['days'] . " DAY),5,6)" . " < MID(DATE_ADD(FROM_UNIXTIME(`" . $atts['list_type'] . "`), INTERVAL " . $connections->options->sqlTimeOffset . " SECOND),5,6) )" . " > ( YEAR('{$wpCurrentDate}')" . " - YEAR(DATE_ADD(FROM_UNIXTIME(`" . $atts['list_type'] . "`), INTERVAL " . $connections->options->sqlTimeOffset . " SECOND)) )" . " - ( MID('{$wpCurrentDate}',5,6)" . " " . $includeToday . " MID(DATE_ADD(FROM_UNIXTIME(`" . $atts['list_type'] . "`), INTERVAL " . $connections->options->sqlTimeOffset . " SECOND),5,6) )" . $visibilityfilter;
    //$out .= print_r($newSQL , TRUE);
    $results = $wpdb->get_results($newSQL);
    //$out .= print_r($results , TRUE);
    // If there are no results no need to proceed and output message.
    if (empty($results)) {
        $noResultMessage = __('No results.', 'connections');
        $noResultMessage = apply_filters('cn_upcoming_no_result_message', $noResultMessage);
        $out .= '<p class="cn-upcoming-no-results">' . $noResultMessage . '</p>';
    } else {
        /*The SQL returns an array sorted by the birthday and/or anniversary date. However the year end wrap needs to be accounted for.
        		Otherwise earlier months of the year show before the later months in the year. Example Jan before Dec. The desired output is to show
        		Dec then Jan dates.  This function checks to see if the month is a month earlier than the current month. If it is the year is changed to the following year rather than the current.
        		After a new list is built, it is resorted based on the date.*/
        foreach ($results as $key => $row) {
            if (gmmktime(23, 59, 59, gmdate('m', $row->{$atts['list_type']}), gmdate('d', $row->{$atts['list_type']}), gmdate('Y', $connections->options->wpCurrentTime)) < $connections->options->wpCurrentTime) {
                $dateSort[] = $row->{$atts['list_type']} = gmmktime(0, 0, 0, gmdate('m', $row->{$atts['list_type']}), gmdate('d', $row->{$atts['list_type']}), gmdate('Y', $connections->options->wpCurrentTime) + 1);
            } else {
                $dateSort[] = $row->{$atts['list_type']} = gmmktime(0, 0, 0, gmdate('m', $row->{$atts['list_type']}), gmdate('d', $row->{$atts['list_type']}), gmdate('Y', $connections->options->wpCurrentTime));
            }
        }
        array_multisort($dateSort, SORT_ASC, $results);
        if (empty($atts['list_title'])) {
            switch ($atts['list_type']) {
                case 'birthday':
                    if ($atts['days'] >= 1) {
                        $list_title = 'Upcoming Birthdays the next ' . $atts['days'] . ' days';
                    } else {
                        $list_title = 'Today\'s Birthdays';
                    }
                    break;
                case 'anniversary':
                    if ($atts['days'] >= 1) {
                        $list_title = 'Upcoming Anniversaries the next ' . $atts['days'] . ' days';
                    } else {
                        $list_title = 'Today\'s Anniversaries';
                    }
                    break;
            }
        } else {
            $list_title = $atts['list_title'];
        }
        ob_start();
        // Prints the template's CSS file.
        do_action('cn_template_inline_css-' . $template->getSlug(), $atts);
        $out .= ob_get_contents();
        ob_end_clean();
        $out .= '<div class="connections-list cn-upcoming cn-' . $atts['list_type'] . '" id="cn-list" data-connections-version="' . $connections->options->getVersion() . '-' . $connections->options->getDBVersion() . '">' . "\n";
        $out .= "\n" . '<div class="cn-template cn-' . $template->getSlug() . '" id="cn-' . $template->getSlug() . '">' . "\n";
        $out .= "\n" . '<div class="cn-clear" id="cn-list-head">' . "\n";
        if ($atts['show_title']) {
            $out .= '<div class="cn-upcoming-title">' . $list_title . '</div>';
        }
        $out .= "\n" . '</div>' . "\n";
        $out .= '<div class="cn-clear" id="cn-list-body">' . "\n";
        foreach ($results as $row) {
            $entry = new cnvCard($row);
            $vCard =& $entry;
            // Configure the page where the entry link to.
            $entry->directoryHome(array('page_id' => $atts['home_id'], 'force_home' => $atts['force_home']));
            if (!$atts['show_lastname']) {
                $entry->setLastName('');
            }
            $entry->name = $entry->getName(array('format' => $atts['name_format']));
            $alternate == '' ? $alternate = '-alternate' : ($alternate = '');
            $out .= '<div class="cn-upcoming-row' . $alternate . ' vcard ' . '">' . "\n";
            ob_start();
            do_action('cn_action_card-' . $template->getSlug(), $entry, $template, $atts);
            $out .= ob_get_contents();
            ob_end_clean();
            $out .= '</div>' . "\n";
        }
        $out .= "\n" . '</div>' . "\n";
        $out .= "\n" . '<div class="cn-clear" id="cn-list-foot">' . "\n";
        $out .= "\n" . '</div>' . "\n";
        $out .= "\n" . '</div>' . "\n";
        $out .= "\n" . '</div>' . "\n";
    }
    if (cnSettingsAPI::get('connections', 'connections_compatibility', 'strip_rnt')) {
        $search = array("\r\n", "\r", "\n", "\t");
        $replace = array('', '', '', '');
        $out = str_replace($search, $replace, $out);
    }
    // Clear any filters that have been added.
    // This allows support using the shortcode multiple times on the same page.
    cnShortcode::clearFilterRegistry();
    return $out;
}