$aud) { $key = (string) $key; $aud = sanitize_key((string) $aud); if ('' === $key || !in_array($aud, $vocab, true) || 'unknown' === $aud) { continue; } if (!preg_match('#^([a-z0-9_\-]+):([0-9]+)$#', $key, $m)) { continue; } $out[$m[1] . ':' . (int) $m[2]] = $aud; } return $out; } public static function grid() { $vocab = self::vocabulary(); $default = array( 'male' => array('male', 'unisex', 'unknown'), 'female' => array('female', 'unisex', 'unknown'), 'unisex' => array('male', 'female', 'unisex', 'unknown'), 'kids' => array('kids', 'unisex', 'unknown'), 'unknown' => $vocab, ); $stored = self::setting('audience_grid', null); $grid = array(); foreach ($vocab as $anchor) { $row = isset($default[$anchor]) ? $default[$anchor] : $vocab; if (is_array($stored) && isset($stored[$anchor]) && is_array($stored[$anchor])) { $row = $stored[$anchor]; } $clean = array(); foreach ((array) $row as $t) { $t = sanitize_key((string) $t); if (in_array($t, $vocab, true) && !in_array($t, $clean, true)) { $clean[] = $t; } } if (!in_array('unknown', $clean, true)) { $clean[] = 'unknown'; } $grid[$anchor] = $clean; } return $grid; } public static function allows($anchor, $target) { $grid = self::grid(); $anchor = ('' === (string) $anchor) ? 'unknown' : (string) $anchor; $target = ('' === (string) $target) ? 'unknown' : (string) $target; if (!isset($grid[$anchor])) { return true; } return in_array($target, $grid[$anchor], true); } public static function markers_in($text, $structural = true) { return class_exists('AIEO_Audience_Lexicon') ? (array) AIEO_Audience_Lexicon::markers_in($text, $structural) : array(); } public static function collapse(array $hits) { if (empty($hits)) { return ''; } if (in_array('unisex', $hits, true)) { return 'unisex'; } if (count(array_intersect($hits, array('male', 'female'))) >= 2) { return 'unisex'; } return (string) reset($hits); } public static function classify_name($name) { return self::collapse(self::markers_in($name, true)); } public static function scan() { $stored = self::term_map(); $out = array(); foreach (self::taxonomies() as $tx) { if (!taxonomy_exists($tx)) { continue; } $terms = get_terms(array('taxonomy' => $tx, 'hide_empty' => false)); if (is_wp_error($terms) || empty($terms)) { continue; } foreach ($terms as $t) { $key = $tx . ':' . (int) $t->term_id; $proposed = self::classify_name($t->name); $confirmed = isset($stored[$key]); if ('' === $proposed && !$confirmed) { continue; } $out[] = array( 'key' => $key, 'taxonomy' => $tx, 'term_id' => (int) $t->term_id, 'name' => (string) $t->name, 'count' => (int) $t->count, 'audience' => $confirmed ? $stored[$key] : $proposed, 'confirmed' => $confirmed, 'caution' => ('product_brand' === $tx), ); } } return $out; } private static function expanded_map() { static $memo = null; if (null !== $memo) { return $memo; } $memo = array(); $map = self::term_map(); foreach ($map as $key => $aud) { list($tx, $tid) = explode(':', $key, 2); if (!taxonomy_exists($tx)) { continue; } if (!isset($memo[$tx])) { $memo[$tx] = array(); } if (!is_taxonomy_hierarchical($tx)) { continue; } $kids = get_term_children((int) $tid, $tx); if (is_wp_error($kids)) { continue; } foreach ((array) $kids as $kid) { $memo[$tx][(int) $kid] = $aud; } } foreach ($map as $key => $aud) { list($tx, $tid) = explode(':', $key, 2); if (!taxonomy_exists($tx)) { continue; } if (!isset($memo[$tx])) { $memo[$tx] = array(); } $memo[$tx][(int) $tid] = $aud; } return $memo; } public static function resolve(array $ids, $default_type = 'product') { static $memo = array(); $ids = array_values(array_unique(array_filter(array_map('intval', $ids)))); $out = array(); $ask = array(); foreach ($ids as $id) { if (isset($memo[$id])) { $out[$id] = $memo[$id]; } else { $ask[] = $id; } } if (empty($ask)) { return $out; } $found = array(); $src = array(); $map = self::expanded_map(); foreach (self::taxonomies() as $tx) { if (empty($map[$tx])) { continue; } $pending = array(); foreach ($ask as $id) { if (!isset($found[$id])) { $pending[] = $id; } } if (empty($pending)) { break; } foreach (array_chunk($pending, 200) as $chunk) { $terms = wp_get_object_terms($chunk, $tx, array('fields' => 'all_with_object_id')); if (is_wp_error($terms) || empty($terms)) { continue; } foreach ($terms as $t) { $tid = (int) $t->term_id; if (!isset($map[$tx][$tid])) { continue; } $oid = (int) $t->object_id; $found[$oid][$map[$tx][$tid]] = true; $src[$oid] = $tx; } } } if (self::title_markers_enabled()) { $pending = array(); foreach ($ask as $id) { if (!isset($found[$id])) { $pending[] = $id; } } if ($pending) { global $wpdb; $vocab = self::vocabulary(); $stamped = array(); foreach (array_chunk($pending, 400) as $chunk) { $ph = implode(',', array_fill(0, count($chunk), '%d')); $rows = $wpdb->get_results($wpdb->prepare( "SELECT post_id, meta_value FROM {$wpdb->postmeta} WHERE meta_key = %s AND post_id IN ({$ph})", array_merge(array(self::TITLE_STAMP_META), $chunk) ), ARRAY_A); foreach ((array) $rows as $r) { $id = (int) $r['post_id']; $v = (string) $r['meta_value']; if ('' === $v) { continue; } $stamped[$id] = true; if ('none' !== $v && 'unknown' !== $v && in_array($v, $vocab, true)) { $found[$id][$v] = true; $src[$id] = 'title'; } } } $live = array(); foreach ($pending as $id) { if (!isset($found[$id]) && !isset($stamped[$id])) { $live[] = $id; } } if ($live && class_exists('AIEO_Audience_Lexicon')) { foreach (array_chunk($live, 400) as $chunk) { $ph = implode(',', array_fill(0, count($chunk), '%d')); $rows = $wpdb->get_results($wpdb->prepare( "SELECT ID, post_title FROM {$wpdb->posts} WHERE ID IN ({$ph})", $chunk ), ARRAY_A); foreach ((array) $rows as $r) { $a = self::classify_name($r['post_title']); if ('' !== $a) { $found[(int) $r['ID']][$a] = true; $src[(int) $r['ID']] = 'title'; } } } } } } foreach ($ask as $id) { $aud = isset($found[$id]) ? self::collapse(array_keys($found[$id])) : ''; $row = array( 'audience' => ('' === $aud) ? 'unknown' : $aud, 'source' => ('' === $aud) ? 'none' : (isset($src[$id]) ? $src[$id] : 'none'), ); $memo[$id] = $row; $out[$id] = $row; } unset($default_type); return $out; } }