/** * Save and or update the objects meta data * based on the action being performed to the object. * * @access private * @since 0.8 * @param string $action The action being performed. * @param int $id The object ID. * @param array $fields An array of the registered fields to save and or update. * * @return void */ private function save($action, $id, $fields) { foreach ($fields as $field) { if (!($id = absint($id))) { return FALSE; } // Quick and dirty hack to prevent the bio and notes fields from being saved in the meta table. // @todo Think of something better to do here. // There should be some type of flag to check before saving as meta. if ($field['id'] === 'bio' || $field['id'] === 'notes') { continue; } $value = $this->sanitize($field['type'], isset($_POST[$field['id']]) ? $_POST[$field['id']] : NULL, isset($field['options']) ? $field['options'] : array(), isset($field['default']) ? $field['default'] : NULL); switch ($action) { case 'add': cnMeta::add('entry', $id, $field['id'], $value); break; case 'copy': cnMeta::add('entry', $id, $field['id'], $value); break; case 'update': cnMeta::update('entry', $id, $field['id'], $value); break; } } }
/** * Callback to delete the term meta when when a term is deleted. * * @access private * @since 8.2 * @static * * @param int $term Term ID. * @param int $tt_id Term taxonomy ID. * @param string $taxonomy Taxonomy slug. * @param mixed $deleted_term Copy of the already-deleted term, in the form specified * by the parent function. WP_Error otherwise. */ public static function deleteTermMeta($term, $tt_id, $taxonomy, $deleted_term) { if (!is_wp_error($deleted_term)) { $meta = cnMeta::get('term', $term); if (!empty($meta)) { foreach ($meta as $key => $value) { cnMeta::delete('term', $term, $key); } } } }
/** * Return the `meta_key` of a term * * @access public * @since 8.5.2 * * @param int $term_id * * @return array|bool|string */ public function get($term_id = 0) { return cnMeta::get('term', $term_id, $this->meta_key, TRUE); }
/** * Load meta data for the player. */ protected function loadMeta() { if ($this->meta !== null) { return $this->meta; } $meta = $this->entry->getMeta(); if (!is_array($meta)) { $myMeta = array(); } else { $myMeta = array(); foreach ($meta as $key => $values) { if (count($values) > 1 && count(array_unique($values)) == 1) { cnMeta::delete('entry', $this->entry->getId(), $key); cnMeta::add('entry', $this->entry->getId(), $key, $values[0]); } $myMeta[$key] = $values[0]; } } $this->meta = $myMeta; return $myMeta; }
/** * Add, update or delete the meta of the specified entry ID. * * @access public * @since 0.8 * @param string $action The action to be performed. * @param int $id The entry ID. * @param array $meta [optional] An array of meta data the action is to be performed on. * * @return array The meta IDs of the meta data the action was performed on. */ public static function meta($action, $id, $meta = array()) { $metaIDs = array(); switch ($action) { case 'add': foreach ($meta as $row) { $metaIDs[] = cnMeta::add('entry', $id, $row['key'], $row['value']); } break; case 'update': foreach ($meta as $metaID => $row) { cnMeta::update('entry', $id, $row['key'], $row['value']); $metaIDs[] = $metaID; } break; case 'delete': if (empty($meta)) { $meta = cnMeta::get('entry', $id); } if ($meta) { foreach ($meta as $key => $value) { cnMeta::delete('entry', $id, $key); $metaIDs[] = $key; } } break; } return $metaIDs; }
/** * Callback to render the "Custom Fields" metabox. * * @access private * @since 0.8 * @param cnEntry $entry An instance of the cnEntry object. * @param array $metabox The metabox attributes array set in self::register(). * @return void */ public static function meta($entry, $metabox) { /** @var wpdb $wpdb */ global $wpdb; $results = $wpdb->get_results($wpdb->prepare("SELECT meta_key, meta_value, meta_id, entry_id\n\t\t\tFROM " . CN_ENTRY_TABLE_META . " WHERE entry_id = %d\n\t\t\tORDER BY meta_key,meta_id", $entry->getId()), ARRAY_A); $metabox = $metabox['args']; $keys = cnMeta::key('entry'); $options = array(); // Toss the meta that is saved as part of a custom field. if (!empty($results)) { foreach ($results as $metaID => $meta) { if (cnMeta::isPrivate($meta['meta_key'])) { unset($results[$metaID]); } } } // Build the meta key select drop down options. if (!empty($keys)) { $options = array_combine(array_map('esc_attr', array_keys($keys)), array_map('esc_html', $keys)); array_walk($options, create_function('&$key', '$key = "<option value=\\"$key\\">$key</option>";')); } array_unshift($options, '<option value="-1">— ' . __('Select', 'connections') . ' —</option>'); $options = implode($options, PHP_EOL); // echo '<input type="hidden" name="wp_meta_box_nonce" value="', wp_create_nonce( basename(__FILE__) ), '" />'; echo '<div class="cn-metabox-section" id="meta-fields">'; ?> <table id="list-table" style="<?php echo empty($results) ? 'display: none;' : 'display: table;'; ?> "> <thead> <tr> <th class="left"><?php _e('Name', 'connections'); ?> </th> <th><?php _e('Value', 'connections'); ?> </th> </tr> </thead> <tbody id="the-list"> <?php if (!empty($results)) { foreach ($results as $metaID => $meta) { // Class added to alternate tr rows for CSS styling. $alternate = !isset($alternate) || $alternate == '' ? 'alternate' : ''; ?> <tr id="meta-<?php echo $meta['meta_id']; ?> " class="<?php echo $alternate; ?> "> <td class="left"> <label class="screen-reader-text" for='meta[<?php echo $meta['meta_id']; ?> ][key]'><?php _e('Key', 'connections'); ?> </label> <input name='meta[<?php echo $meta['meta_id']; ?> ][key]' id='meta[<?php echo $meta['meta_id']; ?> ][key]' type="text" size="20" value="<?php echo esc_textarea($meta['meta_key']); ?> " /> <div class="submit"> <input type="submit" name="deletemeta[<?php echo $meta['meta_id']; ?> ]" id="deletemeta[<?php echo $meta['meta_id']; ?> ]" class="button deletemeta button-small" value="<?php _e('Delete', 'connections'); ?> " /> </div> </td> <td> <label class="screen-reader-text" for='meta[<?php echo $meta['meta_id']; ?> ][value]'><?php _e('Value', 'connections'); ?> </label> <textarea name='meta[<?php echo $meta['meta_id']; ?> ][value]' id='meta[<?php echo $meta['meta_id']; ?> ][value]' rows="2" cols="30"><?php echo esc_textarea(cnFormatting::maybeJSONencode($meta['meta_value'])); ?> </textarea> </td> </tr> <?php } ?> <?php } ?> <!-- This is the row that will be cloned via JS when adding a new Custom Field. --> <tr style="display: none;"> <td class="left"> <label class="screen-reader-text" for='newmeta[0][key]'><?php _e('Key', 'connections'); ?> </label> <input name='newmeta[0][key]' id='newmeta[0][key]' type="text" size="20" value=""/> <div class="submit"> <input type="submit" name="deletemeta[0]" id="deletemeta[0]" class="button deletemeta button-small" value="<?php _e('Delete', 'connections'); ?> " /> <!-- <input type="submit" name="newmeta-0-submit" id="newmeta-0-submit" class="button updatemeta button-small" value="Update" /> --> </div> <!-- <input type="hidden" id="_ajax_nonce" name="_ajax_nonce" value="0db0025bba" /> --> </td> <td> <label class="screen-reader-text" for='newmeta[0][value]'><?php _e('Value', 'connections'); ?> </label> <textarea name='newmeta[0][value]' id='newmeta[0][value]' rows="2" cols="30"></textarea> </td> </tr> </tbody> </table> <p><strong><?php _e('Add New Custom Field:', 'connections'); ?> </strong></p> <table id="newmeta"> <thead> <tr> <th class="left"><label for="metakeyselect"><?php _e('Name', 'connections'); ?> </label></th> <th><label for="metavalue"><?php _e('Value', 'connections'); ?> </label></th> </tr> </thead> <tbody> <tr> <td id="newmetaleft" class="left"> <select id="metakeyselect" name="metakeyselect"> <?php echo $options; ?> </select> <input class="hide-if-js" type=text id="metakeyinput" name="newmeta[99][key]" value=""/> <a href="#postcustomstuff" class="postcustomstuff hide-if-no-js"> <span id="enternew"><?php _e('Enter New', 'connections'); ?> </span> <span id="cancelnew" class="hidden"><?php _e('Cancel', 'connections'); ?> </span></a> </td> <td> <textarea id="metavalue" name="newmeta[99][value]" rows="2" cols="25"></textarea> </td> </tr> </tbody> <tfoot> <td colspan="2"> <div class="submit"> <input type="submit" name="addmeta" id="newmeta-submit" class="button" value="<?php _e('Add Custom Field', 'connections'); ?> " /> </div> <!-- <input type="hidden" id="_ajax_nonce-add-meta" name="_ajax_nonce-add-meta" value="a7f70d2878" /> --> </td> </tfoot> </table> <?php if (isset($metabox['desc']) && !empty($metabox['desc'])) { printf('<p>%1$s</p>', esc_html($metabox['desc'])); } echo '</div>'; }
/** * Write the CSV rows for the current step. * * @access public * @since 8.5.1 */ public function writeRows() { $results = $this->getData(); $rows = ''; if (!empty($results)) { // Go through each entry... foreach ($results as $entry) { $fieldCount = count($this->fields); $row = ''; // ...and go through each cell the user wants to export, and match it with the cell in the entry... for ($i = 0; $i < $fieldCount; $i++) { // ...then find out if it's a breakout cell and process it properly... switch ($this->fields[$i]['type']) { case 1: // Export a standard breakout; just list them all in the order requested... $row .= $this->exportBreakoutCell($this->fields[$i], $entry->id); break; case 2: // Process category table and list all categories in a single cell... $terms = array(); $results = $this->getTerms($entry->id, 'category'); foreach ($results as $term) { $terms[] = $term->name; } $row .= $this->escapeAndQuote(implode(',', $terms)) . ','; break; case 3: $count = $this->getTermCount('category'); $terms = array(); // Process the category table by breaking them out in separate cells, // Prepare an empty frame of the category cells... for ($j = 0; $j < $count + 1; $j++) { // Make an array filled with empty cells $terms[$j] = '"",'; } // Now start filling in the empty cells with data... $row = $this->getTerms($entry->id, 'category'); $j = 0; foreach ($row as $result) { $terms[$j] = $this->escapeAndQuote($result->name) . ','; $j++; } $row .= implode('', $terms); break; case 4: // Export breakout data from the serialized option cell. $row .= $this->exportBreakoutOptionsCell($this->fields[$i], $entry); break; case 5: $data = ''; $meta = cnMeta::get('entry', $entry->id, $this->fields[$i]['field'], TRUE); if (!empty($meta)) { $data = cnFormatting::maybeJSONencode($meta); } $row .= $this->escapeAndQuote($data) . ','; break; case 6: $terms = array(); $parent = $this->fields[$i]['child_of']; $results = $this->getTerms($entry->id, 'category'); foreach ($results as $term) { $terms[] = $parent . ':' . $term->term_id; if (cnTerm::isAncestorOf($parent, $term->term_id, 'category')) { $terms[] = $term->name; } } $row .= $this->escapeAndQuote(implode(',', $terms)) . ','; break; default: // If no breakout type is defined, only display the cell data... $row .= $this->escapeAndQuote($entry->{$this->fields[$i]['field']}) . ','; break; } } // Trim the trailing comma and space, then add newline. $rows .= rtrim($row, ',') . "\r\n"; } // Now write the data... $this->write($rows); return $rows; } return FALSE; }
/** * Outputs the data saved in the "Custom Fields" entry metabox. * This should not be confused with the fields registered with * cnMetaboxAPI. Those fields should be output using a registered * action which runs in $this->getMetaBlock(). * * @access private * @since 0.8 * @uses wp_parse_args() * @uses apply_filters() * @param array $metadata The metadata array passed from $this->getMetaBlock(). @see self::getMetaBlock(). * * @return string */ private function renderMetaBlock($metadata) { $out = ''; $defaults = array('container_tag' => 'ul', 'item_tag' => 'li', 'key_tag' => 'span', 'value_tag' => 'span', 'separator' => ': ', 'before' => '', 'after' => ''); $atts = wp_parse_args(apply_filters('cn_output_meta_atts', $defaults), $defaults); foreach ((array) $metadata as $key => $value) { // Do not render any private keys; ie. ones that begin with an underscore // or any fields registered as part of a custom metabox. if (cnMeta::isPrivate($key, 'entry')) { continue; } $out .= apply_filters('cn_entry_output_meta_key', sprintf('<%1$s><%2$s class="cn-entry-meta-key">%3$s%4$s</%2$s><%5$s class="cn-entry-meta-value">%6$s</%5$s></%1$s>' . PHP_EOL, $atts['item_tag'], $atts['key_tag'], trim($key), $atts['separator'], $atts['value_tag'], implode(', ', (array) $value)), $atts, $key, $value); } if (empty($out)) { return ''; } $out = apply_filters('cn_entry_output_meta_container', sprintf('<%1$s class="cn-entry-meta">%2$s</%1$s>' . PHP_EOL, $atts['container_tag'], $out), $atts, $metadata); echo $atts['before'] . $out . $atts['after'] . PHP_EOL; }
/** * Returns the entry meta data. * * @access public * @since unknown * * @uses wp_parse_args() * @uses cnMeta::get() * * @param array $atts { * Optional. An array of arguments. * * @type string $key Metadata key. If not specified, retrieve all metadata for the specified object. * @type bool $single Default is FALSE. If TRUE, return only the first value of the specified meta_key. * This parameter has no effect if $key is not specified. * } * * @return mixed array|bool|string Array of the entry meta data. * String if $single is set to TRUE. * FALSE on failure. */ public function getMeta($atts = array()) { $defaults = array('key' => '', 'single' => FALSE); $atts = wp_parse_args($atts, $defaults); return cnMeta::get('entry', $this->getId(), $atts['key'], $atts['single']); }
/** * Save and or update the objects meta data * based on the action being performed to the object. * * @access private * @since 0.8 * * @param string $action The action being performed. * @param int $id The object ID. * @param array $fields An array of the registered fields to save and or update. * * @return bool */ private function save($action, $id, $fields) { foreach ($fields as $field) { /** * Filter field meta before it is inserted into the database. * * @since 8.5.14 * * @param array $field An array of the registered field attributes. * @param int $id The object ID. * @param string $action The action being performed. */ $field = apply_filters('cn_pre_save_meta', $field, $id, $action); if (!($id = absint($id))) { return FALSE; } /** * Filter to allow meta to not be saved. * * The dynamic portion of the filter name is so saving meta can be skipped based on the field ID. * * @since 8.5.14 * * @param false $false Return TRUE to not save the field meta. */ if (apply_filters('cn_pre_save_meta_skip', FALSE) || apply_filters('cn_pre_save_meta_skip-' . $field['id'], FALSE)) { continue; } $value = $this->sanitize($field['type'], isset($_POST[$field['id']]) ? $_POST[$field['id']] : NULL, isset($field['options']) ? $field['options'] : array(), isset($field['default']) ? $field['default'] : NULL); switch ($action) { case 'add': cnMeta::add('entry', $id, $field['id'], $value); break; case 'copy': cnMeta::add('entry', $id, $field['id'], $value); break; case 'update': cnMeta::update('entry', $id, $field['id'], $value); break; } } }
/** * Generates SQL clauses to be added to the query. * * @access public * @since 8.2.5 * * @param string $type Type of meta, eg 'entry', 'term'. * @param string $primary_table Database table where the object being filtered is stored (eg CN_ENTRY_TABLE). * @param string $primary_id_column ID column for the filtered object in $primary_table. * @param mixed $context object|null Optional. The main query object. * * @return array { * Array containing JOIN and WHERE SQL clauses to append to the main query. * * @type string $join SQL fragment to append to the main JOIN clause. * @type string $where SQL fragment to append to the main WHERE clause. * } */ public function get_sql($type, $primary_table, $primary_id_column, $context = null) { $this->meta_table = cnMeta::tableName($type); $this->meta_id_column = sanitize_key($type . '_id'); $this->primary_table = $primary_table; $this->primary_id_column = $primary_id_column; $sql = $this->get_sql_clauses(); /* * If any JOINs are LEFT JOINs (as in the case of NOT EXISTS), then all JOINs should * be LEFT. Otherwise posts with no metadata will be excluded from results. */ if (false !== strpos($sql['join'], 'LEFT JOIN')) { $sql['join'] = str_replace('INNER JOIN', 'LEFT JOIN', $sql['join']); } /** * Filter the meta query's generated SQL. * * @since 8.2.5 * * @param array $args { * An array of meta query SQL arguments. * * @type array $clauses Array containing the query's JOIN and WHERE clauses. * @type array $queries Array of meta queries. * @type string $type Type of meta. * @type string $primary_table Primary table. * @type string $primary_id_column Primary column ID. * @type object $context The main query object. * } */ return apply_filters_ref_array('cn_get_meta_sql', array($sql, $this->queries, $type, $primary_table, $primary_id_column, $context)); }
/** * Retrieve the terms in a given taxonomy or list of taxonomies. * * NOTE: This is the Connections equivalent of @see get_terms() in WordPress core ../wp-includes/taxonomy.php * * Filters: * cn_get_terms_atts - The method variables. * Passes: (array) $atts, (array) $taxonomies * Return: $atts * * cn_get_terms_fields - The fields for the SELECT query clause. * Passes: (array) $select, (array) $atts, (array) $taxonomies * Return: $select * * cn_term_inclusions - Query clause which includes terms. * Passes: (string) $inclusions, (array) $atts, (array) $taxonomies * Return: $inclusions * * cn_term_exclusions - Query clause which excludes terms. * Passes: (string) $exclusions, (array) $atts, (array) $taxonomies * Return: $exclusions * * cn_term_orderby - The ORDER BY query clause. * Passes: (string) $orderBy, (array) $atts, (array) $taxonomies * Return: $orderBy * * cn_terms_clauses - An array containing the the query clause segments. * Passes: (array) $pieces, (array) $taxonomies, (array) $atts * Return: $pieces * * @access public * @since 8.1 * @since 8.5.10 Introduced 'name' and 'childless' parameters. * Introduced the 'meta_query' and 'update_meta_cache' parameters. * Converted to return a list of cnTerm_Object objects. * @static * * @global wpdb $wpdb * * @param string|array $taxonomies Taxonomy name or array of taxonomy names. * @param array $atts { * Optional. Array or string of arguments to get terms. * * @type string $get Whether to return terms regardless of ancestry or whether the terms are empty. * Accepts: 'all' | '' * Default: '' * @type array|string $orderby Field(s) to order terms by. * Use 'include' to match the 'order' of the $include param, or 'none' to skip ORDER BY. * Accepts: term_id | name | slug | term_group | parent | count | include | none * Default: 'name * @type string $order Whether to order terms in ascending or descending order. * Accepts: 'ASC' | 'DESC' * Default: 'ASC' * @type bool|int $hide_empty Whether to hide terms not assigned to any posts. * Accepts: 1|true || 0|false * Default: TRUE. * @type array|string $include Array or comma/space-separated string of term ids to include. * Default: array() * @type array|string $exclude Array or comma/space-separated string of term ids to exclude. * If $include is non-empty, $exclude is ignored. * Default empty array. * @type array|string $exclude_tree Array or comma/space-separated string of term ids to exclude * along with all of their descendant terms. If $include is * non-empty, $exclude_tree is ignored. Default empty array. * @type int|string $number Maximum number of terms to return. * Accepts: ''|0 (all) or any positive number. * Default: 0 * @type int $offset The number by which to offset the terms query. * Accepts: integers. * Default: 0 * @type string $fields Term fields to query for. * Accepts: 'all' (returns an array of complete term objects), * 'ids' (returns an array of ids), * 'id=>parent' (returns an associative array with ids as keys, parent term IDs as values), * 'names' (returns an array of term names), * 'count' (returns the number of matching terms), * 'id=>name' (returns an associative array with ids as keys, term names as values), * 'id=>slug' (returns an associative array with ids as keys, term slugs as values). * Default: 'all'. * @type string|array $name Name or array of names to return term(s) for. * Default: '' * @type string|array $slug Slug or array of slugs to return term(s) for. * Default: ''. * @type bool $hierarchical Whether to include terms that have non-empty descendants (even if $hide_empty is set to true). * Default: TRUE * @type string $search Search criteria to match terms. Will be SQL-formatted with wildcards before and after. * Default: '' * @type string $name__like Retrieve terms with criteria by which a term is LIKE $name__like. * Default: '' * @type string $description__like Retrieve terms where the description is LIKE $description__like. * Default: '' * @type int|string $parent Parent term ID to retrieve direct-child terms of. * Default: '' * @type bool $childless True to limit results to terms that have no children. * This parameter has no effect on non-hierarchical taxonomies. * Default: FALSE * @type int $child_of Term ID to retrieve child terms of. * If multiple taxonomies are passed, $child_of is ignored. * Default: 0 * @type bool $pad_counts Whether to pad the quantity of a term's children in the quantity * of each term's "count" object variable. * Default: FALSE * @type bool $update_meta_cache Whether to prime meta caches for matched terms. * Default: TRUE * @type array $meta_query Meta query clauses to limit retrieved terms by. * @see cnMeta_Query. * Default: array() * } * * @uses apply_filters() * @uses wp_parse_args() * @uses wp_parse_id_list() * @uses sanitize_title() * @uses wpdb::prepare() * @uses $wpdb::esc_like() * @uses absint() * @uses wpdb::get_results() * @uses cnTerm::filter() * @uses cnTerm::descendants() * @uses cnTerm::childrenIDs() * @uses cnTerm::padCounts() * @uses cnTerm::children() * * @return array|int|WP_Error Indexed array of cnTerm_Object objects. Will return WP_Error, if any of $taxonomies do not exist.* */ public static function getTaxonomyTerms($taxonomies = array('category'), $atts = array()) { global $wpdb; $select = array(); $where = array(); $orderBy = array(); $orderByClause = ''; /* * @TODO $taxonomies need to be checked against registered taxonomies. * Presently $taxonomies only support a string rather than array. * Additionally, category is the only supported taxonomy. */ $single_taxonomy = !is_array($taxonomies) || 1 === count($taxonomies); if (!is_array($taxonomies)) { $taxonomies = array($taxonomies); } $defaults = array('get' => '', 'orderby' => 'name', 'order' => 'ASC', 'hide_empty' => TRUE, 'include' => array(), 'exclude' => array(), 'exclude_tree' => array(), 'number' => 0, 'offset' => 0, 'fields' => 'all', 'name' => '', 'slug' => '', 'hierarchical' => TRUE, 'search' => '', 'name__like' => '', 'description__like' => '', 'parent' => '', 'childless' => FALSE, 'child_of' => 0, 'pad_counts' => FALSE, 'meta_query' => array(), 'update_meta_cache' => TRUE); /** * Filter the terms query arguments. * * @since 8.1 * * @param array $atts An array of arguments. * @param string|array $taxonomies A taxonomy or array of taxonomies. */ $atts = apply_filters('cn_get_terms_args', $atts, $taxonomies); $atts = wp_parse_args($atts, $defaults); // @TODO Implement is_taxonomy_hierarchical(). if (!$single_taxonomy || '' !== $atts['parent'] && 0 !== $atts['parent']) { $atts['hierarchical'] = FALSE; $atts['pad_counts'] = FALSE; } // 'parent' overrides 'child_of'. if (0 < intval($atts['parent'])) { $atts['child_of'] = FALSE; } if ('all' == $atts['get']) { $atts['childless'] = FALSE; $atts['child_of'] = 0; $atts['hide_empty'] = 0; $atts['hierarchical'] = FALSE; $atts['pad_counts'] = FALSE; } if ($atts['child_of']) { $hierarchy = self::childrenIDs(reset($taxonomies)); if (!isset($hierarchy[$atts['child_of']])) { return array(); } } if ($atts['parent']) { $hierarchy = self::childrenIDs(reset($taxonomies)); if (!isset($hierarchy[$atts['parent']])) { return array(); } } // $args can be whatever, only use the args defined in defaults to compute the key $filter_key = has_filter('cn_term_exclusions') ? serialize($GLOBALS['wp_filter']['cn_term_exclusions']) : ''; $key = md5(serialize(wp_array_slice_assoc($atts, array_keys($defaults))) . serialize($taxonomies) . $filter_key); $last_changed = wp_cache_get('last_changed', 'cn_terms'); if (!$last_changed) { $last_changed = microtime(); wp_cache_set('last_changed', $last_changed, 'cn_terms'); } $cache_key = "cn_get_terms:{$key}:{$last_changed}"; $cache = wp_cache_get($cache_key, 'cn_terms'); if (FALSE !== $cache) { /** * Filter the given taxonomy's terms cache. * * @since 8.1.6 * * @param array $cache Cached array of terms for the given taxonomy. * @param string|array $taxonomies A taxonomy or array of taxonomies. * @param array $args An array of arguments to get terms. */ $cache = apply_filters('cn_terms', $cache, $taxonomies, $atts); return $cache; } /* * Construct the ORDER By query clause. */ if (is_array($atts['orderby'])) { foreach ($atts['orderby'] as $i => $value) { if (!isset($order)) { $order = 'ASC'; } switch ($value) { case 'name': $orderField = 't.name'; break; case 'id': case 'term_id': $orderField = 't.term_id'; break; case 'slug': $orderField = 't.slug'; break; case 'include': $include = implode(',', wp_parse_id_list($atts['include'])); $orderField = "FIELD( t.term_id, {$include} )"; break; case 'term_group': $orderField = 't.term_group'; break; case 'none': $orderField = ''; // If an `none` order field was supplied, break out of both the switch and foreach statements. break 2; case 'parent': $orderField = 'tt.parent'; break; case 'count': $orderField = 'tt.count'; break; default: $orderField = 't.name'; break; } // Set the $order to align with $atts['orderby']. if (is_array($atts['order']) && isset($atts['order'][$i])) { $order = $atts['order'][$i]; // If an aligned $atts['order'] does not exist use the last $order set otherwise use $atts['order']. } else { $order = is_array($atts['order']) ? $order : $atts['order']; } $order = strtoupper($order); $order = in_array($order, array('ASC', 'DESC')) ? $order : 'ASC'; $orderBy[] = sprintf('%s %s', $orderField, $order); } // The @var $value will be set to the last value from the $atts['orderby'] foreach loop. // If a `none` $atts['orderby'] was found in the supplied array, no order by clause will be set. if (!empty($orderBy) && $value != 'none') { $orderByClause = 'ORDER BY ' . implode(', ', $orderBy); } } else { switch ($atts['orderby']) { case 'name': $atts['orderby'] = 't.name'; break; case 'id': case 'term_id': $atts['orderby'] = 't.term_id'; break; case 'slug': $atts['orderby'] = 't.slug'; break; case 'include': $include = implode(',', wp_parse_id_list($atts['include'])); $atts['orderby'] = "FIELD( t.term_id, {$include} )"; break; case 'term_group': $atts['orderby'] = 't.term_group'; break; case 'none': $atts['orderby'] = ''; break; case 'parent': $atts['orderby'] = 'tt.parent'; break; case 'count': $atts['orderby'] = 'tt.count'; break; default: $atts['orderby'] = 't.name'; break; } if (is_array($atts['order'])) { // $atts['orderby'] was a string but an array was passed for $atts['order'], assume the 0 index. $order = $atts['order'][0]; } else { $order = $atts['order']; } if (!empty($atts['orderby'])) { $order = strtoupper($order); $order = in_array($order, array('ASC', 'DESC')) ? $order : 'ASC'; $orderByClause = 'ORDER BY ' . sprintf('%s %s', $atts['orderby'], $order); } } /** * Filter the ORDER BY clause of the terms query. * * @since 8.1 * * @param string $orderBy ORDER BY clause of the terms query. * @param array $atts An array of terms query arguments. * @param string|array $taxonomies A taxonomy or array of taxonomies. */ $orderBy = apply_filters('cn_terms_orderby', $orderByClause, $atts, $taxonomies); /* * Start construct the WHERE query clause. */ $where[] = 'tt.taxonomy IN (\'' . implode('\', \'', $taxonomies) . '\')'; /* * Define the included terms. */ $inclusions = ''; if (!empty($atts['include'])) { $atts['exclude'] = ''; $atts['exclude_tree'] = ''; $inclusions = implode(',', wp_parse_id_list($atts['include'])); } if (!empty($inclusions)) { $inclusions = 'AND t.term_id IN ( ' . $inclusions . ' )'; } /** * Filter the terms to be included in the terms query. * * @since 8.1 * * @param string $inclusions IN clause of the terms query. * @param array $atts An array of terms query arguments. * @param string|array $taxonomies A taxonomy or array of taxonomies. */ $inclusions = apply_filters('cn_term_inclusions', $inclusions, $atts, $taxonomies); if (!empty($inclusions)) { $where[] = $inclusions; } /* * Define the excluded terms. */ $exclusions = array(); if (!empty($atts['exclude_tree'])) { $atts['exclude_tree'] = wp_parse_id_list($atts['exclude_tree']); $excluded_children = $atts['exclude_tree']; foreach ($atts['exclude_tree'] as $extrunk) { $excluded_children = array_merge($excluded_children, (array) cnTerm::getTaxonomyTerms($taxonomies[0], array('child_of' => intval($extrunk), 'fields' => 'ids', 'hide_empty' => 0))); } $exclusions = array_merge($excluded_children, $exclusions); } if (!empty($atts['exclude'])) { $exclusions = array_merge(wp_parse_id_list($atts['exclude']), $exclusions); } // 'childless' terms are those without an entry in the flattened term hierarchy. $childless = (bool) $atts['childless']; if ($childless) { foreach ($taxonomies as $_tax) { $term_hierarchy = self::childrenIDs($_tax); $exclusions = array_merge(array_keys($term_hierarchy), $exclusions); } } if (!empty($exclusions)) { $exclusions = ' AND t.term_id NOT IN (' . implode(',', array_map('intval', $exclusions)) . ')'; } else { $exclusions = ''; } /** * Filter the terms to exclude from the terms query. * * @since 8.1 * * @param string $exclusions NOT IN clause of the terms query. * @param array $atts An array of terms query arguments. * @param string|array $taxonomies A taxonomy or array of taxonomies. */ $exclusions = apply_filters('cn_term_exclusions', $exclusions, $atts, $taxonomies); if (!empty($exclusions)) { $where[] = $exclusions; } if (!empty($atts['name'])) { $names = (array) $atts['name']; foreach ($names as &$_name) { $_name = sanitize_term_field('name', $_name, 0, reset($taxonomies), 'db'); } $where[] = "AND t.name IN ('" . implode("', '", array_map('esc_sql', $names)) . "')"; } if (!empty($atts['slug'])) { if (is_array($atts['slug'])) { $slug = array_map('sanitize_title', $atts['slug']); $where[] = " AND t.slug IN ('" . implode("', '", $slug) . "')"; } else { $slug = sanitize_title($atts['slug']); $where[] = " AND t.slug = '{$slug}'"; } } if (!empty($atts['name__like'])) { $where[] = $wpdb->prepare(" AND t.name LIKE %s", '%' . $wpdb->esc_like($atts['name__like']) . '%'); } if (!empty($atts['description__like'])) { $where[] = $wpdb->prepare(" AND tt.description LIKE %s", '%' . $wpdb->esc_like($atts['description__like']) . '%'); } if ('' !== $atts['parent']) { $where[] = $wpdb->prepare('AND tt.parent = %d', $atts['parent']); } if ('count' == $atts['fields']) { $atts['hierarchical'] = FALSE; } if ($atts['hide_empty'] && !$atts['hierarchical']) { $where[] = 'AND tt.count > 0'; } // Do not limit the query results when we have to descend the family tree. if ($atts['number'] && !$atts['hierarchical'] && !$atts['child_of'] && '' === $atts['parent']) { $atts['number'] = absint($atts['number']); $atts['offset'] = absint($atts['offset']); if ($atts['offset']) { $limit = $wpdb->prepare('LIMIT %d,%d', $atts['offset'], $atts['number']); } else { $limit = $wpdb->prepare('LIMIT %d', $atts['number']); } } else { $limit = ''; } if (!empty($atts['search'])) { //$atts['search'] = like_escape( $atts['search'] ); $atts['search'] = $wpdb->esc_like($atts['search']); $where[] = $wpdb->prepare('AND ( (t.name LIKE %s) OR (t.slug LIKE %s) )', '%' . $atts['search'] . '%', '%' . $atts['search'] . '%'); } // Meta query support. $distinct = ''; $join = ''; if (!empty($atts['meta_query'])) { $meta_query = new cnMeta_Query($atts['meta_query']); $meta_clauses = $meta_query->get_sql('term', 't', 'term_id'); $distinct .= 'DISTINCT '; $join .= $meta_clauses['join']; $where[] = $meta_clauses['where']; } switch ($atts['fields']) { case 'all': $select = array('t.*', 'tt.*'); break; case 'ids': case 'id=>parent': $select = array('t.term_id', 'tt.parent', 'tt.count'); break; case 'names': $select = array('t.term_id', 'tt.parent', 'tt.count', 't.name'); break; case 'count': $orderBy = ''; //$order = ''; $select = array('COUNT(*)'); break; case 'id=>name': $select = array('t.term_id', 't.name', 'tt.count', 'tt.taxonomy'); break; case 'id=>slug': $select = array('t.term_id', 't.slug', 'tt.count', 'tt.taxonomy'); break; } /** * Filter the fields to select in the terms query. * * @since 8.1 * * @param array $select An array of fields to select for the terms query. * @param array $atts An array of term query arguments. * @param string|array $taxonomies A taxonomy or array of taxonomies. */ $fields = implode(', ', apply_filters('cn_get_terms_fields', $select, $atts, $taxonomies)); $join .= 'INNER JOIN ' . CN_TERM_TAXONOMY_TABLE . ' AS tt ON t.term_id = tt.term_id'; $pieces = array('fields', 'join', 'where', 'distinct', 'orderBy', 'orderby', 'order', 'limit'); /** * Filter the terms query SQL clauses. * * @since 8.1 * * @param array $pieces Terms query SQL clauses. * @param string|array $taxonomies A taxonomy or array of taxonomies. * @param array $atts An array of terms query arguments. */ $clauses = apply_filters('cn_terms_clauses', compact($pieces), $taxonomies, $atts); foreach ($pieces as $piece) { ${$piece} = isset($clauses[$piece]) ? $clauses[$piece] : ''; } $sql = sprintf('SELECT %1$s FROM %2$s AS t %3$s WHERE %4$s %5$s%6$s', $distinct . $fields, CN_TERMS_TABLE, $join, implode(' ', $where), $orderBy, empty($limit) ? '' : ' ' . $limit); if ('count' == $atts['fields']) { $term_count = $wpdb->get_var($sql); return absint($term_count); } $terms = $wpdb->get_results($sql); if ('all' == $atts['fields']) { foreach ($taxonomies as $taxonomy) { update_term_cache($terms, 'cn_' . $taxonomy); } } // Prime term meta cache. if ($atts['update_meta_cache']) { $term_ids = wp_list_pluck($terms, 'term_id'); cnMeta::updateCache('term', $term_ids); } if (empty($terms)) { wp_cache_add($cache_key, array(), 'cn_terms', DAY_IN_SECONDS); $terms = apply_filters('cn_terms', array(), $taxonomies, $atts); return $terms; } if ($atts['child_of']) { $children = self::childrenIDs(reset($taxonomies)); if (!empty($children)) { $terms = self::descendants($atts['child_of'], $terms, reset($taxonomies)); } } /* * @todo Add method to adjust counts based on user visibility permissions. */ // Update term counts to include children. if ($atts['pad_counts'] && 'all' == $atts['fields']) { foreach ($taxonomies as $_tax) { self::padCounts($terms, $_tax); } } // Make sure we show empty categories that have children. if ($atts['hierarchical'] && $atts['hide_empty'] && is_array($terms)) { foreach ($terms as $k => $term) { if (!$term->count) { $children = self::children($term->term_id, $term->taxonomy); if (is_array($children)) { foreach ($children as $child_id) { $child = self::filter($child_id, $term->taxonomy); if ($child->count) { continue 2; } } } // It really is empty unset($terms[$k]); } } } $_terms = array(); if ('id=>parent' == $atts['fields']) { foreach ($terms as $term) { $_terms[$term->term_id] = $term->parent; } } elseif ('ids' == $atts['fields']) { foreach ($terms as $term) { $_terms[] = $term->term_id; } } elseif ('names' == $atts['fields']) { foreach ($terms as $term) { $_terms[] = $term->name; } } elseif ('id=>name' == $atts['fields']) { foreach ($terms as $term) { $_terms[$term->term_id] = $term->name; } } elseif ('id=>slug' == $atts['fields']) { foreach ($terms as $term) { $_terms[$term->term_id] = $term->slug; } } if (!empty($_terms)) { $terms = $_terms; } if ($atts['number'] && is_array($terms) && count($terms) > $atts['number']) { $terms = array_slice($terms, $atts['offset'], $atts['number']); } wp_cache_add($cache_key, $terms, 'cn_terms', DAY_IN_SECONDS); if ('all' === $atts['fields']) { $terms = array_map(array('cnTerm', 'get'), $terms); } $terms = apply_filters('cn_terms', $terms, $taxonomies, $atts); return $terms; }
/** * Load data from connections for the doubles team. */ protected function load() { if ($this->cnData === null) { global $connections; $cnRetrieve = $connections->retrieve; $ret = $cnRetrieve->entries(array('family_name' => $this->familyName, 'allow_public_override' => true, 'private_override' => true)); if (count($ret) == 1) { $this->cnData = $ret[0]; $this->cnMeta = array(); $allMeta = cnMeta::get('entry', $this->cnData->id); if (is_array($allMeta)) { foreach ($allMeta as $key => $values) { $this->cnMeta[$key] = $values[0]; } } } else { $this->cnData = new StdClass(); $this->cnMeta = array(); } } }