/** * @param WP_REST_Request $request Full details about the request. * * @return array */ protected function get_entries($request) { // Grab an instance of the Connections object. $instance = Connections_Directory(); $atts = array('limit' => $request['per_page'], 'offset' => $request['offset']); $results = $instance->retrieve->entries($atts); return $results; }
/** * Get the system info. * * @access private * @since 8.3 * @static * * @global wpdb $wpdb * * @uses Browser() * @uses Connections_Directory() * @uses wp_get_theme() * @uses cnSystem_Info::getHost() * * @return string */ public static function get() { /** @var wpdb $wpdb */ global $wpdb; if (!class_exists('Browser')) { require_once CN_PATH . 'vendor/browser/Browser.php'; } $browser = new Browser(); // Grab an instance of the Connections object. $instance = Connections_Directory(); // Get theme info $theme_data = wp_get_theme(); $theme = $theme_data->Name . ' ' . $theme_data->Version; // Try to identify the hosting provider $host = self::getHost(); ob_start(); require_once CN_PATH . 'includes/system-info/inc.system-info.php'; return ob_get_clean(); }
/** * Function for displaying the widget on the page. * * @access private * @since 1.0 * * @param array $args * @param array $option * * @return string */ public function widget($args, $option) { // Only process and display the widget if displaying a single entry. if (get_query_var('cn-entry-slug')) { // Grab an instance of the Connections object. $instance = Connections_Directory(); // Query the entry. $result = $instance->retrieve->entries(array('slug' => urldecode(get_query_var('cn-entry-slug')))); // Setup the entry object $entry = new cnEntry($result[0]); // Query the entry meta. $metadata = $entry->getMeta(array('key' => 'hobbies', 'single' => TRUE)); // If there is no meta; bail. if (empty($metadata)) { return; } /** * Extract $before_widget, $after_widget, $before_title and $after_title. * * @var $before_widget * @var $after_widget * @var $before_title * @var $after_title */ extract($args); // Setup the default widget options if they were not set when they were added to the sidebar; // ie. the user did not click the "Save" button on the widget. $title = strlen($option['title']) > 0 ? $option['title'] : __('Hobbies', 'connections_hobbies'); // Setup the atts to be passed to the method that displays the data. $atts = array(); echo $before_widget; echo $before_title . $title . $after_title; // Display the income level. Connections_Hobbies::block('hobbies', $metadata, NULL, $atts); echo $after_widget; } }
public static function shortcode($atts, $content = '', $tag = 'cn_thumbr') { // Grab an instance of the Connections object. $instance = Connections_Directory(); $log = array(); $srcset = array(); $permitted = array('attachment', 'featured', 'path', 'url', 'logo', 'photo'); $defaults = array('type' => 'url', 'source' => NULL, 'negate' => FALSE, 'grayscale' => FALSE, 'brightness' => 0, 'colorize' => NULL, 'contrast' => 0, 'detect_edges' => FALSE, 'emboss' => FALSE, 'gaussian_blur' => FALSE, 'blur' => FALSE, 'sketchy' => FALSE, 'sharpen' => FALSE, 'smooth' => NULL, 'opacity' => 100, 'crop_mode' => 1, 'crop_focus' => array(0.5, 0.5), 'crop_only' => FALSE, 'canvas_color' => '#FFFFFF', 'quality' => 90, 'sizes' => '1024|640|320'); $defaults = apply_filters('cn_thumbr_shortcode_atts', $defaults); $atts = shortcode_atts($defaults, $atts, $tag); if (!in_array($atts['type'], $permitted)) { return __('Valid image source type not supplied.', 'connections'); } /* * Convert some of the $atts values in the array to boolean because the Shortcode API passes all values as strings. */ cnFormatting::toBoolean($atts['negate']); cnFormatting::toBoolean($atts['grayscale']); cnFormatting::toBoolean($atts['detect_edges']); cnFormatting::toBoolean($atts['emboss']); cnFormatting::toBoolean($atts['gaussian_blur']); cnFormatting::toBoolean($atts['blur']); cnFormatting::toBoolean($atts['sketchy']); cnFormatting::toBoolean($atts['sharpen']); // cnFormatting::toBoolean( $atts['crop'] ); cnFormatting::toBoolean($atts['crop_only']); $atts['sizes'] = explode('|', $atts['sizes']); array_map('trim', $atts['sizes']); array_map('absint', $atts['sizes']); if (empty($atts['sizes'])) { return __('No image sizes were supplied or supplied values were invalid.', 'connections'); } switch ($atts['type']) { case 'attachment': $source = wp_get_attachment_url(absint($atts['source'])); break; case 'featured': $source = wp_get_attachment_url(get_post_thumbnail_id()); break; case 'path': $source = $atts['source']; break; case 'url': $source = esc_url($atts['source']); break; case 'logo': $result = $instance->retrieve->entry(absint($atts['source'])); $entry = new cnEntry($result); $meta = $entry->getImageMeta(array('type' => 'logo')); if (is_wp_error($meta)) { // Display the error messages. return implode(PHP_EOL, $meta->get_error_messages()); } $source = $meta['url']; break; case 'photo': $result = $instance->retrieve->entry(absint($atts['source'])); $entry = new cnEntry($result); $meta = $entry->getImageMeta(array('type' => 'photo')); if (is_wp_error($meta)) { // Display the error messages. return implode(PHP_EOL, $meta->get_error_messages()); } $source = $meta['url']; break; } // Unset $atts['source'] because passing that $atts to cnImage::get() extracts and overwrite the $source var. unset($atts['source']); foreach ($atts['sizes'] as $width) { $atts['width'] = $width; $image = cnImage::get($source, $atts, 'data'); if (is_wp_error($image)) { // Display the error messages. return implode(PHP_EOL, $image->get_error_messages()); } elseif ($image === FALSE) { return __('An error has occured while creating the thumbnail.', 'connections'); } if (defined('WP_DEBUG') && WP_DEBUG === TRUE) { $log[] = '<pre>' . $image['log'] . '</pre>'; } $srcset[] = $image['url'] . ' ' . $width . 'w'; } $out = sprintf('<img class="cn-image" srcset="%1$s" sizes="100vw"%2$s />', implode(',', $srcset), empty($content) ? '' : ' alt="' . esc_attr($content) . '"'); if (defined('WP_DEBUG') && WP_DEBUG === TRUE) { $out .= implode('', $log); } return $out; }
/** * Will return TRUE?FALSE based on current user capability or privacy setting if the user is not logged in to * WordPress. * * @access public * @since 0.7.2.0 * @static * * @uses is_user_logged_in() * @uses current_user_can() * @uses is_admin() * @uses cnOptions::loginRequired() * @uses cnOptions::getAllowPublicOverride() * @uses cnOptions::getAllowPrivateOverride() * * @param string $visibility * * @return bool */ public static function userPermitted($visibility) { // Ensure a valid option for $visibility. if (!in_array($visibility, array('public', 'private', 'unlisted'))) { return FALSE; } if (is_user_logged_in()) { switch ($visibility) { case 'public': return current_user_can('connections_view_public'); case 'private': return current_user_can('connections_view_private'); case 'unlisted': return is_admin() && current_user_can('connections_view_unlisted'); default: return FALSE; } } else { // Unlisted entries are not shown on the frontend. if ('unlisted' == $visibility) { return FALSE; } // Grab an instance of the Connections object. $instance = Connections_Directory(); if (cnOptions::loginRequired()) { switch ($visibility) { case 'public': return $instance->options->getAllowPublicOverride(); case 'private': return $instance->options->getAllowPrivateOverride(); default: return FALSE; } } else { if ('public' == $visibility) { return TRUE; } } // If we get here, return FALSE return FALSE; } }
/** * This action will handle frontend process requests, currently only creating the vCard for download. * * @TODO If no vcard is found should redirect to an error message. * @access private * @since 0.7.3 * @return void */ public static function frontendActions() { // Grab an instance of the Connections object. $instance = Connections_Directory(); $process = get_query_var('cn-process'); $token = get_query_var('cn-token'); $id = (int) get_query_var('cn-id'); if ('vcard' === $process) { $slug = get_query_var('cn-entry-slug'); //var_dump($slug); /* * If the token and id values were set, the link was likely from the admin. * Check for those values and validate the token. The primary reason for this * to be able to download vCards of entries that are set to "Unlisted". */ if (!empty($id) && !empty($token)) { if (!wp_verify_nonce($token, 'download_vcard_' . $id)) { wp_die('Invalid vCard Token'); } $entry = $instance->retrieve->entry($id); // Die if no entry was found. if (empty($entry)) { wp_die(__('vCard not available for download.', 'connections')); } $vCard = new cnvCard($entry); //var_dump($vCard);die; } else { $entry = $instance->retrieve->entries(array('slug' => $slug)); //var_dump($entry);die; // Die if no entry was found. if (empty($entry)) { wp_die(__('vCard not available for download.', 'connections')); } $vCard = new cnvCard($entry[0]); //var_dump($vCard);die; } $filename = sanitize_file_name($vCard->getName()); //var_dump($filename); $data = $vCard->getvCard(); //var_dump($data);die; header('Content-Description: File Transfer'); header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename=' . $filename . '.vcf'); header('Content-Length: ' . strlen($data)); header('Pragma: public'); header("Pragma: no-cache"); //header( "Expires: 0" ); header('Expires: Wed, 11 Jan 1984 05:00:00 GMT'); header('Cache-Control: private'); // header( 'Connection: close' ); ob_clean(); flush(); echo $data; exit; } }
/** * Display results based on qurey var `cn-view`. * * @access public * @since 0.7.3 * @static * @uses get_query_var() * @param array $atts * @param string $content [optional] * * @return string */ public static function view($atts, $content = '', $tag = 'connections') { // Grab an instance of the Connections object. $instance = Connections_Directory(); /*$getAllowPublic = $instance->options->getAllowPublic(); var_dump($getAllowPublic); $getAllowPublicOverride = $instance->options->getAllowPublicOverride(); var_dump($getAllowPublicOverride); $getAllowPrivateOverride = $instance->options->getAllowPrivateOverride(); var_dump($getAllowPrivateOverride);*/ /* * Only show this message under the following condition: * - ( The user is not logged in AND the 'Login Required' is checked ) AND ( neither of the shortcode visibility overrides are enabled ). */ if (!is_user_logged_in() && !$instance->options->getAllowPublic() && !($instance->options->getAllowPublicOverride() || $instance->options->getAllowPrivateOverride())) { $message = $instance->settings->get('connections', 'connections_login', 'message'); // Format and texturize the message. $message = wptexturize(wpautop($message)); // Make any links and such clickable. $message = make_clickable($message); // Apply the shortcodes. $message = do_shortcode($message); return $message; } $view = get_query_var('cn-view'); switch ($view) { case 'submit': if (has_action('cn_submit_entry_form')) { ob_start(); do_action('cn_submit_entry_form', $atts, $content, $tag); return ob_get_clean(); } else { return '<p>' . __('Future home of front end submissions.', 'connections') . '</p>'; } break; case 'landing': return '<p>' . __('Future home of the landing pages, such a list of categories.', 'connections') . '</p>'; break; case 'search': if (has_action('cn_submit_search_form')) { ob_start(); do_action('cn_submit_search_form', $atts, $content, $tag); return ob_get_clean(); } else { return '<p>' . __('Future home of the search page.', 'connections') . '</p>'; } break; case 'results': if (has_action('cn_submit_search_results')) { ob_start(); do_action('cn_submit_search_results', $atts, $content, $tag); return ob_get_clean(); } else { return '<p>' . __('Future home of the search results landing page.', 'connections') . '</p>'; } break; // Show the standard result list. // Show the standard result list. case 'card': return cnShortcode_Connections::shortcode($atts, $content); break; // Show the "View All" result list using the "Names" template. // Show the "View All" result list using the "Names" template. case 'all': // Disable the output of the repeat character index. $atts['repeat_alphaindex'] = FALSE; // Force the use of the Names template. $atts['template'] = 'names'; return cnShortcode_Connections::shortcode($atts, $content); break; // Show the entry detail using a template based on the entry type. // Show the entry detail using a template based on the entry type. case 'detail': switch (get_query_var('cn-process')) { case 'edit': if (has_action('cn_edit_entry_form')) { // Check to see if the entry has been linked to a user ID. $entryID = get_user_meta(get_current_user_id(), 'connections_entry_id', TRUE); // var_dump( $entryID ); // $results = $instance->retrieve->entries(array('status' => 'approved,pending')); // var_dump( $results ); /* * The `cn_edit_entry_form` action should only be executed if the user is * logged in and they have the `connections_manage` capability and either the * `connections_edit_entry` or `connections_edit_entry_moderated` capability. */ if (is_user_logged_in() && (current_user_can('connections_manage') || $entryID == $results[0]->id) && (current_user_can('connections_edit_entry') || current_user_can('connections_edit_entry_moderated'))) { ob_start(); if (!current_user_can('connections_edit_entry') && $results[0]->status == 'pending') { echo '<p>' . __('Your entry submission is currently under review, however, you can continue to make edits to your entry submission while your submission is under review.', 'connections') . '</p>'; } do_action('cn_edit_entry_form', $atts, $content, $tag); return ob_get_clean(); } else { return __('You are not authorized to edit entries. Please contact the admin if you received this message in error.', 'connections'); } } break; default: // Ensure an array is passed the the cnRetrieve::entries method. if (!is_array($atts)) { $atts = (array) $atts; } $results = $instance->retrieve->entries($atts); //var_dump($results); $atts['list_type'] = $instance->settings->get('connections', 'connections_display_single', 'template') ? $results[0]->entry_type : NULL; // Disable the output of the following because they do no make sense to display for a single entry. $atts['show_alphaindex'] = FALSE; $atts['repeat_alphaindex'] = FALSE; $atts['show_alphahead'] = FALSE; return cnShortcode_Connections::shortcode($atts, $content); break; } break; // Show the standard result list. // Show the standard result list. default: //return cnShortcode_Connections::shortcode( $atts, $content ); if (has_action("cn_view_{$view}")) { ob_start(); do_action("cn_view_{$view}", $atts, $content, $tag); return ob_get_clean(); } break; } return cnShortcode_Connections::shortcode($atts, $content); }
/** * Add the the current Connections category description or entry bio excerpt as the page meta description. * * @access private * @since 0.7.8 * @static * * @uses cnQuery::getVar() * @uses esc_attr() * @uses strip_shortcodes() */ public static function metaDesc() { // Whether or not to filter the page title with the current directory location. if (!cnSettingsAPI::get('connections', 'seo_meta', 'page_desc')) { return; } $description = ''; if (cnQuery::getVar('cn-cat-slug')) { // If the category slug is a descendant, use the last slug from the URL for the query. $categorySlug = explode('/', cnQuery::getVar('cn-cat-slug')); if (isset($categorySlug[count($categorySlug) - 1])) { $categorySlug = $categorySlug[count($categorySlug) - 1]; } $term = cnTerm::getBy('slug', $categorySlug, 'category'); $category = new cnCategory($term); $description = $category->getExcerpt(array('length' => 160)); } if (cnQuery::getVar('cn-cat')) { if (is_array(cnQuery::getVar('cn-cat'))) { return; } $categoryID = cnQuery::getVar('cn-cat'); $term = cnTerm::getBy('id', $categoryID, 'category'); $category = new cnCategory($term); $description = $category->getExcerpt(array('length' => 160)); } if (cnQuery::getVar('cn-entry-slug')) { // Grab an instance of the Connections object. $instance = Connections_Directory(); $result = $instance->retrieve->entries(array('slug' => urldecode(cnQuery::getVar('cn-entry-slug')))); // Make sure an entry is returned and then echo the meta desc. if (!empty($result)) { $entry = new cnEntry($result[0]); $description = $entry->getExcerpt(array('length' => 160)); } } if (0 == strlen($description)) { return; } echo '<meta name="description" content="' . esc_attr(trim(strip_shortcodes(strip_tags(stripslashes($description))))) . '"/>' . "\n"; }
/** * The core template Customizer control string. * * @access private * @since 8.4 * * @uses Connections_Directory() * @uses apply_filters() * * @return array */ private function controlStrings() { // Grab an instance of the Connections object. $instance = Connections_Directory(); $addressTypes = array_keys($instance->options->getDefaultAddressValues()); $phoneTypes = array_keys($instance->options->getDefaultPhoneNumberValues()); $emailTypes = array_keys($instance->options->getDefaultEmailValues()); $dateTypes = array_keys($instance->options->getDateOptions()); $linkTypes = array_keys($instance->options->getDefaultLinkValues()); $strings = array('title' => array('label' => __('Show the entry title.', 'connections'), 'desc' => __('Whether or not to display the Title field.', 'connections')), 'org' => array('label' => __('Show the entry organization.', 'connections'), 'desc' => __('Whether or not to display the Organization field.', 'connections')), 'dept' => array('label' => __('Show the entry department.', 'connections'), 'desc' => __('Whether or not to display the Department field.', 'connections')), 'contact_name' => array('label' => __('Show the entry contact name.', 'connections'), 'desc' => __('Whether or not to display the Contact First and Last Name fields.', 'connections')), 'family' => array('label' => __('Show the entry family members.', 'connections'), 'desc' => __('Whether or not to display the family members.', 'connections')), 'addresses' => array('label' => __('Show the addresses.', 'connections'), 'desc' => __('Whether or not to display the addresses.', 'connections')), 'phone_numbers' => array('label' => __('Show the phone numbers.', 'connections'), 'desc' => __('Whether or not to display the phone numbers.', 'connections')), 'email' => array('label' => __('Show the email addresses.', 'connections'), 'desc' => __('Whether or not to display the email addresses.', 'connections')), 'im' => array('label' => __('Show the IM addresses.', 'connections'), 'desc' => __('Whether or not to display the IM addresses.', 'connections')), 'social_media' => array('label' => __('Show the social networks.', 'connections'), 'desc' => __('Whether or not to display the social networks.', 'connections')), 'links' => array('label' => __('Show the links.', 'connections'), 'desc' => __('Whether or not to display the links.', 'connections')), 'dates' => array('label' => __('Show the dates.', 'connections'), 'desc' => __('Whether or not to display the dates.', 'connections')), 'bio' => array('label' => __('Show the bio.', 'connections'), 'desc' => __('Whether or not to display the bio field.', 'connections')), 'notes' => array('label' => __('Show the notes.', 'connections'), 'desc' => __('Whether or not to display the notes field.', 'connections')), 'categories' => array('label' => __('Show the categories assigned to the entry.', 'connections'), 'desc' => __('Whether or not to display the categories.', 'connections')), 'last_updated' => array('label' => __('Show the last updated message.', 'connections'), 'desc' => __('Whether or not to display the last updated message.', 'connections')), 'return_to_top' => array('label' => __('Show display to top.', 'connections'), 'desc' => __('Whether or not to display the return to top arrow.', 'connections')), 'name_format' => array('label' => __('Name Format', 'connections'), 'desc' => __(sprintf('Default: %s', '<code>%prefix% %first% %middle% %last% %suffix%</code>'), 'connections')), 'contact_name_format' => array('label' => __('Contact Name Format', 'connections'), 'desc' => __(sprintf('Default: %s', '<code>%label%%separator% %first% %last%</code>'), 'connections')), 'address_format' => array('label' => __('Address Format', 'connections'), 'desc' => __(sprintf('Default: %s', '<code>%label% %line1% %line2% %line3% %city% %state% %zipcode% %country%</code>'), 'connections')), 'email_format' => array('label' => __('Email Format', 'connections'), 'desc' => __(sprintf('Default: %s', '<code>%label%%separator% %address%</code>'), 'connections')), 'phone_format' => array('label' => __('Phone Format', 'connections'), 'desc' => __(sprintf('Default: %s', '<code>%label%%separator% %number%</code>'), 'connections')), 'link_format' => array('label' => __('Link Format', 'connections'), 'desc' => __(sprintf('Default: %s', '<code>%label%%separator% %title%</code>'), 'connections')), 'date_format' => array('label' => __('Date Format', 'connections'), 'desc' => __(sprintf('Default: %s', '<code>%label%%separator% %date%</code>'), 'connections')), 'address_types' => array('label' => __('Display Address Types', 'connections'), 'desc' => __(sprintf('Valid: %s', '<code>' . implode('</code>, <code>', $addressTypes)) . '</code>', 'connections')), 'phone_types' => array('label' => __('Display Phone Types', 'connections'), 'desc' => __(sprintf('Valid: %s', '<code>' . implode('</code>, <code>', $phoneTypes)) . '</code>', 'connections')), 'email_types' => array('label' => __('Display Email Types', 'connections'), 'desc' => __(sprintf('Valid: %s', '<code>' . implode('</code>, <code>', $emailTypes)) . '</code>', 'connections')), 'date_types' => array('label' => __('Display Date Types', 'connections'), 'desc' => __(sprintf('Valid: %s', '<code>' . implode('</code>, <code>', $dateTypes)) . '</code>', 'connections')), 'link_types' => array('label' => __('Display Link Types', 'connections'), 'desc' => __(sprintf('Valid: %s', '<code>' . implode('</code>, <code>', $linkTypes)) . '</code>', 'connections'))); /** * An associative array of core strings used by the Template Customizer. * * The array key is the string ID. The value is an associative array with two keys. * The `label` key is the Customizer control label. * The `desc` key is the Customizer control description. * * @since 8.4 * * @param array $strings */ return apply_filters('cn_template_customizer_strings', $strings); }
remove_filter('page_rewrite_rules', array('cnRewrite', 'addPageRewriteRules')); // Flush so they are rebuilt. flush_rewrite_rules(); } } /** * The main function responsible for returning the Connections instance * to functions everywhere. * * Use this function like you would a global variable, except without needing * to declare the global. * * NOTE: Declaring an instance in the global @var $connections connectionsLoad to provide backward * compatibility with many internal methods, template and extensions that expect it. * * Example: <?php $instance = Connections_Directory(); ?> * * @access public * @since 0.7.9 * @global $connections * @return connectionsLoad */ function Connections_Directory() { global $connections; $connections = connectionsLoad::instance(); return $connections; } // Start Connections. Connections_Directory(); }
/** * Update the entry in the db. * * @access public * @since unknown * * @return false|int */ public function update() { /** @var wpdb $wpdb */ global $wpdb; // Grab an instance of the Connections object. $instance = Connections_Directory(); $this->serializeOptions(); $this->setPropertyDefaultsByEntryType(); do_action('cn_update-entry', $this); $result = $wpdb->update(CN_ENTRY_TABLE, array('ts' => current_time('mysql'), 'ordo' => $this->getOrder(), 'entry_type' => $this->entryType, 'visibility' => $this->getVisibility(), 'slug' => $this->getSlug(), 'honorific_prefix' => $this->honorificPrefix, 'first_name' => $this->firstName, 'middle_name' => $this->middleName, 'last_name' => $this->lastName, 'honorific_suffix' => $this->honorificSuffix, 'title' => $this->title, 'organization' => $this->organization, 'department' => $this->department, 'contact_first_name' => $this->contactFirstName, 'contact_last_name' => $this->contactLastName, 'family_name' => $this->familyName, 'birthday' => $this->birthday, 'anniversary' => $this->anniversary, 'addresses' => $this->addresses, 'phone_numbers' => $this->phoneNumbers, 'email' => $this->emailAddresses, 'im' => $this->im, 'social' => $this->socialMedia, 'links' => $this->links, 'dates' => $this->dates, 'options' => $this->options, 'bio' => $this->bio, 'notes' => $this->notes, 'edited_by' => $instance->currentUser->getID(), 'user' => $this->getUser(), 'status' => $this->status), array('id' => $this->id), array('%s', '%d', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%d', '%d', '%s'), array('%d')); //print_r($wpdb->last_query); /* * Only update the rest of the entry's data if the update to the ENTRY TABLE was successful. */ if (FALSE !== $result) { require_once CN_PATH . 'includes/entry/class.entry-db.php'; $cnDb = new cnEntry_DB($this->getId()); $cnDb->upsert(CN_ENTRY_ADDRESS_TABLE, array('order' => array('key' => 'order', 'format' => '%d'), 'preferred' => array('key' => 'preferred', 'format' => '%d'), 'type' => array('key' => 'type', 'format' => '%s'), 'line_1' => array('key' => 'line_1', 'format' => '%s'), 'line_2' => array('key' => 'line_2', 'format' => '%s'), 'line_3' => array('key' => 'line_3', 'format' => '%s'), 'line_4' => array('key' => 'line_4', 'format' => '%s'), 'district' => array('key' => 'district', 'format' => '%s'), 'county' => array('key' => 'county', 'format' => '%s'), 'city' => array('key' => 'city', 'format' => '%s'), 'state' => array('key' => 'state', 'format' => '%s'), 'zipcode' => array('key' => 'zipcode', 'format' => '%s'), 'country' => array('key' => 'country', 'format' => '%s'), 'latitude' => array('key' => 'latitude', 'format' => '%s'), 'longitude' => array('key' => 'longitude', 'format' => '%s'), 'visibility' => array('key' => 'visibility', 'format' => '%s')), $this->getAddresses(array(), TRUE, TRUE, 'db'), array('id' => array('key' => 'id', 'format' => '%d'))); $cnDb->upsert(CN_ENTRY_PHONE_TABLE, array('order' => array('key' => 'order', 'format' => '%d'), 'preferred' => array('key' => 'preferred', 'format' => '%d'), 'type' => array('key' => 'type', 'format' => '%s'), 'number' => array('key' => 'number', 'format' => '%s'), 'visibility' => array('key' => 'visibility', 'format' => '%s')), $this->getPhoneNumbers(array(), TRUE, TRUE), array('id' => array('key' => 'id', 'format' => '%d'))); $cnDb->upsert(CN_ENTRY_EMAIL_TABLE, array('order' => array('key' => 'order', 'format' => '%d'), 'preferred' => array('key' => 'preferred', 'format' => '%d'), 'type' => array('key' => 'type', 'format' => '%s'), 'address' => array('key' => 'address', 'format' => '%s'), 'visibility' => array('key' => 'visibility', 'format' => '%s')), $this->getEmailAddresses(array(), TRUE, TRUE), array('id' => array('key' => 'id', 'format' => '%d'))); $cnDb->upsert(CN_ENTRY_MESSENGER_TABLE, array('order' => array('key' => 'order', 'format' => '%d'), 'preferred' => array('key' => 'preferred', 'format' => '%d'), 'type' => array('key' => 'type', 'format' => '%s'), 'uid' => array('key' => 'id', 'format' => '%s'), 'visibility' => array('key' => 'visibility', 'format' => '%s')), $this->getIm(array(), TRUE, TRUE), array('id' => array('key' => 'uid', 'format' => '%d'))); $cnDb->upsert(CN_ENTRY_SOCIAL_TABLE, array('order' => array('key' => 'order', 'format' => '%d'), 'preferred' => array('key' => 'preferred', 'format' => '%d'), 'type' => array('key' => 'type', 'format' => '%s'), 'url' => array('key' => 'url', 'format' => '%s'), 'visibility' => array('key' => 'visibility', 'format' => '%s')), $this->getSocialMedia(array(), TRUE, TRUE), array('id' => array('key' => 'id', 'format' => '%d'))); $cnDb->upsert(CN_ENTRY_LINK_TABLE, array('order' => array('key' => 'order', 'format' => '%d'), 'preferred' => array('key' => 'preferred', 'format' => '%d'), 'type' => array('key' => 'type', 'format' => '%s'), 'title' => array('key' => 'title', 'format' => '%s'), 'url' => array('key' => 'url', 'format' => '%s'), 'target' => array('key' => 'target', 'format' => '%s'), 'follow' => array('key' => 'follow', 'format' => '%d'), 'image' => array('key' => 'image', 'format' => '%d'), 'logo' => array('key' => 'logo', 'format' => '%d'), 'visibility' => array('key' => 'visibility', 'format' => '%s')), $this->getLinks(array(), TRUE, TRUE), array('id' => array('key' => 'id', 'format' => '%d'))); $cnDb->upsert(CN_ENTRY_DATE_TABLE, array('order' => array('key' => 'order', 'format' => '%d'), 'preferred' => array('key' => 'preferred', 'format' => '%d'), 'type' => array('key' => 'type', 'format' => '%s'), 'date' => array('key' => 'date', 'format' => '%s'), 'visibility' => array('key' => 'visibility', 'format' => '%s')), $this->getDates(array(), TRUE, TRUE), array('id' => array('key' => 'id', 'format' => '%d'))); $this->updateObjectCaches(); } do_action('cn_updated-entry', $this); return $result; }
/** * Add the entry actions to the admin bar * * @access private * @static * @since 8.2 * @uses cnURL::permalink() * @uses current_user_can() * @param $admin_bar object * * @return void */ public static function adminBarMenuItems($admin_bar) { if (get_query_var('cn-entry-slug')) { // Grab an instance of the Connections object. $instance = Connections_Directory(); $entry = $instance->retrieve->entries(array('slug' => rawurldecode(get_query_var('cn-entry-slug')), 'status' => 'approved,pending')); // preg_match( '/href="(.*?)"/', cnURL::permalink( array( 'slug' => $entry->slug, 'return' => TRUE ) ), $matches ); // $permalink = $matches[1]; if (current_user_can('connections_manage') && current_user_can('connections_view_menu') && (current_user_can('connections_edit_entry_moderated') || current_user_can('connections_edit_entry'))) { $admin_bar->add_node(array('parent' => FALSE, 'id' => 'cn-edit-entry', 'title' => __('Edit Entry', 'connections'), 'href' => admin_url(wp_nonce_url('admin.php?page=connections_manage&cn-action=edit_entry&id=' . $entry[0]->id, 'entry_edit_' . $entry[0]->id)), 'meta' => array('title' => __('Edit Entry', 'connections')))); } } }
/** * Renders the dates metabox. * * @access public * @since 0.8 * @param object $entry An instance of the cnEntry object. * @param array $metabox The metabox options array from self::register(). * @return string The dates metabox. */ public static function date($entry, $metabox) { // Grab an instance of the Connections object. $instance = Connections_Directory(); // Grab the email types. $dateTypes = $instance->options->getDateOptions(); echo '<div class="widgets-sortables ui-sortable" id="dates">', PHP_EOL; // --> Start template <-- \\ echo '<textarea id="date-template" style="display: none;">', PHP_EOL; echo '<div class="widget-top">', PHP_EOL; echo '<div class="widget-title-action"><a class="widget-action"></a></div>', PHP_EOL; echo '<div class="widget-title"><h4>', PHP_EOL; cnHTML::field(array('type' => 'select', 'class' => '', 'id' => 'date[::FIELD::][type]', 'options' => $dateTypes, 'required' => FALSE, 'label' => __('Type', 'connections'), 'return' => FALSE)); cnHTML::field(array('type' => 'radio', 'format' => 'inline', 'class' => '', 'id' => 'date[preferred]', 'options' => array('::FIELD::' => __('Preferred', 'connections')), 'required' => FALSE, 'before' => '<span class="preferred">', 'after' => '</span>', 'return' => FALSE)); // Only show this if there are visibility options that the user is permitted to see. if (!empty(self::$visibility)) { cnHTML::field(array('type' => 'radio', 'format' => 'inline', 'class' => '', 'id' => 'date[::FIELD::][visibility]', 'options' => self::$visibility, 'required' => FALSE, 'before' => '<span class="visibility">' . __('Visibility', 'connections') . ' ', 'after' => '</span>', 'return' => FALSE), 'public'); } echo '</h4></div>', PHP_EOL; echo '</div>', PHP_EOL; echo '<div class="widget-inside">'; cnHTML::field(array('type' => 'text', 'class' => 'datepicker', 'id' => 'date[::FIELD::][date]', 'required' => FALSE, 'label' => __('Date', 'connections'), 'before' => '', 'after' => '', 'return' => FALSE)); echo '<p class="cn-remove-button"><a href="#" class="cn-remove cn-button button cn-button-warning" data-type="date" data-token="::FIELD::">', __('Remove', 'connections'), '</a></p>'; echo '</div>', PHP_EOL; echo '</textarea>', PHP_EOL; // --> End template <-- \\ $dates = $entry->getDates(array(), FALSE); //print_r($dates); if (!empty($dates)) { foreach ($dates as $date) { $token = str_replace('-', '', cnUtility::getUUID()); $selectName = 'date[' . $token . '][type]'; $preferred = $date->preferred ? $token : ''; echo '<div class="widget date" id="date-row-' . $token . '">', PHP_EOL; echo '<div class="widget-top">', PHP_EOL; echo '<div class="widget-title-action"><a class="widget-action"></a></div>', PHP_EOL; echo '<div class="widget-title"><h4>', PHP_EOL; cnHTML::field(array('type' => 'select', 'class' => '', 'id' => 'date[' . $token . '][type]', 'options' => $dateTypes, 'required' => FALSE, 'label' => __('Type', 'connections'), 'return' => FALSE), $date->type); cnHTML::field(array('type' => 'radio', 'format' => 'inline', 'class' => '', 'id' => 'date[preferred]', 'options' => array($token => __('Preferred', 'connections')), 'required' => FALSE, 'before' => '<span class="preferred">', 'after' => '</span>', 'return' => FALSE), $preferred); // Only show this if there are visibility options that the user is permitted to see. if (!empty(self::$visibility)) { cnHTML::field(array('type' => 'radio', 'format' => 'inline', 'class' => '', 'id' => 'date[' . $token . '][visibility]', 'options' => self::$visibility, 'required' => FALSE, 'before' => '<span class="visibility">' . __('Visibility', 'connections') . ' ', 'after' => '</span>', 'return' => FALSE), $date->visibility); } echo '</h4></div>', PHP_EOL; echo '</div>', PHP_EOL; echo '<div class="widget-inside">', PHP_EOL; cnHTML::field(array('type' => 'text', 'class' => 'datepicker', 'id' => 'date[' . $token . '][date]', 'required' => FALSE, 'label' => __('Date', 'connections'), 'before' => '', 'after' => '', 'return' => FALSE), date('m/d/Y', strtotime($date->date))); echo '<input type="hidden" name="date[', $token, '][id]" value="', $date->id, '">', PHP_EOL; echo '<p class="cn-remove-button"><a href="#" class="cn-remove cn-button button cn-button-warning" data-type="date" data-token="' . $token . '">', __('Remove', 'connections'), '</a></p>', PHP_EOL; echo '</div>', PHP_EOL; echo '</div>', PHP_EOL; } } echo '</div>', PHP_EOL; echo '<p class="add"><a href="#" class="cn-add cn-button button" data-type="date" data-container="dates">', __('Add Date', 'connections'), '</a></p>', PHP_EOL; }
/** * Add count of children to parent count. * * Recalculates term counts by including items from child terms. Assumes all * relevant children are already in the $terms argument. * * NOTE: This is the Connections equivalent of @see _pad_term_counts() in WordPress core ../wp-includes/taxonomy.php * * @access private * @since 8.1 * @static * * @global $wpdb * * @uses childrenIDs() * @uses is_user_logged_in() * @uses current_user_can() * @uses wpdb::get_results() * * @param array $terms List of Term IDs * @param string $taxonomy Term Context * * @return null Will break from function if conditions are not met. */ private static function padCounts(&$terms, $taxonomy) { /** @var wpdb $wpdb */ global $wpdb; $term_ids = array(); $visibility = array(); // Grab an instance of the Connections object. /** @var connectionsLoad $instance */ $instance = Connections_Directory(); // This function only works for hierarchical taxonomies like post categories. // if ( !is_taxonomy_hierarchical( $taxonomy ) ) // return; $term_hier = self::childrenIDs($taxonomy); if (empty($term_hier)) { return; } $term_items = array(); foreach ((array) $terms as $key => $term) { $terms_by_id[$term->term_id] =& $terms[$key]; $term_ids[$term->term_taxonomy_id] = $term->term_id; } /* * // START --> Set up the query to only return the entries based on user permissions. */ if (is_user_logged_in()) { if (current_user_can('connections_view_public')) { $visibility[] = 'public'; } if (current_user_can('connections_view_private')) { $visibility[] = 'private'; } if (current_user_can('connections_view_unlisted') && is_admin()) { $visibility[] = 'unlisted'; } } else { // Display the 'public' entries if the user is not required to be logged in. $visibility[] = $instance->options->getAllowPublic() ? 'public' : ''; } /* * // END --> Set up the query to only return the entries based on user permissions. */ // Get the object and term ids and stick them in a lookup table // $tax_obj = get_taxonomy( $taxonomy ); $entry_types = array('individual', 'organization', 'family'); $results = $wpdb->get_results("SELECT entry_id, term_taxonomy_id FROM " . CN_TERM_RELATIONSHIP_TABLE . " INNER JOIN " . CN_ENTRY_TABLE . " ON entry_id = id WHERE term_taxonomy_id IN (" . implode(',', array_keys($term_ids)) . ") AND entry_type IN ('" . implode("', '", $entry_types) . "') AND visibility IN ('" . implode("', '", (array) $visibility) . "')"); foreach ($results as $row) { $id = $term_ids[$row->term_taxonomy_id]; $term_items[$id][$row->entry_id] = isset($term_items[$id][$row->entry_id]) ? ++$term_items[$id][$row->entry_id] : 1; } // Touch every ancestor's lookup row for each post in each term foreach ($term_ids as $term_id) { $child = $term_id; while (!empty($terms_by_id[$child]) && ($parent = $terms_by_id[$child]->parent)) { if (!empty($term_items[$term_id])) { foreach ($term_items[$term_id] as $item_id => $touches) { $term_items[$parent][$item_id] = isset($term_items[$parent][$item_id]) ? ++$term_items[$parent][$item_id] : 1; } } $child = $parent; } } // Transfer the touched cells foreach ((array) $term_items as $id => $items) { if (isset($terms_by_id[$id])) { $terms_by_id[$id]->count = count($items); } } }
/** * Echo or return the entry's phone numbers in a HTML hCard compliant string. * * Accepted options for the $atts property are: * preferred (bool) Retrieve the preferred entry phone number. * type (array) || (string) Retrieve specific phone number types. * Permitted Types: * homephone * homefax * cellphone * workphone * workfax * format (string) The tokens to use to display the phone number block parts. * Permitted Tokens: * %label% * %number% * %separator% * separator (string) The separator to use. * before (string) HTML to output before the phone numbers. * after (string) HTML to after before the phone numbers. * return (bool) Return string if set to TRUE instead of echo string. * * Filters: * cn_output_default_atts_phone => (array) Register the methods default attributes. * * @access public * @since unknown * * @param array $atts Accepted values as noted above. * @param bool $cached Returns the cached data rather than querying the db. * * @return string */ public function getPhoneNumberBlock($atts = array(), $cached = TRUE) { // Grab an instance of the Connections object. $instance = Connections_Directory(); /* * // START -- Set the default attributes array. \\ */ $defaults = array('preferred' => NULL, 'type' => NULL, 'limit' => NULL, 'format' => '', 'separator' => ':', 'before' => '', 'after' => '', 'return' => FALSE); $defaults = apply_filters('cn_output_default_atts_phone', $defaults); $atts = cnSanitize::args($atts, $defaults); $atts['id'] = $this->getId(); /* * // END -- Set the default attributes array if not supplied. \\ */ $rows = array(); $phoneNumbers = $this->getPhoneNumbers($atts, $cached); $search = array('%label%', '%number%', '%separator%'); if (empty($phoneNumbers)) { return ''; } foreach ($phoneNumbers as $phone) { $replace = array(); $row = "\t" . '<span class="tel">'; $replace[] = empty($phone->name) ? '' : '<span class="phone-name">' . $phone->name . '</span>'; if (empty($phone->number)) { $replace[] = ''; } else { if ($instance->settings->get('connections', 'link', 'phone')) { $replace[] = '<a class="value" href="tel:' . $phone->number . '" value="' . preg_replace('/[^0-9]/', '', $phone->number) . '">' . $phone->number . '</a>'; } else { $replace[] = '<span class="value">' . $phone->number . '</span>'; } } $replace[] = '<span class="cn-separator">' . $atts['separator'] . '</span>'; $row .= str_ireplace($search, $replace, empty($atts['format']) ? empty($defaults['format']) ? '%label%%separator% %number%' : $defaults['format'] : $atts['format']); // Set the hCard Phone Number Type. $row .= $this->gethCardTelType($phone->type); $row .= '</span>' . PHP_EOL; $rows[] = apply_filters('cn_output_phone_number', cnString::replaceWhatWith($row, ' '), $phone, $this, $atts); } $block = '<span class="phone-number-block">' . PHP_EOL . implode(PHP_EOL, $rows) . PHP_EOL . '</span>'; $block = apply_filters('cn_output_phone_numbers', $block, $phoneNumbers, $this, $atts); $html = $atts['before'] . $block . $atts['after'] . PHP_EOL; return $this->echoOrReturn($atts['return'], $html); }
/** * Register the user friendly column header names. * * @access private * @since 8.5.1 * * @return array */ private function setHeaderNames() { // Grab an instance of the Connections object. $instance = Connections_Directory(); // Core fields. $fields = array('id' => 'Entry ID', 'entry_type' => 'Entry Type', 'visibility' => 'Visibility', 'family_name' => 'Family Name', 'honorific_prefix' => 'Honorific Prefix', 'first_name' => 'First Name', 'middle_name' => 'Middle Name', 'last_name' => 'Last Name', 'honorific_suffix' => 'Honorific Suffix', 'title' => 'Title', 'organization' => 'Organization', 'department' => 'Department', 'contact_first_name' => 'Contact First Name', 'contact_last_name' => 'Contact Last Name', 'bio' => 'Biography', 'notes' => 'Notes'); $fields['category'] = 'Categories'; /* * Build the array of core and extended address fields for mapping during import. */ $coreAddressTypes = $instance->options->getDefaultAddressValues(); $addressFields = array('line_1' => 'Line One', 'line_2' => 'Line Two', 'line_3' => 'Line Three', 'line_4' => 'Line Four', 'district' => 'District', 'county' => 'County', 'city' => 'City', 'state' => 'State', 'zipcode' => 'Zipcode', 'country' => 'Country', 'latitude' => 'Latitude', 'longitude' => 'Longitude', 'visibility' => 'Visibility'); /* * Add the core address types to the field array. */ foreach ($coreAddressTypes as $addressType => $addressName) { foreach ($addressFields as $addressFieldType => $addressFieldName) { $key = 'address_' . $addressType . '_' . $addressFieldType; $fields[$key] = $addressName . ' Address | ' . $addressFieldName; } } /* * Build the array of core phone fields for mapping during import. */ $corePhoneTypes = $instance->options->getDefaultPhoneNumberValues(); $phoneFields = array('number' => 'Number', 'visibility' => 'Visibility'); // Add the core phone types to the field array. foreach ($corePhoneTypes as $phoneType => $phoneName) { foreach ($phoneFields as $phoneFieldType => $phoneFieldName) { $key = 'phone_' . $phoneType . '_' . $phoneFieldType; $fields[$key] = 'Phone | ' . $phoneName . ' | ' . $phoneFieldName; } } /* * Build the array of core email fields for mapping during import. */ $coreEmailTypes = $instance->options->getDefaultEmailValues(); $emailFields = array('address' => 'Address', 'visibility' => 'Visibility'); // Add the core email types to the field array. foreach ($coreEmailTypes as $emailType => $emailName) { foreach ($emailFields as $emailFieldType => $emailFieldName) { $key = 'email_' . $emailType . '_' . $emailFieldType; $fields[$key] = 'Email | ' . $emailName . ' | ' . $emailFieldName; } } /* * Build the array of core IM fields for mapping during import. */ $coreIMTypes = $instance->options->getDefaultIMValues(); $IMFields = array('uid' => 'User ID', 'visibility' => 'Visibility'); // Add the core IM types to the field array. foreach ($coreIMTypes as $IMType => $IMName) { foreach ($IMFields as $IMFieldType => $IMFieldName) { $key = 'im_' . $IMType . '_' . $IMFieldType; $fields[$key] = 'Messenger | ' . $IMName . ' | ' . $IMFieldName; } } /* * Build the array of core social media fields for mapping during import. */ $coreSocialTypes = $instance->options->getDefaultSocialMediaValues(); $socialFields = array('url' => 'URL', 'visibility' => 'Visibility'); // Add the core email types to the field array. foreach ($coreSocialTypes as $socialType => $socialName) { foreach ($socialFields as $socialFieldType => $socialFieldName) { $key = 'social_' . $socialType . '_' . $socialFieldType; $fields[$key] = 'Social Network | ' . $socialName . ' | ' . $socialFieldName; } } /* * Build the array of core link fields for mapping during import. */ $coreLinkTypes = $instance->options->getDefaultLinkValues(); $linkFields = array('url' => 'URL', 'visibility' => 'Visibility'); // Add the core email types to the field array. foreach ($coreLinkTypes as $linkType => $linkName) { foreach ($linkFields as $linkFieldType => $linkFieldName) { $key = 'links_' . $linkType . '_' . $linkFieldType; $fields[$key] = 'Link | ' . $linkName . ' | ' . $linkFieldName; } } /* * Build the array of core date fields for mapping during import. */ $coreDateTypes = $instance->options->getDateOptions(); $dateFields = array('date' => 'Date', 'visibility' => 'Visibility'); // Add the core date types to the field array. foreach ($coreDateTypes as $dateType => $dateName) { foreach ($dateFields as $dateFieldType => $dateFieldName) { $key = 'dates_' . $dateType . '_' . $dateFieldType; $fields[$key] = 'Date | ' . $dateName . ' | ' . $dateFieldName; } } $fields['options_image_url'] = 'Photo URL'; $fields['options_logo_url'] = 'Logo URL'; $this->headerNames = apply_filters('cn_csv_export_fields', $fields); }
/** * The dashboard widget used to display the recently added/modified entries. * * @access public * @since 0.8 * @param object $null Generally a $post or $entry object. Not used in Connections core. * @param array $metabox The metabox options array from self::register(). * @return string The recently added/modifed entries. */ public static function recent($null, $metabox) { // Grab an instance of the Connections object. $instance = Connections_Directory(); add_filter('cn_list_results', array($instance->retrieve, 'removeUnknownDateAdded'), 9); remove_action('cn_list_actions', array('cnTemplatePart', 'listActions')); $atts = array('order_by' => $metabox['args']['order_by'], 'template' => $metabox['args']['template'], 'show_alphaindex' => FALSE, 'show_alphahead' => FALSE, 'limit' => $metabox['args']['limit'], 'status' => $metabox['args']['status']); connectionsEntryList($atts); remove_filter('cn_list_results', array($instance->retrieve, 'removeUnknownDateAdded'), 9); }
/** * Renders the social media network field. * * @access private * @since 8.5.11 * * @param stdClass $date * @param string $token */ private static function dateField($date, $token = '::FIELD::') { // Grab an instance of the Connections object. $instance = Connections_Directory(); // Grab the date types. $dateTypes = $instance->options->getDateOptions(); ?> <div class="widget-top"> <div class="widget-title-action"><a class="widget-action"></a></div> <div class="widget-title"> <h4> <?php cnHTML::field(array('type' => 'select', 'class' => '', 'id' => 'date[' . $token . '][type]', 'options' => $dateTypes, 'required' => FALSE, 'label' => __('Type', 'connections'), 'return' => FALSE), isset($date->type) ? $date->type : ''); cnHTML::field(array('type' => 'radio', 'format' => 'inline', 'class' => '', 'id' => 'date[preferred]', 'options' => array($token => __('Preferred', 'connections')), 'required' => FALSE, 'before' => '<span class="preferred">', 'after' => '</span>', 'return' => FALSE), isset($date->preferred) && $date->preferred ? $token : ''); // Only show this if there are visibility options that the user is permitted to see. if (!empty(self::$visibility)) { cnHTML::field(array('type' => 'radio', 'format' => 'inline', 'class' => '', 'id' => 'date[' . $token . '][visibility]', 'options' => self::$visibility, 'required' => FALSE, 'before' => '<span class="visibility">' . __('Visibility', 'connections') . ' ', 'after' => '</span>', 'return' => FALSE), isset($date->visibility) ? $date->visibility : 'public'); } ?> </h4> </div> </div> <div class="widget-inside"> <?php cnHTML::field(array('type' => 'text', 'class' => 'datepicker', 'id' => 'date[' . $token . '][date]', 'required' => FALSE, 'label' => __('Date', 'connections'), 'before' => '', 'after' => '', 'return' => FALSE), isset($date->date) ? date('m/d/Y', strtotime($date->date)) : ''); ?> <?php if (isset($date->id)) { ?> <input type="hidden" name="date[<?php echo $token; ?> ][id]" value="<?php echo $date->id; ?> "> <?php } ?> <p class="cn-remove-button"> <a href="#" class="cn-remove cn-button button cn-button-warning" data-type="date" data-token="<?php echo $token; ?> "><?php esc_html_e('Remove', 'connections'); ?> </a> </p> </div> <?php }
/** * Add rating links to the admin dashboard * * @access private * @since 8.2.9 * * @param string $text The existing footer text * * @return string */ public static function rateUs($text) { if (defined('DOING_AJAX') && DOING_AJAX) { return $text; } // Grab an instance of the Connections object. $instance = Connections_Directory(); //var_dump( get_current_screen()->id ); //var_dump( $instance->pageHook ); if (in_array(get_current_screen()->id, get_object_vars($instance->pageHook))) { //if ( in_array( get_current_screen()->id, (array) $instance->pageHook ) ) { $rate_text = sprintf(__('Thank you for using <a href="%1$s" target="_blank">Connections Business Directory</a>! Please <a href="%2$s" target="_blank">rate us</a> on <a href="%2$s" target="_blank">WordPress.org</a>', 'connections'), 'http://connections-pro.com', 'https://wordpress.org/support/view/plugin-reviews/connections?filter=5#postform'); return str_replace('</span>', '', $text) . ' | ' . $rate_text . '</span>'; } else { return $text; } }
function connectionsShowCategoriesPage() { /* * Check whether user can edit categories. */ if (!current_user_can('connections_edit_categories')) { wp_die('<p id="error-page" style="-moz-background-clip:border; -moz-border-radius:11px; background:#FFFFFF none repeat scroll 0 0; border:1px solid #DFDFDF; color:#333333; display:block; font-size:12px; line-height:18px; margin:25px auto 20px; padding:1em 2em; text-align:center; width:700px">' . __('You do not have sufficient permissions to access this page.', 'connections') . '</p>'); } else { // Grab an instance of the Connections object. $instance = Connections_Directory(); $form = new cnFormObjects(); $taxonomy = 'category'; $action = ''; if (isset($_GET['cn-action'])) { $action = $_GET['cn-action']; } if ($action === 'edit_category') { $id = absint($_GET['id']); check_admin_referer('category_edit_' . $id); $term = $instance->retrieve->category($id); $category = new cnCategory($term); /** * Fires before the Edit Term form for all taxonomies. * * The dynamic portion of the hook name, `$taxonomy`, refers to * the taxonomy slug. * * @since 3.0.0 * * @param object $tag Current taxonomy term object. * @param string $taxonomy Current $taxonomy slug. */ do_action("cn_{$taxonomy}_pre_edit_form", $term, $taxonomy); ?> <div class="wrap"> <div class="form-wrap" style="width:600px; margin: 0 auto;"> <h2><a name="new"></a><?php _e('Edit Category', 'connections'); ?> </h2> <?php $attr = array('action' => '', 'method' => 'post', 'id' => 'addcat', 'name' => 'updatecategory'); $form->open($attr); $form->tokenField('update_category'); /** * Fires inside the Edit Term form tag. * * The dynamic portion of the hook name, `$taxonomy`, refers to * the taxonomy slug. * * @since 3.7.0 */ do_action("cn_{$taxonomy}_term_edit_form_tag"); ?> <div class="form-field form-required term-name-wrap"> <label for="category_name"><?php _e('Name', 'connections'); ?> </label> <input type="text" aria-required="true" size="40" value="<?php echo esc_attr($category->getName()); ?> " id="category_name" name="category_name"/> <input type="hidden" value="<?php echo esc_attr($category->getID()); ?> " id="category_id" name="category_id"/> <p><?php _e('The name is how it appears on your site.', 'connections'); ?> </p> </div> <div class="form-field term-slug-wrap"> <label for="category_slug"><?php _e('Slug', 'connections'); ?> </label> <input type="text" size="40" value="<?php echo esc_attr($category->getSlug()); ?> " id="category_slug" name="category_slug"/> <p><?php _e('The “slug” is the URL-friendly version of the name. It is usually all lowercase and contains only letters, numbers, and hyphens.', 'connections'); ?> </p> </div> <div class="form-field term-parent-wrap"> <label for="category_parent"><?php _e('Parent', 'connections'); ?> </label> <?php cnTemplatePart::walker('term-select', array('hide_empty' => 0, 'hide_if_empty' => FALSE, 'name' => 'category_parent', 'orderby' => 'name', 'taxonomy' => 'category', 'selected' => $category->getParent(), 'exclude_tree' => $category->getID(), 'hierarchical' => TRUE, 'show_option_none' => __('None', 'connections'))); ?> <p><?php _e('Categories can have a hierarchy. You might have a Jazz category, and under that have children categories for Bebop and Big Band. Totally optional.', 'connections'); ?> </p> </div> <div class="form-field term-description-wrap"> <?php ob_start(); /* * Now we're going to have to keep track of which TinyMCE plugins * WP core supports based on version, sigh. */ if (version_compare($GLOBALS['wp_version'], '3.8.999', '<')) { $tinymcePlugins = array('inlinepopups', 'tabfocus', 'paste', 'wordpress', 'wplink', 'wpdialogs'); } else { $tinymcePlugins = array('tabfocus', 'paste', 'wordpress', 'wplink', 'wpdialogs'); } wp_editor(wp_kses_post($category->getDescription()), 'category_description', array('media_buttons' => FALSE, 'tinymce' => array('editor_selector' => 'tinymce', 'toolbar1' => 'bold, italic, underline, |, bullist, numlist, |, justifyleft, justifycenter, justifyright, alignleft, aligncenter, alignright, |, link, unlink, |, pastetext, pasteword, removeformat, |, undo, redo', 'toolbar2' => '', 'inline_styles' => TRUE, 'relative_urls' => FALSE, 'remove_linebreaks' => FALSE, 'plugins' => implode(',', $tinymcePlugins)))); echo ob_get_clean(); ?> </div> <?php /** * Fires after the Edit Term form fields are displayed. * * The dynamic portion of the hook name, `$taxonomy`, refers to * the taxonomy slug. * * @since 3.0.0 * * @param object $tag Current taxonomy term object. * @param string $taxonomy Current taxonomy slug. */ do_action("cn_{$taxonomy}_edit_form_fields", $term, $taxonomy); /** * Fires at the end of the Edit Term form for all taxonomies. * * The dynamic portion of the hook name, `$taxonomy`, refers to the taxonomy slug. * * @since 3.0.0 * * @param object $tag Current taxonomy term object. * @param string $taxonomy Current taxonomy slug. */ do_action("{$taxonomy}_edit_form", $term, $taxonomy); ?> <input type="hidden" name="cn-action" value="update_category"/> <p class="submit"> <a class="button button-warning" href="admin.php?page=connections_categories"><?php _e('Cancel', 'connections'); ?> </a> <input type="submit" name="update" id="update" class="button button-primary" value="<?php _e('Update Category', 'connections'); ?> "/> </p> <?php $form->close(); ?> </div> </div> <?php } else { /** * @var CN_Terms_List_Table $table */ $table = cnTemplatePart::table('term-admin', array('screen' => get_current_screen()->id)); $table->prepare_items(); ?> <div class="wrap nosubsub"> <h2>Connections : <?php _e('Categories', 'connections'); ?> </h2> <form class="search-form" action="" method="get"> <input type="hidden" name="page" value="<?php echo esc_attr($_REQUEST['page']); ?> "/> <?php $table->search_box(__('Search Categories', 'connections'), 'category'); ?> </form> <br class="clear"/> <div id="col-container"> <div id="col-right"> <div class="col-wrap"> <?php $attr = array('action' => '', 'method' => 'post'); $form->open($attr); //$form->tokenField( 'bulk_delete_category' ); ?> <input type="hidden" name="cn-action" value="category_bulk_actions"/> <?php $table->display(); $form->close(); ?> <br class="clear" /> <script type="text/javascript"> /* <![CDATA[ */ (function ($) { $(document).ready(function () { $('#doaction, #doaction2').click(function () { if ($('select[name^="action"]').val() == 'delete') { var m = 'You are about to delete the selected category(ies).\n \'Cancel\' to stop, \'OK\' to delete.'; return showNotice.warn(m); } }); }); })(jQuery); /* ]]> */ </script> <div class="form-wrap"> <p><?php _e('<strong>Note:</strong><br/>Deleting a category which has been assigned to an entry will reassign that entry as <strong>Uncategorized</strong>.', 'connections'); ?> </p> </div> <?php /** * Fires after the taxonomy list table. * * The dynamic portion of the hook name, `$taxonomy`, refers to the taxonomy slug. * * @since 3.0.0 * * @param string $taxonomy The taxonomy name. */ do_action("cn_after-{$taxonomy}-table", $taxonomy); ?> </div> </div> <!-- right column --> <div id="col-left"> <div class="col-wrap"> <?php /** * Fires before the Add Term form for all taxonomies. * * The dynamic portion of the hook name, `$taxonomy`, refers to the taxonomy slug. * * @since 3.0.0 * * @param string $taxonomy The taxonomy slug. */ do_action("cn_{$taxonomy}_pre_add_form", $taxonomy); ?> <div class="form-wrap"> <h3><?php _e('Add New Category', 'connections'); ?> </h3> <?php $attr = array('action' => '', 'method' => 'post'); $form->open($attr); $form->tokenField('add_category'); /** * Fires at the beginning of the Add Tag form. * * The dynamic portion of the hook name, `$taxonomy`, refers to the taxonomy slug. * * @since 3.7.0 */ do_action("cn_{$taxonomy}_term_new_form_tag"); ?> <div class="form-field form-required term-name-wrap"> <label for="category_name"><?php _e('Name', 'connections'); ?> </label> <input type="text" aria-required="true" size="40" value="" id="category_name" name="category_name"/> <input type="hidden" value="" id="category_id" name="category_id"/> <p><?php _e('The name is how it appears on your site.', 'connections'); ?> </p> </div> <div class="form-field term-slug-wrap"> <label for="category_slug"><?php _e('Slug', 'connections'); ?> </label> <input type="text" size="40" value="" id="category_slug" name="category_slug"/> <p><?php _e('The “slug” is the URL-friendly version of the name. It is usually all lowercase and contains only letters, numbers, and hyphens.', 'connections'); ?> </p> </div> <div class="form-field term-parent-wrap"> <label for="category_parent"><?php _e('Parent', 'connections'); ?> </label> <?php $dropdown_args = array('hide_empty' => 0, 'hide_if_empty' => FALSE, 'taxonomy' => 'category', 'name' => 'category_parent', 'orderby' => 'name', 'hierarchical' => TRUE, 'show_option_none' => __('None', 'connections')); /** * Filter the taxonomy parent drop-down on the Edit Term page. * * @since 3.7.0 * * @param array $dropdown_args { * An array of taxonomy parent drop-down arguments. * * @type int|bool $hide_empty Whether to hide terms not attached to any posts. Default 0|false. * @type bool $hide_if_empty Whether to hide the drop-down if no terms exist. Default false. * @type string $taxonomy The taxonomy slug. * @type string $name Value of the name attribute to use for the drop-down select element. * Default 'parent'. * @type string $orderby The field to order by. Default 'name'. * @type bool $hierarchical Whether the taxonomy is hierarchical. Default true. * @type string $show_option_none Label to display if there are no terms. Default 'None'. * } * * @param string $taxonomy The taxonomy slug. */ $dropdown_args = apply_filters('cn_taxonomy_parent_dropdown_args', $dropdown_args, 'category'); cnTemplatePart::walker('term-select', $dropdown_args); ?> <p><?php _e('Categories can have a hierarchy. You might have a Jazz category, and under that have children categories for Bebop and Big Band. Totally optional.', 'connections'); ?> </p> </div> <div class="form-field term-description-wrap"> <?php ob_start(); /* * Now we're going to have to keep track of which TinyMCE plugins * WP core supports based on version, sigh. */ if (version_compare($GLOBALS['wp_version'], '3.8.999', '<')) { $tinymcePlugins = array('inlinepopups', 'tabfocus', 'paste', 'wordpress', 'wplink', 'wpdialogs'); } else { $tinymcePlugins = array('tabfocus', 'paste', 'wordpress', 'wplink', 'wpdialogs'); } wp_editor('', 'category_description', array('media_buttons' => FALSE, 'tinymce' => array('editor_selector' => 'tinymce', 'toolbar1' => 'bold, italic, underline, |, bullist, numlist, |, justifyleft, justifycenter, justifyright, alignleft, aligncenter, alignright, |, link, unlink, |, pastetext, pasteword, removeformat, |, undo, redo', 'toolbar2' => '', 'inline_styles' => TRUE, 'relative_urls' => FALSE, 'remove_linebreaks' => FALSE, 'plugins' => implode(',', $tinymcePlugins)))); echo ob_get_clean(); ?> </div> <input type="hidden" name="cn-action" value="add_category"/> <?php /** * Fires after the Add Term form fields for hierarchical taxonomies. * * The dynamic portion of the hook name, `$taxonomy`, refers to the taxonomy slug. * * @since 3.0.0 * * @param string $taxonomy The taxonomy slug. */ do_action("cn_{$taxonomy}_add_form_fields", $taxonomy); submit_button(__('Add New Category', 'connections'), 'primary', 'add'); /** * Fires at the end of the Add Term form for all taxonomies. * * The dynamic portion of the hook name, `$taxonomy`, refers to the taxonomy slug. * * @since 3.0.0 * * @param string $taxonomy The taxonomy slug. */ do_action("cn_{$taxonomy}_add_form", $taxonomy); ?> <?php $form->close(); ?> </div> </div> </div> <!-- left column --> </div> <!-- Column container --> </div> <?php } } }
/** * @param array $atts * @param string $content * @param string $tag * * @return string */ public static function shortcode($atts, $content = '', $tag = 'connections') { // Grab an instance of the Connections object. $instance = Connections_Directory(); $html = ''; if (is_customize_preview()) { /** * Hook to allow the active template to be overridden and set to the current template being customized. * * @since 8.4 * * @param array $atts { * @type string $template The template slug of the template being customized. * } */ $atts = apply_filters('cn_template_customizer_template', $atts); } /** @var cnTemplate $template */ $template = cnTemplateFactory::loadTemplate($atts); if ($template === FALSE) { return cnTemplatePart::loadTemplateError($atts); } /* * 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')); self::addFilterRegistry('cn_locate_file_paths'); do_action('cn_template_include_once-' . $template->getSlug()); do_action('cn_template_enqueue_js-' . $template->getSlug()); /* * Now that the template has been loaded, Validate the user supplied shortcode atts. */ $defaults = array('id' => NULL, 'slug' => NULL, 'category' => NULL, 'category_in' => NULL, 'exclude_category' => NULL, 'category_name' => NULL, 'category_slug' => NULL, 'wp_current_category' => FALSE, 'allow_public_override' => FALSE, 'private_override' => FALSE, 'show_alphaindex' => cnSettingsAPI::get('connections', 'display_results', 'index'), 'repeat_alphaindex' => cnSettingsAPI::get('connections', 'display_results', 'index_repeat'), 'show_alphahead' => cnSettingsAPI::get('connections', 'display_results', 'show_current_character'), 'list_type' => NULL, 'order_by' => NULL, 'limit' => NULL, 'offset' => NULL, 'family_name' => NULL, 'last_name' => NULL, 'title' => NULL, 'organization' => NULL, 'department' => NULL, 'district' => NULL, 'county' => NULL, 'city' => NULL, 'state' => NULL, 'zip_code' => NULL, 'country' => NULL, 'meta_query' => '', 'content' => '', 'near_addr' => NULL, 'latitude' => NULL, 'longitude' => NULL, 'radius' => 10, 'unit' => 'mi', 'template' => NULL, 'width' => NULL, 'lock' => FALSE, 'force_home' => FALSE, 'home_id' => in_the_loop() && is_page() ? get_the_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['allow_public_override']); cnFormatting::toBoolean($atts['private_override']); cnFormatting::toBoolean($atts['show_alphaindex']); cnFormatting::toBoolean($atts['repeat_alphaindex']); cnFormatting::toBoolean($atts['show_alphahead']); cnFormatting::toBoolean($atts['wp_current_category']); cnFormatting::toBoolean($atts['lock']); cnFormatting::toBoolean($atts['force_home']); // var_dump( $atts ); /* * The post editor entity encodes the post text we have to decode it * so a match can be made when the query is run. */ $atts['family_name'] = html_entity_decode($atts['family_name']); $atts['last_name'] = html_entity_decode($atts['last_name']); $atts['title'] = html_entity_decode($atts['title']); $atts['organization'] = html_entity_decode($atts['organization']); $atts['department'] = html_entity_decode($atts['department']); $atts['city'] = html_entity_decode($atts['city']); $atts['state'] = html_entity_decode($atts['state']); $atts['zip_code'] = html_entity_decode($atts['zip_code']); $atts['country'] = html_entity_decode($atts['country']); $atts['category_name'] = html_entity_decode($atts['category_name']); if (0 < strlen($atts['meta_query'])) { // The meta query syntax follows the JSON standard, except, the WordPress Shortcode API does not allow // brackets within shortcode options, so parenthesis have to be used instead, so, lets swap them // that was json_decode can be ran and the resulting array used in cnRetrieve::entries(). $atts['meta_query'] = str_replace(array('(', ')'), array('[', ']'), $atts['meta_query']); $metaQuery = cnFormatting::maybeJSONdecode($atts['meta_query']); $atts['meta_query'] = is_array($metaQuery) ? $metaQuery : array(); } $atts = apply_filters('cn_list_retrieve_atts', $atts); $atts = apply_filters('cn_list_retrieve_atts-' . $template->getSlug(), $atts); $results = $instance->retrieve->entries($atts); // $html .= print_r( $instance->lastQuery, TRUE ); // Apply any registered filters to the results. if (!empty($results)) { $results = apply_filters('cn_list_results', $results); $results = apply_filters('cn_list_results-' . $template->getSlug(), $results); self::addFilterRegistry('cn_list_results-' . $template->getSlug()); } ob_start(); // Prints the template's CSS file. // NOTE: This is primarily to support legacy templates which included a CSS // file which was not enqueued in the page header. do_action('cn_template_inline_css-' . $template->getSlug(), $atts); // The return to top anchor do_action('cn_list_return_to_target', $atts); $html .= ob_get_clean(); $html .= sprintf('<div class="cn-list" id="cn-list" data-connections-version="%1$s-%2$s"%3$s>', $instance->options->getVersion(), $instance->options->getDBVersion(), empty($atts['width']) ? '' : ' style="width: ' . $atts['width'] . 'px;"'); $html .= sprintf('<div class="cn-template cn-%1$s" id="cn-%1$s" data-template-version="%2$s">', $template->getSlug(), $template->getVersion()); // The filter should check $content that content is not empty before processing $content. // And if it is empty the filter should return (bool) FALSE, so the core template parts can be executed. $content = apply_filters("cn_shortcode_content-{$tag}", FALSE, $content, $atts, $results, $template); if ($content === FALSE) { ob_start(); // Render the core result list header. cnTemplatePart::header($atts, $results, $template); // Render the core result list body. cnTemplatePart::body($atts, $results, $template); // Render the core result list footer. cnTemplatePart::footer($atts, $results, $template); $html .= ob_get_clean(); } else { $html .= $content; } $html .= PHP_EOL . '</div>' . (WP_DEBUG ? '<!-- END #cn-' . $template->getSlug() . ' -->' : '') . PHP_EOL; $html .= PHP_EOL . '</div>' . (WP_DEBUG ? '<!-- END #cn-list -->' : '') . PHP_EOL; // Clear any filters that have been added. // This allows support using the shortcode multiple times on the same page. cnShortcode::clearFilterRegistry(); // @todo This should be run via a filter. return self::removeEOL($html); }
/** * This is the registered function calls for the Connections admin pages as registered * using the add_menu_page() and add_submenu_page() WordPress functions. * * @access private * @since unknown */ public static function showPage() { // Grab an instance of the Connections object. $instance = Connections_Directory(); if ($instance->dbUpgrade) { include_once CN_PATH . 'includes/inc.upgrade.php'; connectionsShowUpgradePage(); return; } switch ($_GET['page']) { case 'connections_dashboard': include_once CN_PATH . 'includes/admin/pages/dashboard.php'; connectionsShowDashboardPage(); break; case 'connections_manage': include_once CN_PATH . 'includes/admin/pages/manage.php'; $action = isset($_GET['cn-action']) && !empty($_GET['cn-action']) ? $_GET['cn-action'] : ''; connectionsShowViewPage(esc_attr($action)); break; case 'connections_add': include_once CN_PATH . 'includes/admin/pages/manage.php'; connectionsShowViewPage('add_entry'); break; case 'connections_categories': include_once CN_PATH . 'includes/admin/pages/categories.php'; connectionsShowCategoriesPage(); break; case 'connections_settings': include_once CN_PATH . 'includes/admin/pages/settings.php'; connectionsShowSettingsPage(); break; case 'connections_tools': include_once CN_PATH . 'includes/admin/pages/tools.php'; connectionsShowToolsPage(); break; case 'connections_templates': include_once CN_PATH . 'includes/admin/pages/templates.php'; connectionsShowTemplatesPage(); break; case 'connections_roles': include_once CN_PATH . 'includes/admin/pages/roles.php'; connectionsShowRolesPage(); break; } }
/** * Register the metaboxes. * * @access private * @since 0.8 * * @global string $hook_suffix The current admin page hook. * * @return void */ public static function register() { global $hook_suffix; // Grab an instance of the Connections object. $instance = Connections_Directory(); // The metaboxes only need to be added on the manage page if performing an action to an entry. // This is to prevent the metaboxes from showing on the Screen Option tab on the Manage // admin page when viewing the manage entries table. if ($hook_suffix == $instance->pageHook->manage && !isset($_GET['cn-action'])) { return; } foreach (self::$metaboxes as $metabox) { if (in_array($hook_suffix, $metabox['pages'])) { cnMetabox_Render::add($hook_suffix, $metabox); } } }
/** * Return an array of entry ID/s found with the supplied search terms. * * @todo Allow the fields for each table to be defined as a comma delimited list, convert an array and validate against of list of valid table fields. * @todo Add a filter to allow the search fields to be changed. * * Resources used: * http://devzone.zend.com/26/using-mysql-full-text-searching/ * http://onlamp.com/onlamp/2003/06/26/fulltext.html * * @since 0.7.2.0 * @param array $atts [optional] * * @return array */ public function search($atts = array()) { /** @var wpdb $wpdb */ global $wpdb; // Grab an instance of the Connections object. $instance = Connections_Directory(); $results = array(); $scored = array(); $fields = $instance->options->getSearchFields(); $fields = apply_filters('cn_search_fields', $fields); // If no search search fields are set, return an empty array. if (empty($fields)) { return array(); } /* * // START -- Set the default attributes array. \\ */ $defaults['terms'] = array(); if (in_array('family_name', $fields)) { $defaults['fields']['entry'][] = 'family_name'; } if (in_array('first_name', $fields)) { $defaults['fields']['entry'][] = 'first_name'; } if (in_array('middle_name', $fields)) { $defaults['fields']['entry'][] = 'middle_name'; } if (in_array('last_name', $fields)) { $defaults['fields']['entry'][] = 'last_name'; } if (in_array('title', $fields)) { $defaults['fields']['entry'][] = 'title'; } if (in_array('organization', $fields)) { $defaults['fields']['entry'][] = 'organization'; } if (in_array('department', $fields)) { $defaults['fields']['entry'][] = 'department'; } if (in_array('contact_first_name', $fields)) { $defaults['fields']['entry'][] = 'contact_first_name'; } if (in_array('contact_last_name', $fields)) { $defaults['fields']['entry'][] = 'contact_last_name'; } if (in_array('bio', $fields)) { $defaults['fields']['entry'][] = 'bio'; } if (in_array('notes', $fields)) { $defaults['fields']['entry'][] = 'notes'; } if (in_array('address_line_1', $fields)) { $defaults['fields']['address'][] = 'line_1'; } if (in_array('address_line_2', $fields)) { $defaults['fields']['address'][] = 'line_2'; } if (in_array('address_line_3', $fields)) { $defaults['fields']['address'][] = 'line_3'; } if (in_array('address_city', $fields)) { $defaults['fields']['address'][] = 'city'; } if (in_array('address_state', $fields)) { $defaults['fields']['address'][] = 'state'; } if (in_array('address_zipcode', $fields)) { $defaults['fields']['address'][] = 'zipcode'; } if (in_array('address_country', $fields)) { $defaults['fields']['address'][] = 'country'; } if (in_array('phone_number', $fields)) { $defaults['fields']['phone'][] = 'number'; } $atts = wp_parse_args($atts, apply_filters('cn_search_atts', $defaults)); // @todo Validate each fiels array to ensure only permitted fields will be used. /* * // END -- Set the default attributes array if not supplied. \\ */ // If no search terms were entered, return an empty array. if (empty($atts['terms'])) { return array(); } // If value is a string, stripe the white space and covert to an array. if (!is_array($atts['terms'])) { $atts['terms'] = explode(' ', trim($atts['terms'])); } // Trim any white space from around the terms in the array. array_walk($atts['terms'], 'trim'); $atts['terms'] = apply_filters('cn_search_terms', $atts['terms']); // Remove any single characters and stop words from terms. $atts['terms'] = $this->parse_search_terms($atts['terms']); // If no search terms are left after removing stop words, return an empty array. if (empty($atts['terms'])) { return array(); } /* * Perform search using FULLTEXT if enabled. * * Perform the search on each table individually because joining the tables doesn't scale when * there are a large number of entries. * * NOTES: * The following is the error reported by MySQL when DB does not support FULLTEXT: 'The used table type doesn't support FULLTEXT indexes' * If DB does not support FULLTEXT the query will fail and the $results will be an empty array. * * FULLTEXT Restrictions as noted here: http://onlamp.com/onlamp/2003/06/26/fulltext.html * * Some of the default behaviors of these restrictions can be changed in your my.cnf or using the SET command * * FULLTEXT indices are NOT supported in InnoDB tables. * MySQL requires that you have at least three rows of data in your result set before it will return any results. * By default, if a search term appears in more than 50% of the rows then MySQL will not return any results. * By default, your search query must be at least four characters long and may not exceed 254 characters. * MySQL has a default stopwords file that has a list of common words (i.e., the, that, has) which are not returned in your search. In other words, searching for the will return zero rows. * According to MySQL's manual, the argument to AGAINST() must be a constant string. In other words, you cannot search for values returned within the query. */ if (cnSettingsAPI::get('connections', 'search', 'fulltext_enabled')) { $terms = array(); $shortwords = array(); /* * Remove any shortwords from the FULLTEXT query since the db will drop them anyway. * Add the shortwords to a separate array to be used to do a LIKE query. */ foreach ($atts['terms'] as $key => $term) { if (strlen($term) >= 2 && strlen($term) <= 3) { unset($atts['terms'][$key]); $shortwords[] = $term; } } if (!empty($atts['terms'])) { // Make each term required, functional AND query. $terms = apply_filters('cn_search_fulltext_terms', '+' . implode(' +', $atts['terms'])); } /* * Only search the primary records if at least one fields is selected to be searched. */ if (!empty($atts['fields']['entry'])) { $select = array(); $from = array(); $where = array(); $like = array(); $select[] = 'SELECT ' . CN_ENTRY_TABLE . '.id'; /* * Set up the SELECT to return the results scored by relevance. */ if (!empty($terms)) { $select[] = $wpdb->prepare('MATCH (' . implode(', ', $atts['fields']['entry']) . ') AGAINST (%s) AS score', $terms); } $from[] = CN_ENTRY_TABLE; /* * If there are long word terms, perform a FULLTEXT query. */ if (!empty($terms)) { $where[] = $wpdb->prepare('MATCH (' . implode(', ', $atts['fields']['entry']) . ') AGAINST (%s IN BOOLEAN MODE)', $terms); } /* * If there are no long words and there are short words, perform a LIKE query for the short words. */ if (empty($terms) && !empty($shortwords)) { foreach ($shortwords as $word) { $like[] = $wpdb->prepare(implode(' LIKE %s OR ', $atts['fields']['entry']) . ' LIKE %s ', array_fill(0, count($atts['fields']['entry']), $wpdb->esc_like($word) . '%')); } $where[] = '( ' . implode(') OR (', $like) . ')'; } /* * Return the query results ordered by the relevance score. */ $orderBy = empty($terms) ? '' : ' ORDER BY score'; $sql = implode(', ', $select) . ' FROM ' . implode(',', $from) . ' WHERE ' . implode(' AND ', $where) . $orderBy; $scored = $wpdb->get_results($sql, ARRAY_A); } /* * Only search the address records if at least one fields is selected to be searched. */ if (!empty($atts['fields']['address'])) { $select = array(); $from = array(); $where = array(); $like = array(); $select[] = 'SELECT ' . CN_ENTRY_ADDRESS_TABLE . '.entry_id'; /* * Set up the SELECT to return the results scored by relevance. */ if (!empty($terms)) { $select[] = $wpdb->prepare('MATCH (' . implode(', ', $atts['fields']['address']) . ') AGAINST (%s) AS score', $terms); } $from[] = CN_ENTRY_ADDRESS_TABLE; /* * If there are long word terms, perform a FULLTEXT query. */ if (!empty($terms)) { $where[] = $wpdb->prepare('MATCH (' . implode(', ', $atts['fields']['address']) . ') AGAINST (%s IN BOOLEAN MODE)', $terms); } /* * If there are no long words and there are short words, perform a LIKE query for the short words. */ if (empty($terms) && !empty($shortwords)) { foreach ($shortwords as $word) { $like[] = $wpdb->prepare(implode(' LIKE %s OR ', $atts['fields']['address']) . ' LIKE %s ', array_fill(0, count($atts['fields']['address']), $wpdb->esc_like($word) . '%')); } $where[] = '( ' . implode(') OR (', $like) . ')'; } /* * Return the query results ordered by the relevance score. */ $orderBy = empty($terms) ? '' : ' ORDER BY score'; $sql = implode(', ', $select) . ' FROM ' . implode(',', $from) . ' WHERE ' . implode(' AND ', $where) . $orderBy; $ids = $wpdb->get_results($sql, ARRAY_A); /* * If any results are returned merge them in to the $scored results. */ if (!empty($ids)) { $scored = array_merge($scored, $ids); } } /* * Only search the phone records if thefield is selected to be search. */ if (!empty($atts['fields']['phone'])) { $select = array(); $from = array(); $where = array(); $like = array(); $select[] = 'SELECT ' . CN_ENTRY_PHONE_TABLE . '.entry_id'; /* * Set up the SELECT to return the results scored by relevance. */ if (!empty($terms)) { $select[] = $wpdb->prepare('MATCH (' . implode(', ', $atts['fields']['phone']) . ') AGAINST (%s) AS score', $terms); } $from[] = CN_ENTRY_PHONE_TABLE; /* * If there are long word terms, perform a FULLTEXT query. */ if (!empty($terms)) { $where[] = $wpdb->prepare('MATCH (' . implode(', ', $atts['fields']['phone']) . ') AGAINST (%s IN BOOLEAN MODE)', $terms); } /* * If there are no long words and there are short words, perform a LIKE query for the short words. */ if (empty($terms) && !empty($shortwords)) { foreach ($shortwords as $word) { $like[] = $wpdb->prepare(implode(' LIKE %s OR ', $atts['fields']['phone']) . ' LIKE %s ', array_fill(0, count($atts['fields']['phone']), $wpdb->esc_like($word) . '%')); } $where[] = '( ' . implode(') OR (', $like) . ')'; } /* * Return the query results ordered by the relevance score. */ $orderBy = empty($terms) ? '' : ' ORDER BY score'; $sql = implode(', ', $select) . ' FROM ' . implode(',', $from) . ' WHERE ' . implode(' AND ', $where) . $orderBy; $ids = $wpdb->get_results($sql, ARRAY_A); /* * If any results are returned merge them in to the $scored results. */ if (!empty($ids)) { $scored = array_merge($scored, $ids); } } $scored = apply_filters('cn_search_scored_results', $scored, $terms); /* * The query results are stored in the $scored array ordered by relevance. * Only the entry ID/s are needed to be returned. Setup the $results array * with only the entry ID/s in the same order as returned by the relevance score. */ foreach ($scored as $entry) { $results[] = isset($entry['id']) ? $entry['id'] : $entry['entry_id']; } } /* * If no results are found, perhaps to the way MySQL performs FULLTEXT queries, FULLTEXT search being disabled * or the DB not supporting FULLTEXT, run a LIKE query. * * Perform the search on each table individually because joining the tables doesn't scale when * there are a large number of entries. */ if ((cnSettingsAPI::get('connections', 'search', 'keyword_enabled') && empty($results) || cnSettingsAPI::get('connections', 'search', 'fulltext_enabled') && empty($results)) && !empty($atts['terms'])) { /* * Only search the primary records if at least one fields is selected to be searched. */ if (!empty($atts['fields']['entry'])) { $like = array(); // Reset the like array. foreach ($atts['terms'] as $term) { /* * Attempt to secure the query using $wpdb->prepare() and like_escape() * * Since $wpdb->prepare() required var for each directive in the query string we'll use array_fill * where the count based on the number of columns that will be searched. */ $like[] = $wpdb->prepare(implode(' LIKE %s OR ', $atts['fields']['entry']) . ' LIKE %s ', array_fill(0, count($atts['fields']['entry']), '%' . $wpdb->esc_like($term) . '%')); } $sql = 'SELECT ' . CN_ENTRY_TABLE . '.id FROM ' . CN_ENTRY_TABLE . ' WHERE (' . implode(') OR (', $like) . ')'; //print_r($sql); $results = array_merge($results, $wpdb->get_col($sql)); //print_r($results);die; } /* * Only search the address records if at least one fields is selected to be searched. */ if (!empty($atts['fields']['address'])) { $like = array(); // Reset the like array. foreach ($atts['terms'] as $term) { /* * Attempt to secure the query using $wpdb->prepare() and like_escape() * * Since $wpdb->prepare() required var for each directive in the query string we'll use array_fill * where the count based on the number of columns that will be searched. */ $like[] = $wpdb->prepare(implode(' LIKE %s OR ', $atts['fields']['address']) . ' LIKE %s ', array_fill(0, count($atts['fields']['address']), '%' . $wpdb->esc_like($term) . '%')); } $sql = 'SELECT ' . CN_ENTRY_ADDRESS_TABLE . '.entry_id FROM ' . CN_ENTRY_ADDRESS_TABLE . ' WHERE (' . implode(') OR (', $like) . ')'; //print_r($sql); $results = array_merge($results, $wpdb->get_col($sql)); //print_r($results); } /* * Only search the phone records if the field is selected to be search. */ if (!empty($atts['fields']['phone'])) { $like = array(); // Reset the like array. foreach ($atts['terms'] as $term) { /* * Attempt to secure the query using $wpdb->prepare() and like_escape() * * Since $wpdb->prepare() required var for each directive in the query string we'll use array_fill * where the count based on the number of columns that will be searched. */ $like[] = $wpdb->prepare(implode(' LIKE %s OR ', $atts['fields']['phone']) . ' LIKE %s ', array_fill(0, count($atts['fields']['phone']), '%' . $wpdb->esc_like($term) . '%')); } $sql = 'SELECT ' . CN_ENTRY_PHONE_TABLE . '.entry_id FROM ' . CN_ENTRY_PHONE_TABLE . ' WHERE (' . implode(') OR (', $like) . ')'; //print_r($sql); $results = array_merge($results, $wpdb->get_col($sql)); //print_r($results); } } return apply_filters('cn_search_results', $results, $atts); }
/** * Enqueues the Connections CSS on the required admin pages. * * @access private * @since 0.7.3.2 * @static * * @uses Connections_Directory() * @uses wp_enqueue_style() * @uses do_action() * @uses apply_filters() * * @param string $pageHook The current admin page hook. * * @return void */ public static function enqueueAdminStyles($pageHook) { // Grab an instance of the Connections object. $instance = Connections_Directory(); // Load on all the Connections admin pages. if (in_array($pageHook, get_object_vars($instance->pageHook))) { wp_enqueue_style('cn-admin'); wp_enqueue_style('cn-admin-jquery-ui'); wp_enqueue_style('cn-admin-jquery-datepicker'); wp_enqueue_style('cn-font-awesome'); if (is_rtl()) { wp_enqueue_style('cn-admin-rtl'); } do_action('cn_admin_enqueue_styles', $pageHook); } $editPages = apply_filters('cn_admin_required_edit_scripts', array($instance->pageHook->manage, $instance->pageHook->add)); if (in_array($pageHook, $editPages)) { wp_enqueue_style('cn-chosen'); do_action('cn_admin_enqueue_edit_styles', $pageHook); } }
/** * Update the post date and post modified date to reflect the current entry being viewed. * * @access private * @since 8.1 * @static * * @uses is_main_query() * @uses get_query_var() * @uses get_gmt_from_date() * * @param array $posts An array of WP_Post objects. * @param object $wp_query A reference to the WP_Query object * * @return array */ public static function postDates($posts, $wp_query) { // Grab an instance of the Connections object. $instance = Connections_Directory(); if ($wp_query->is_main_query() && get_query_var('cn-entry-slug')) { $result = $instance->retrieve->entries(array('slug' => urldecode(get_query_var('cn-entry-slug')))); $modified = $result[0]->ts; $created = $result[0]->date_added ? date('Y-m-d H:i:s', $result[0]->date_added) : $result[0]->ts; if (isset($posts[0])) { if (isset($posts[0]->post_date)) { $posts[0]->post_date = $created; $posts[0]->post_date_gmt = get_gmt_from_date($created); } if (isset($posts[0]->post_modified)) { $posts[0]->post_modified = $modified; $posts[0]->post_modified_gmt = get_gmt_from_date($modified); } } } return $posts; }
/** * Bulk category actions. * * @access public * @since 0.7.7 * @uses current_user_can() * @uses check_admin_referer() * @uses wp_redirect() * @uses get_admin_url() * @uses get_current_blog_id() * @return void */ public static function categoryManagement() { // Grab an instance of the Connections object. $instance = Connections_Directory(); $action = ''; if (isset($_REQUEST['action']) && '-1' !== $_REQUEST['action']) { $action = $_REQUEST['action']; } elseif (isset($_REQUEST['action2']) && '-1' !== $_REQUEST['action2']) { $action = $_REQUEST['action2']; } /* * Check whether user can edit Settings */ if (current_user_can('connections_edit_categories')) { switch ($action) { case 'delete': check_admin_referer('bulk-terms'); foreach ((array) $_POST['category'] as $id) { $result = $instance->retrieve->category(absint($id)); $category = new cnCategory($result); $category->delete(); } break; } $url = get_admin_url(get_current_blog_id(), 'admin.php?page=connections_categories'); if (isset($_REQUEST['paged']) && !empty($_REQUEST['paged'])) { $page = absint($_REQUEST['paged']); $url = add_query_arg(array('paged' => $page), $url); } wp_redirect($url); exit; } else { cnMessage::set('error', 'capability_categories'); } }
/** * Renders the Template admin page. * * @access private * @since unknown */ function connectionsShowTemplatesPage() { /* * Check whether user can edit Settings */ if (!current_user_can('connections_manage_template')) { wp_die('<p id="error-page" style="-moz-background-clip:border; -moz-border-radius:11px; background:#FFFFFF none repeat scroll 0 0; border:1px solid #DFDFDF; color:#333333; display:block; font-size:12px; line-height:18px; margin:25px auto 20px; padding:1em 2em; text-align:center; width:700px">' . __('You do not have sufficient permissions to access this page.', 'connections') . '</p>'); } else { // Grab an instance of the Connections object. $instance = Connections_Directory(); $type = isset($_GET['type']) ? esc_attr($_GET['type']) : 'all'; $templates = cnTemplateFactory::getCatalog($type); $adminURL = self_admin_url('admin.php'); $pageURL = add_query_arg('page', 'connections_templates', $adminURL); $homeID = cnSettingsAPI::get('connections', 'connections_home_page', 'page_id'); $homeURL = get_permalink($homeID); $customizerURL = add_query_arg('cn-customize-template', 'true', $homeURL); ?> <div class="wrap"> <h1>Connections : <?php _e('Templates', 'connections'); ?> <a class="button add-new-h2" href="http://connections-pro.com/templates/" target="_blank"><?php _e('Get More', 'connections'); ?> </a> </h1> <ul class="subsubsub"> <li> <a <?php if ('all' == $type) { echo 'class="current" '; } ?> href="<?php echo esc_url(add_query_arg('type', 'all', $pageURL)); ?> "> <?php _e('All', 'connections'); ?> </a> | </li> <li> <a <?php if ('individual' == $type) { echo 'class="current" '; } ?> href="<?php echo esc_url(add_query_arg('type', 'individual', $pageURL)); ?> "> <?php _e('Individual', 'connections'); ?> </a> | </li> <li> <a <?php if ('organization' == $type) { echo 'class="current" '; } ?> href="<?php echo esc_url(add_query_arg('type', 'organization', $pageURL)); ?> "> <?php _e('Organization', 'connections'); ?> </a> | </li> <li> <a <?php if ('family' == $type) { echo 'class="current" '; } ?> href="<?php echo esc_url(add_query_arg('type', 'family', $pageURL)); ?> "> <?php _e('Family', 'connections'); ?> </a> | </li> <li> <a <?php if ('anniversary' == $type) { echo 'class="current" '; } ?> href="<?php echo esc_url(add_query_arg('type', 'anniversary', $pageURL)); ?> "> <?php _e('Anniversary', 'connections'); ?> </a> | </li> <li> <a <?php if ('birthday' == $type) { echo 'class="current" '; } ?> href="<?php echo esc_url(add_query_arg('type', 'birthday', $pageURL)); ?> "> <?php _e('Birthday', 'connections'); ?> </a> </li> </ul> <br class="clear"> <table cellspacing="0" cellpadding="0" id="currenttheme"> <tbody> <tr> <td class="current_template"> <h2><?php _e('Current Template', 'connections'); ?> </h2> <div id="current-template"> <?php $slug = $instance->options->getActiveTemplate($type); /** @var cnTemplate $activeTemplate */ $activeTemplate = cnTemplateFactory::getTemplate($slug); if ($activeTemplate) { cnTemplateThumbnail($activeTemplate); cnTemplateAuthor($activeTemplate); cnTemplateDescription($activeTemplate); cnTemplateCustomizerButton($activeTemplate, $customizerURL, $pageURL); // Remove the current template so it does not show in the available templates. unset($templates->{$activeTemplate->getSlug()}); } else { echo '<h3 class="error"> Template ', esc_attr($slug), ' can not be found.</h3>'; } ?> </div> <div class="clear"></div> </td> <td class="template_instructions" colspan="2"> <p> <strong><?php _e('Instructions', 'connections'); ?> :</strong> </p> <p> <?php _e('By default the <code><a href="http://connections-pro.com/documentation/connections/shortcodes/shortcode-connections/">[connections]</a></code> shortcode will show all entries types. To change the template used when displaying all entry types, select the "All" tab and activate the template. When the <code><a href="http://connections-pro.com/documentation/connections/shortcodes/shortcode-connections/list_type/">list_type</a></code>shortcode option is used to filter the entries based on the entry type, the template for that entry type will be used. To change the template used for a specific entry type, select the appropriate tab and then activate the template. If multiple entry types are specified in the <code><a href="http://connections-pro.com/documentation/connections/shortcodes/shortcode-connections/list_type/">list_type</a></code> shortcode option, the template for the entry type listed first will be used to display the entry list.', 'connections'); ?> </p> <p> <?php _e('The <code><a href="http://connections-pro.com/documentation/connections/shortcodes/shortcode-upcoming-list/">[upcoming_list]</a></code> shortcode which displays the upcoming anniversaries and birthdays will be displayed with the template that is activated under their respective tabs.', 'connections'); ?> </p> <p> <?php _e('The current active template for each template type can be overridden by using the <code><a href="http://connections-pro.com/documentation/connections/shortcodes/shortcode-connections/template-option/">template</a></code> shortcode option.', 'connections'); ?> </p> </td> </tr> </tbody> </table> <!-- /#currenttheme --> <table cellspacing="0" cellpadding="0" id="availablethemes"> <tbody> <tr> <td class="current_template" colspan="3"> <h2><?php _e('Available Templates', 'connections'); ?> </h2> </td> </tr> <?php $slugs = array_keys((array) $templates); natcasesort($slugs); $table = array(); $rows = ceil(count($slugs) / 3); for ($row = 1; $row <= $rows; $row++) { for ($col = 1; $col <= 3; $col++) { $table[$row][$col] = array_shift($slugs); } } foreach ($table as $row => $cols) { ?> <tr> <?php foreach ($cols as $col => $slug) { if (!isset($templates->{$slug})) { continue; } /** @var cnTemplate $template */ $template = $templates->{$slug}; $class = array('available-theme'); if ($row == 1) { $class[] = 'top'; } if ($row == $rows) { $class[] = 'bottom'; } if ($col == 1) { $class[] = 'left'; } if ($col == 3) { $class[] = 'right'; } ?> <td <?php echo cnHTML::attribute('class', $class); ?> > <?php cnTemplateThumbnail($template); cnTemplateAuthor($template); cnTemplateDescription($template); cnTemplateDeactivateText($template); cnTemplateShortcodeOverride($template); ?> <span class="action-links"> <?php cntemplateActivateButton($template, $type); cnTemplateDeleteButton($template); cnTemplateCustomizerButton($template, $customizerURL, $pageURL); ?> </span> </td> <?php } ?> </tr> <?php } ?> </tbody> </table> <!-- /#availablethemes --> </div> <!-- /.wrap --> <?php } }
/** * Load the template. The template that will be loaded will be * determined by the template activated under the `All` template type. * Unless overridden by either the `template` or `list_type` shortcode * options. * * @access private * @since 0.8 * @static * * @param array $atts The shortcode atts array. * * @return cnTemplate|FALSE An instance the of cnTemplate object or `FALSE` if the template was not found/loaded. */ public static function loadTemplate($atts) { $type = 'all'; $defaults = array('list_type' => NULL, 'template' => NULL); /** * @since 0.7.9.4 * * @param array $atts { * @type string $list_type The shortcode list_type attribute value. * @type string $template The template slug. * } */ $defaults = apply_filters('cn_load_template', $defaults); $atts = shortcode_atts($defaults, $atts); if (!empty($atts['list_type'])) { $permittedTypes = array('individual', 'organization', 'family', 'connection_group'); // Convert to array. Trim the space characters if present. $atts['list_type'] = explode(',', str_replace(' ', '', $atts['list_type'])); // Set the template type to the first in the entry type from the supplied if multiple list types are provided. if (in_array($atts['list_type'][0], $permittedTypes)) { $type = $atts['list_type'][0]; // Change the list type to family from connection_group to maintain compatibility with versions 0.7.0.4 and earlier. if ($type == 'connection_group') { $type = 'family'; } } } /* * 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 = self::getTemplate($atts['template']); } else { // Grab an instance of the Connections object. $instance = Connections_Directory(); $slug = $instance->options->getActiveTemplate($type); $template = self::getTemplate($slug); } // If the template was not located, return FALSE. // This will in turn display the template not found error message // later in the execution of the shortcode. if ($template == FALSE) { return FALSE; } /** @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()); return $template; }
/** * 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); }