/**
  * Outputs entry data JSON encoded in HTML data attribute.
  * This is an action called by the `cn_action_entry_after` hook.
  *
  * @access public
  * @since  0.8
  *
  * @param array   $atts  Shortcode $atts passed by the `cn_action_entry_after` action hook.
  * @param cnEntry $entry An instance the the cnEntry object.
  *
  * @return string
  */
 public static function JSON($atts, $entry)
 {
     $defaults = array('tag' => 'div', 'before' => '', 'after' => '', 'return' => FALSE, 'show_addresses' => TRUE, 'show_phone_numbers' => TRUE, 'show_email' => TRUE, 'show_im' => TRUE, 'show_social_media' => TRUE, 'show_links' => TRUE, 'show_dates' => TRUE, 'show_bio' => TRUE, 'show_notes' => TRUE);
     $atts = wp_parse_args($atts, $defaults);
     $data = array('type' => $entry->getEntryType(), 'id' => $entry->getId(), 'ruid' => $entry->getRuid(), 'slug' => $entry->getSlug(), 'name' => array('full' => $entry->getName($atts), 'prefix' => $entry->getHonorificPrefix(), 'first' => $entry->getFirstName(), 'middle' => $entry->getMiddleName(), 'last' => $entry->getLastName(), 'suffix' => $entry->getHonorificSuffix()), 'title' => $entry->getTitle(), 'organization' => $entry->getOrganization(), 'department' => $entry->getDepartment(), 'contact_name' => array('full' => $entry->getContactName(), 'first' => $entry->getContactFirstName(), 'last' => $entry->getContactLastName()), 'family_name' => $entry->getFamilyName(), 'family_members' => $entry->getFamilyMembers(), 'categories' => $entry->getCategory(), 'meta' => $entry->getMeta($atts));
     if ($atts['show_addresses']) {
         $data['addresses'] = $entry->getAddresses($atts);
     }
     if ($atts['show_phone_numbers']) {
         $data['phone_numbers'] = $entry->getPhoneNumbers($atts);
     }
     if ($atts['show_email']) {
         $data['email_addresses'] = $entry->getEmailAddresses($atts);
     }
     if ($atts['show_im']) {
         $data['im'] = $entry->getIm($atts);
     }
     if ($atts['show_social_media']) {
         $data['social_media'] = $entry->getSocialMedia($atts);
     }
     if ($atts['show_links']) {
         $data['links'] = $entry->getLinks($atts);
     }
     if ($atts['show_dates']) {
         $data['dates'] = $entry->getDates($atts);
     }
     if ($atts['show_bio']) {
         $data['bio'] = $entry->getBio();
     }
     if ($atts['show_notes']) {
         $data['notes'] = $entry->getNotes();
     }
     $out = sprintf('<%1$s class="cn-entry-data-json" data-entry-data-json=\'%2$s\'></%1$s>', $atts['tag'], htmlspecialchars(json_encode($data), ENT_QUOTES, 'UTF-8'));
     $out = (empty($atts['before']) ? '' : $atts['before']) . $out . (empty($atts['after']) ? '' : $atts['after']) . PHP_EOL;
     return self::echoOrReturn($atts['return'], $out);
 }
 /**
  * Prepare a single entry output for response.
  *
  * @param cnEntry         $entry   Post object.
  * @param WP_REST_Request $request Request object.
  *
  * @return WP_REST_Response $data
  */
 public function prepare_item_for_response($entry, $request)
 {
     $data = array();
     //$entry->directoryHome(
     //	array(
     //		'page_id'    => $homeID,
     //		'force_home' => $forceHome,
     //	)
     //);
     $data['id'] = $entry->getId();
     $data['type'] = $entry->getEntryType();
     $data['slug'] = $entry->getSlug();
     $data['name'] = array('raw' => $entry->getName(array(), 'raw'), 'rendered' => $entry->getName());
     $data['honorific_prefix'] = array('raw' => $entry->getHonorificPrefix('raw'), 'rendered' => $entry->getHonorificPrefix());
     $data['given_name'] = array('raw' => $entry->getFirstName('raw'), 'rendered' => $entry->getFirstName());
     $data['additional_name'] = array('raw' => $entry->getMiddleName('raw'), 'rendered' => $entry->getMiddleName());
     $data['family_name'] = array('raw' => $entry->getLastName('raw'), 'rendered' => $entry->getLastName());
     $data['honorific_suffix'] = array('raw' => $entry->getHonorificSuffix('raw'), 'rendered' => $entry->getHonorificSuffix());
     $data['job_title'] = array('raw' => $entry->getTitle('raw'), 'rendered' => $entry->getTitle());
     $data['org'] = array('organization_name' => array('raw' => $entry->getDepartment('raw'), 'rendered' => $entry->getDepartment()), 'organization_unit' => array('raw' => $entry->getOrganization('raw'), 'rendered' => $entry->getOrganization()));
     $data['contact'] = array('given_name' => array('raw' => $entry->getContactFirstName('raw'), 'rendered' => $entry->getContactFirstName()), 'family_name' => array('raw' => $entry->getContactLastName('raw'), 'rendered' => $entry->getContactLastName()));
     $data = $this->prepare_address_for_response($entry, $request, $data);
     // Wrap the data in a response object.
     $response = rest_ensure_response($data);
     return $response;
 }
 /**
  * Echos the family members of the family entry type.
  *
  * @access  public
  * @since   unknown
  *
  * @param array $atts {
  *     Optional.
  *
  *     @type string $container_tag The relationship container tag. Default `ul`. Accepts HTML tag.
  *     @type string $item_tag      The relationship row tag. Default `li`. Accepts HTML tag.
  *     @type string $item_format   The relationship row HTML markup.
  *     @type string $name_format   How the relationship name should be displayed @see cnEntry::getName().
  *     @type string $separator     The string used to separate the relation label from the relation name. Default ':'.
  *     @type string $before        HTML to be displayed before the relations container. Default, empty string.
  *     @type string $after         HTML to be displayed after the relations container. Default, empty string.
  *     @type string $before_item   HTML to be displayed before a relation row. Default, empty string.
  *     @type string $after_item    HTML to be displayed after a relation row. Default, empty string.
  * }
  *
  * @return string
  */
 public function getFamilyMemberBlock($atts = array())
 {
     $defaults = array('container_tag' => 'ul', 'item_tag' => 'li', 'item_format' => '<%1$s class="cn-relation"><span class="cn-relation-label">%relation%</span>%separator% <span class="cn-relation-name notranslate">%name%</span></%1$s>', 'name_format' => '', 'separator' => ':', 'before' => '', 'after' => '', 'before_item' => '', 'after_item' => '', 'return' => FALSE);
     /**
      * Filter the arguments.
      *
      * @since unknown
      *
      * @param array $atts An array of arguments.
      */
     $atts = cnSanitize::args(apply_filters('cn_output_family_atts', $atts), $defaults);
     $html = '';
     $search = array('%relation%', '%name%', '%separator%');
     if ($this->getFamilyMembers()) {
         // Grab an instance of the Connections object.
         $instance = Connections_Directory();
         foreach ($this->getFamilyMembers() as $key => $value) {
             $relation = new cnEntry();
             $replace = array();
             if ($relation->set($key)) {
                 $replace[] = $instance->options->getFamilyRelation($value);
                 $replace[] = cnURL::permalink(array('type' => 'name', 'slug' => $relation->getSlug(), 'title' => $relation->getName(array('format' => $atts['name_format'])), 'text' => $relation->getName(array('format' => $atts['name_format'])), 'home_id' => $this->directoryHome['page_id'], 'force_home' => $this->directoryHome['force_home'], 'return' => TRUE));
                 $replace[] = empty($atts['separator']) ? '' : '<span class="cn-separator">' . $atts['separator'] . '</span>';
                 $row = str_ireplace($search, $replace, empty($atts['item_format']) ? $defaults['item_format'] : $atts['item_format']);
                 $html .= "\t" . sprintf($row, $atts['item_tag']) . PHP_EOL;
             }
         }
         $html = sprintf('<%1$s class="cn-relations">' . PHP_EOL . '%2$s</%1$s>', $atts['container_tag'], $html);
         $html = $atts['before'] . $html . $atts['after'] . PHP_EOL;
     }
     return $this->echoOrReturn($atts['return'], $html);
 }
 /**
  * Add / Edit / Copy an entry.
  *
  * @access private
  * @since  0.7.8
  *
  * @uses   absint()
  *
  * @param  string $action Valid options are: add | update
  * @param  array  $data [optional] The data to be used when adding / editing / duplicating an entry.
  * @param  int    $id [optional] If editing/duplicating an entry, the entry ID.
  *
  * @return bool
  */
 private static function process($action, $data = array(), $id = 0)
 {
     global $connections;
     /** @var cnEntry $entry */
     $entry = new cnEntry();
     // If copying/editing an entry, the entry data is loaded into the class
     // properties and then properties are overwritten by the data as needed.
     if (!empty($id)) {
         $entry->set(absint($id));
     }
     if (isset($data['entry_type'])) {
         $entry->setEntryType($data['entry_type']);
     }
     if (isset($data['family_name'])) {
         $entry->setFamilyName($data['family_name']);
     }
     isset($data['family_member']) ? $entry->setFamilyMembers($data['family_member']) : $entry->setFamilyMembers(array());
     if (isset($data['honorific_prefix'])) {
         $entry->setHonorificPrefix($data['honorific_prefix']);
     }
     if (isset($data['first_name'])) {
         $entry->setFirstName($data['first_name']);
     }
     if (isset($data['middle_name'])) {
         $entry->setMiddleName($data['middle_name']);
     }
     if (isset($data['last_name'])) {
         $entry->setLastName($data['last_name']);
     }
     if (isset($data['honorific_suffix'])) {
         $entry->setHonorificSuffix($data['honorific_suffix']);
     }
     if (isset($data['title'])) {
         $entry->setTitle($data['title']);
     }
     if (isset($data['organization'])) {
         $entry->setOrganization($data['organization']);
     }
     if (isset($data['department'])) {
         $entry->setDepartment($data['department']);
     }
     if (isset($data['contact_first_name'])) {
         $entry->setContactFirstName($data['contact_first_name']);
     }
     if (isset($data['contact_last_name'])) {
         $entry->setContactLastName($data['contact_last_name']);
     }
     isset($data['address']) ? $entry->setAddresses($data['address']) : $entry->setAddresses(array());
     isset($data['phone']) ? $entry->setPhoneNumbers($data['phone']) : $entry->setPhoneNumbers(array());
     isset($data['email']) ? $entry->setEmailAddresses($data['email']) : $entry->setEmailAddresses(array());
     isset($data['im']) ? $entry->setIm($data['im']) : $entry->setIm(array());
     isset($data['social']) ? $entry->setSocialMedia($data['social']) : $entry->setSocialMedia(array());
     //( isset($data['website']) ) ? $entry->setWebsites($data['website']) : $entry->setWebsites( array() );
     isset($data['link']) ? $entry->setLinks($data['link']) : $entry->setLinks(array());
     isset($data['date']) ? $entry->setDates($data['date']) : $entry->setDates(array());
     if (isset($data['birthday_day']) && isset($data['birthday_month'])) {
         $entry->setBirthday($data['birthday_day'], $data['birthday_month']);
     }
     if (isset($data['anniversary_day']) && isset($data['anniversary_month'])) {
         $entry->setAnniversary($data['anniversary_day'], $data['anniversary_month']);
     }
     if (isset($data['bio'])) {
         $entry->setBio($data['bio']);
     }
     if (isset($data['notes'])) {
         $entry->setNotes($data['notes']);
     }
     if (isset($data['visibility'])) {
         $entry->setVisibility($data['visibility']);
     }
     isset($data['user']) ? $entry->setUser($data['user']) : $entry->setUser(0);
     switch ($action) {
         case 'add':
             // If the entry is being copied, the source slug needs copied because it is required
             // in order to copy the source entry images to the new entry.
             if (!empty($id)) {
                 $sourceEntrySlug = rawurldecode($entry->getSlug());
                 $entry->setSlug($entry->getName(array('format' => '%first%-%last%')));
                 // If a new entry is being added, set the unique slug.
             } else {
                 $entry->setSlug($entry->getName(array('format' => '%first%-%last%')));
             }
             break;
         case 'update':
             // If an entry is being edited, set the new slug, if a new slug was provided.
             if (isset($data['slug']) && $data['slug'] != $entry->getSlug()) {
                 $entry->setSlug($data['slug']);
             }
             break;
     }
     $slug = rawurldecode($entry->getSlug());
     // Run any registered filters before processing, passing the $entry object.
     // ? Should the logo, photo and category data be passed too?
     $entry = apply_filters('cn_pre_process_' . $action . '-entry', $entry, isset($data['entry_category']) ? $data['entry_category'] : array());
     /*
      * Process the logo upload --> START <--
      */
     if (isset($_FILES['original_logo']) && $_FILES['original_logo']['error'] != 4) {
         // If an entry is being updated and a new logo is uploaded, the old logo needs to be deleted.
         // Delete the entry logo.
         self::deleteImages($entry->getLogoName(), $slug);
         // Delete logo the legacy logo, pre 8.1.
         self::deleteLegacyLogo($entry);
         // Process the newly uploaded image.
         $result = self::processLogo($slug);
         // If there were no errors processing the logo, set the values.
         if ($result) {
             $entry->setLogoLinked(TRUE);
             $entry->setLogoDisplay(TRUE);
             $entry->setLogoName($result['name']);
             $entry->setOriginalLogoMeta($result);
         } else {
             $entry->setLogoLinked(FALSE);
             $entry->setLogoDisplay(FALSE);
         }
     }
     // Don't do this if an entry is being updated.
     if ($action !== 'update') {
         // If an entry is being copied and there is a logo, the logo will be duplicated for the new entry.
         // That way if an entry is deleted, only the entry specific logo will be deleted.
         if ($entry->getLogoName() != NULL && (isset($sourceEntrySlug) && !empty($sourceEntrySlug))) {
             self::copyImages($entry->getLogoName(), $sourceEntrySlug, $slug);
         }
     }
     /*
      * If copying an entry, the logo visibility property is set based on the user's choice.
      * NOTE: This must come after the logo processing.
      */
     if (isset($data['logoOptions'])) {
         switch ($data['logoOptions']) {
             case 'remove':
                 $entry->setLogoDisplay(FALSE);
                 $entry->setLogoLinked(FALSE);
                 // Delete the entry image and its variations.
                 self::deleteImages($entry->getLogoName(), $slug);
                 // Delete logo the legacy logo, pre 8.1.
                 self::deleteLegacyLogo($entry);
                 $entry->setLogoName(NULL);
                 break;
             case 'hidden':
                 $entry->setLogoDisplay(FALSE);
                 break;
             case 'show':
                 $entry->setLogoDisplay(TRUE);
                 break;
             default:
                 $entry->setLogoDisplay(FALSE);
                 break;
         }
     }
     /*
      * Process the logo upload --> END <--
      */
     /*
      * Process the image upload. --> START <--
      */
     if (isset($_FILES['original_image']) && $_FILES['original_image']['error'] != 4) {
         // Delete the entry image and its variations.
         self::deleteImages($entry->getImageNameOriginal(), $slug);
         // Delete any legacy images, pre 8.1, that may exist.
         self::deleteLegacyImages($entry);
         // Process the newly uploaded image.
         $result = self::processImage($slug);
         // If there were no errors processing the image, set the values.
         if ($result) {
             $entry->setImageLinked(TRUE);
             $entry->setImageDisplay(TRUE);
             $entry->setImageNameOriginal($result['image_names']['original']);
             $entry->setOriginalImageMeta($result['image']['original']['meta']);
         } else {
             $entry->setImageLinked(FALSE);
             $entry->setImageDisplay(FALSE);
         }
     }
     // Don't do this if an entry is being updated.
     if ($action !== 'update') {
         // If an entry is being copied and there is an image, the image will be duplicated for the new entry.
         // That way if an entry is deleted, only the entry specific images will be deleted.
         if ($entry->getImageNameOriginal() != NULL && (isset($sourceEntrySlug) && !empty($sourceEntrySlug))) {
             self::copyImages($entry->getImageNameOriginal(), $sourceEntrySlug, $slug);
         }
     }
     // If copying an entry, the image visibility property is set based on the user's choice.
     // NOTE: This must come after the image processing.
     if (isset($data['imgOptions'])) {
         switch ($data['imgOptions']) {
             case 'remove':
                 $entry->setImageDisplay(FALSE);
                 $entry->setImageLinked(FALSE);
                 // Delete the entry image and its variations.
                 self::deleteImages($entry->getImageNameOriginal(), $slug);
                 // Delete any legacy images, pre 8.1, that may exist.
                 self::deleteLegacyImages($entry);
                 $entry->setImageNameOriginal(NULL);
                 break;
             case 'hidden':
                 $entry->setImageDisplay(FALSE);
                 break;
             case 'show':
                 $entry->setImageDisplay(TRUE);
                 break;
             default:
                 $entry->setImageDisplay(FALSE);
                 break;
         }
     }
     /*
      * Process the image upload. --> END <--
      */
     switch ($action) {
         case 'add':
             // Set moderation status per role capability assigned to the current user.
             if (current_user_can('connections_add_entry')) {
                 $entry->setStatus('approved');
                 $messageID = 'entry_added';
             } elseif (current_user_can('connections_add_entry_moderated')) {
                 $entry->setStatus('pending');
                 $messageID = 'entry_added_moderated';
             } else {
                 $entry->setStatus('pending');
                 $messageID = 'entry_added_moderated';
             }
             // Save the entry to the database. On fail store error message.
             if ($entry->save() == FALSE) {
                 cnMessage::set('error', 'entry_added_failed');
                 return FALSE;
             } else {
                 cnMessage::set('success', $messageID);
                 $entryID = (int) $connections->lastInsertID;
                 $entry->setID($entryID);
             }
             break;
         case 'update':
             // Set moderation status per role capability assigned to the current user.
             if (current_user_can('connections_edit_entry')) {
                 if ($entry->getStatus() == 'pending' && current_user_can('connections_add_entry_moderated')) {
                     $entry->setStatus('pending');
                     $messageID = 'entry_updated_moderated';
                 } elseif ($entry->getStatus() == 'approved' && current_user_can('connections_add_entry_moderated')) {
                     $entry->setStatus('approved');
                     $messageID = 'entry_updated';
                 } elseif ($entry->getStatus() == 'pending' && current_user_can('connections_add_entry')) {
                     $entry->setStatus('approved');
                     $messageID = 'entry_updated';
                 } elseif ($entry->getStatus() == 'approved' && current_user_can('connections_add_entry')) {
                     $entry->setStatus('approved');
                     $messageID = 'entry_updated';
                 } else {
                     // $entry->setStatus( 'pending' );
                     // $messageID = 'entry_updated_moderated';
                     $messageID = 'entry_updated';
                 }
             } elseif (current_user_can('connections_edit_entry_moderated')) {
                 $entry->setStatus('pending');
                 $messageID = 'entry_updated_moderated';
             } else {
                 $entry->setStatus('pending');
                 $messageID = 'entry_updated_moderated';
             }
             // Update the entry to the database. On fail store error message.
             if ($entry->update() == FALSE) {
                 cnMessage::set('error', 'entry_updated_failed');
                 return FALSE;
             } else {
                 cnMessage::set('success', $messageID);
                 $entryID = (int) $entry->getId();
             }
             break;
     }
     do_action('cn_process_taxonomy-category', $action, $entryID);
     do_action('cn_process_meta-entry', $action, $entryID);
     // Refresh the cnEntry object with any updated taxonomy or meta data
     // that may have been added/updated via actions.
     $entry->set($entryID);
     // Run any registered post process actions.
     do_action("cn_post_process_{$action}-entry", $entry);
     return $entryID;
 }
 /**
  * Prepare a single post output for response.
  *
  * @param cnEntry         $entry   Post object.
  * @param WP_REST_Request $request Request object.
  *
  * @return WP_REST_Response $data
  */
 public function prepare_item_for_response($entry, $request)
 {
     //$entry->directoryHome(
     //	array(
     //		'page_id'    => $homeID,
     //		'force_home' => $forceHome,
     //	)
     //);
     $addresses = $entry->getAddresses();
     /**
      * NOTES:
      *
      *  - The `coordinates` index array value must not have indexes otherwise it'll be converted to an object
      * which is invalid geoJSON.
      *  - The `coordinates` must but cast as floats otherwise they'll be converted to strings.
      *  - The `coordinates` must be longitude, latitude order per the geoJSON spec.
      *
      * @todo Loop thu each address within an entry so a geoJSON `feature` is added for each address the entry may have.
      * @todo The entry only needs to be added to $entries if it has at least one address and those address has both a latitude and longitude.
      *
      * @link http://connections-pro.com/support/topic/map-view/#post-319981
      */
     if ((!isset($addresses[0]->latitude) || empty($addresses[0]->latitude)) && (!isset($addresses[0]->longitude) || empty($addresses[0]->longitude))) {
         //return;
     }
     switch ($entry->getEntryType()) {
         case 'individual':
             $type = 'Person';
             break;
         case 'organization':
             $type = 'Organization';
             break;
         case 'family':
             $type = 'Family';
             break;
         default:
             $type = NULL;
     }
     $data = array('type' => 'Feature', 'geometry' => array('type' => 'Point', 'coordinates' => array((double) $addresses[0]->longitude, (double) $addresses[0]->latitude)), 'properties' => array('id' => $entry->getId(), 'type' => $type, 'slug' => $entry->getSlug(), 'permalink' => $entry->getPermalink(), 'name' => $entry->getName(), 'title' => $entry->getTitle(), 'department' => $entry->getDepartment() ? array('@type' => 'Organization', 'name' => $entry->getDepartment()) : NULL, 'organization' => $entry->getOrganization() ? array('@type' => 'Organization', 'name' => $entry->getOrganization()) : NULL, 'bio' => $entry->getBio(), 'notes' => $entry->getNotes()));
     // Wrap the data in a response object.
     $response = rest_ensure_response($data);
     return $response;
 }