__( 'contains', DFRAPI_DOMAIN ), 'not_contain' => __( 'doesn\'t contain', DFRAPI_DOMAIN ), 'start' => __( 'starts with', DFRAPI_DOMAIN ), 'end' => __( 'ends with', DFRAPI_DOMAIN ), 'match' => __( 'matches', DFRAPI_DOMAIN ) ); $opFulltextExact = array_merge($opFulltext, array( 'is' => __( 'is', DFRAPI_DOMAIN ) )); $opRange = array( 'lt' => __( 'less than', DFRAPI_DOMAIN ), 'gt' => __( 'greater than', DFRAPI_DOMAIN ), 'between' => __( 'between', DFRAPI_DOMAIN ) ); $opIs = array( 'is' => __( 'is', DFRAPI_DOMAIN ) ); $opIsIsnt = array( 'is' => __( 'is', DFRAPI_DOMAIN ), 'is_not' => __( 'isn\'t', DFRAPI_DOMAIN ) ); $opYesNo = array( 'yes' => __( 'yes', DFRAPI_DOMAIN ), 'no' => __( 'no', DFRAPI_DOMAIN ) ); $sortOpts = array( '' => __( 'Relevance', DFRAPI_DOMAIN ), '+price' => __( 'Price Ascending', DFRAPI_DOMAIN ), '-price' => __( 'Price Decending', DFRAPI_DOMAIN ), '+saleprice' => __( 'Sale Price Ascending', DFRAPI_DOMAIN ), '-saleprice' => __( 'Sale Price Decending', DFRAPI_DOMAIN ), '+salediscount' => __( 'Discount Ascending', DFRAPI_DOMAIN ), '-salediscount' => __( 'Discount Decending', DFRAPI_DOMAIN ), '+merchant' => __( 'Merchant', DFRAPI_DOMAIN ), '+time_updated' => __( 'Last updated Ascending', DFRAPI_DOMAIN ), '-time_updated' => __( 'Last updated Decending', DFRAPI_DOMAIN ) ); return array( array( 'title' => __( 'Any field', DFRAPI_DOMAIN ), 'name' => 'any', 'input' => 'text', 'operator' => $opFulltext ), array( 'title' => __( 'Product name', DFRAPI_DOMAIN ), 'name' => 'name', 'input' => 'text', 'operator' => $opFulltextExact, ), array( 'title' => __( 'Brand', DFRAPI_DOMAIN ), 'name' => 'brand', 'input' => 'text', 'operator' => $opFulltextExact, ), array( 'title' => __( 'Description', DFRAPI_DOMAIN ), 'name' => 'description', 'input' => 'text', 'operator' => $opFulltext, ), array( 'title' => __( 'Tags', DFRAPI_DOMAIN ), 'name' => 'tags', 'input' => 'text', 'operator' => array( 'in' => __( 'contain', DFRAPI_DOMAIN ), 'not_in' => __( 'don\'t contain', DFRAPI_DOMAIN ) ) ), array( 'title' => __( 'Category', DFRAPI_DOMAIN ), 'name' => 'category', 'input' => 'text', 'operator' => $opFulltext ), array( 'title' => __( 'Product type', DFRAPI_DOMAIN ), 'name' => 'type', 'input' => 'select', 'options' => array( 'products' => __( 'Product', DFRAPI_DOMAIN ), 'coupons' => __( 'Coupon', DFRAPI_DOMAIN ) ), 'operator' => $opIs ), array( 'title' => __( 'Currency', DFRAPI_DOMAIN ), 'name' => 'currency', 'input' => 'select', 'options' => array( 'USD' => 'USD', 'CAD' => 'CAD', 'GBP' => 'GBP', 'EUR' => 'EUR', 'AUD' => 'AUD', 'DKK' => 'DKK', 'SEK' => 'SEK', 'NOK' => 'NOK', 'CHF' => 'CHF', 'NZD' => 'NZD', 'TRY' => 'TRY', ), 'operator' => $opIsIsnt ), array( 'title' => __( 'Price', DFRAPI_DOMAIN ), 'name' => 'price', 'input' => 'range', 'operator' => $opRange ), array( 'title' => __( 'Sale Price', DFRAPI_DOMAIN ), 'name' => 'saleprice', 'input' => 'range', 'operator' => $opRange ), array( 'title' => __( 'Network', DFRAPI_DOMAIN ), 'name' => 'source_id', 'input' => 'network', 'operator' => $opIsIsnt ), array( 'title' => __( 'Merchant', DFRAPI_DOMAIN ), 'name' => 'merchant_id', 'input' => 'merchant', 'operator' => $opIsIsnt ), array( 'title' => __( 'On Sale', DFRAPI_DOMAIN ), 'name' => 'onsale', 'input' => 'none', 'operator' => $opYesNo ), array( 'title' => __( 'Discount', DFRAPI_DOMAIN ), 'name' => 'salediscount', 'input' => 'range', 'operator' => $opRange ), array( 'title' => __( 'Has Image', DFRAPI_DOMAIN ), 'name' => 'image', 'input' => 'none', 'operator' => $opYesNo ), array( 'title' => __( 'Last updated', DFRAPI_DOMAIN ), 'name' => 'time_updated', 'input' => 'range', 'operator' => array('lt' => 'before', 'gt' => 'after', 'between' => 'between'), ), array( 'title' => __( 'Limit', DFRAPI_DOMAIN ), 'name' => 'limit', 'input' => 'text', 'operator' => array('is' => 'is') ), array( 'title' => __( 'Sort By', DFRAPI_DOMAIN ), 'name' => 'sort', 'input' => 'none', 'operator' => $sortOpts ), array( 'title' => __( 'Exclude Duplicates', DFRAPI_DOMAIN ), 'name' => 'duplicates', 'input' => 'text', 'operator' => array( 'is' => __( 'matching these fields', DFRAPI_DOMAIN ), ) ) ); } function defaults() { return array( 'any' => array('operator' => 'contain', 'value'=> ''), 'name' => array('operator' => 'contain', 'value'=> ''), 'type' => array('value'=> 'product'), 'currency' => array('value'=> 'USD'), 'price' => array('operator' => 'between', 'value'=> '0', 'value2' => '999999'), 'saleprice' => array('operator' => 'between', 'value'=> '0', 'value2' => '999999'), 'source_id' => array('value'=> array()), 'merchant_id' => array('value'=> array()), 'onsale' => array('value'=> '1'), 'image' => array('value'=> '1'), 'thumbnail' => array('value'=> '1'), 'time_updated' => array('operator' => 'lt', 'value'=> 'today'), 'limit' => array('value'=> 1000), ); } public $useSelected; public $prefix; function get($ary, $key, $default="") { return is_array($ary) && isset($ary[$key]) ? $ary[$key] : $default; } function inputPrefix($index) { return sprintf('%s[%s]', $this->prefix ? $this->prefix : "query", $index); } function byName($a, $b) { return strcasecmp($a['name'], $b['name']); } function ary($s) { if(!is_array($s)) $s = explode(',', trim($s)); return array_filter($s, 'strlen'); } function ids($lst) { $ids = array(); foreach($lst as $obj) $ids []= $obj['_id']; return $ids; } function selectOpts($opts, $selectedValue=NULL) { $html = ""; foreach($opts as $value => $title) { $sel = $selectedValue == $value ? "selected='selected'" : ""; $title = htmlspecialchars($title); $value = htmlspecialchars($value); $html .= ""; } return $html; } function allNetworks() { $lst = dfrapi_api_get_all_networks(); usort($lst, array($this, 'byName')); return $lst; } function selectedNetworks() { $selected = $this->get(get_option( 'dfrapi_networks' ), 'ids'); if(empty($selected)) return array(); $lst = array(); foreach($this->allNetworks() as $net) if(isset($selected[$net['_id']])) $lst []= $net; return $lst; } function groupClass($nid) { if (empty($nid)) { return ''; } $networks = $this->allNetworks(); foreach($networks as $network) { if ($network['_id'] == $nid) { $name = str_replace( array( " ", "-", "." ), "", $network['group'] ); $type = ( $network['type'] == 'coupons' ) ? '_coupons' : ''; return 'network_logo_16x16_' . strtolower( $name . $type ); } } } function selectedMerchants() { $selected = $this->get(get_option( 'dfrapi_merchants' ), 'ids'); if(empty($selected)) return array(); $lst = array(); foreach(dfrapi_api_get_merchants_by_id($selected) as $merchant) { $lst []= $merchant; } usort($lst, array($this, 'byName')); return $lst; } function networksMerchantsPopup($kind, $value) { $title = array( 'network' => __( 'Select Networks', DFRAPI_DOMAIN ), 'merchant' => __( 'Select Merchants', DFRAPI_DOMAIN ) ); $clear = __( 'Clear search', DFRAPI_DOMAIN ); $ok = __( 'OK', DFRAPI_DOMAIN ); $cells = ""; $all = ($kind == 'network') ? ($this->useSelected ? $this->selectedNetworks() : $this->allNetworks()) : $this->selectedMerchants(); foreach($all as $obj) { $id = $obj['_id']; $nid = ($kind == 'network') ? $obj['_id'] : $obj['source_id']; $group_class = $this->groupClass($nid); $name = $obj['name']; $checked = in_array($id, $value) ? "checked='checked'" : ""; $cells .= "
"; } return "

{$title[$kind]}

Search: ×
{$cells}
$ok
"; } function networksMerchantsNames($kind, $value, $maxNames=5) { $all = ($kind == 'network') ? $this->allNetworks() : dfrapi_api_get_merchants_by_id($value); $names = array(); foreach($all as $obj) { if(in_array($obj['_id'], $value)) { $names []= "{$obj['name']}"; if(count($names) >= $maxNames) break; } } $html = implode(', ', $names); if(count($value) - count($names)) { $html .= ' ' . sprintf(__( 'and %s more', DFRAPI_DOMAIN ), count($value) - count($names)); } return $html; } function chooseBox($kind, $field, $index, $value) { $pfx = $this->inputPrefix($index); $value = implode(',', $this->ary($value)); $choose = __( 'choose', DFRAPI_DOMAIN ); return "
{$choose}
"; } function ajaxHandler() { $command = $this->get($_POST, 'command'); $value = $this->ary($this->get($_POST, 'value')); $this->useSelected = intval($this->get($_POST, 'useSelected', 1)); switch($command) { case "choose_network": return $this->networksMerchantsPopup('network', $value); case "choose_merchant": return $this->networksMerchantsPopup('merchant', $value); case "names_network": return $this->networksMerchantsNames('network', $value); case "names_merchant": return $this->networksMerchantsNames('merchant', $value); } return ""; } function renderField($field, $index, $params) { $pfx = $this->inputPrefix($index); $value = $this->get($params, 'value'); $operator = $this->get($params, 'operator'); $input = ""; switch($field['input']) { case 'text': $value = htmlspecialchars($value); $input = ""; break; case 'select': $opts = $this->selectOpts($field['options'], $value); $input = ""; break; case 'range': $value = htmlspecialchars($value); $value2 = htmlspecialchars($this->get($params, 'value2')); $and = __( 'and', DFRAPI_DOMAIN ); $input = " "; break; case 'network': $input = $this->chooseBox('network', $field, $index, $value); break; case 'merchant': $input = $this->chooseBox('merchant', $field, $index, $value); break; case 'none': $input = ""; break; } if(count($field['operator']) == 1) { $key = key($field['operator']); $val = current($field['operator']); $operator = " {$val} "; } else { $opts = $this->selectOpts($field['operator'], $operator); $operator = ""; } return array($operator, $input); } function renderRow($field, $index, $params, $show) { $pfx = $this->inputPrefix($index); list($operator, $input) = $this->renderField($field, $index, $params); $fieldOpts = ''; foreach($this->fields() as $f) { if(!$this->useSelected && $f['name'] == 'merchant_id') continue; $sel = $field['name'] == $f['name'] ? "selected='selected'" : ""; $fieldOpts .= ""; } $style = $show ? "" : "style='display:none'"; return "
{$input}
{$operator}
"; } function render($prefix, $query, $useSelected=TRUE) { $this->prefix = $prefix; $this->useSelected = intval($useSelected); if(!$query) $query = array( array('field'=>'any', 'value'=>'') ); $defaults = $this->defaults(); $fieldMap = array(); $fieldUsed = array(); foreach($this->fields() as $f) { if(!$this->useSelected && $f['name'] == 'merchant_id') continue; $fieldMap[$f['name']] = $f; } $form = ""; $index = 0; foreach($query as $params) { $field = $this->get($fieldMap, $this->get($params, 'field')); if(!$field) continue; $fieldUsed[$field['name']] = 1; $form .= $this->renderRow($field, $index++, $params, TRUE); } $show = ($index == 0); // if none shown, show the first foreach($fieldMap as $field) { $name = $field['name']; if(!isset($fieldUsed[$name])) { $form .= $this->renderRow($field, $index++, isset($defaults[$name]) ? $defaults[$name] : null, $show); $show = FALSE; } } $loading = __( 'Loading, please wait', DFRAPI_DOMAIN ); $add = __( 'add filter', DFRAPI_DOMAIN ); return "
{$form}
$add
"; } function combineLists($lst, $func) { if(!count($lst)) return array(); if(count($lst) == 1) return current($lst); $lst = call_user_func_array($func, $lst); return count($lst) ? $lst : NULL; } function idFilter($inList, $exList) { $inList = $this->combineLists($inList, 'array_intersect'); $exList = $this->combineLists($exList, 'array_merge'); if(is_null($inList) || is_null($exList)) { return NULL; } if(count($inList)) { if(count($exList)) { $inList = array_diff($inList, $exList); if(!count($inList)) return NULL; } return array("IN", $inList); } if(count($exList)) { return array("!IN", $exList); } return array(NULL, NULL); } function fulltextFilter($operator, $value) { if($operator == 'match') return array("LIKE", $value); $value = trim(preg_replace('~[!\\[\\]"^$]+~', " ", $value)); if(strlen($value)) { switch($operator) { case 'is': return array('LIKE', "^$value\$"); case 'contain': return array('LIKE', $value); case 'not_contain': return array('!LIKE', $value); case 'start': return array('LIKE', "^$value"); case 'end': return array('LIKE', "$value\$"); } } return array(NULL, NULL); } function makeFilters($query, $useSelected=TRUE) { $filters = array(); $selected = array( 'in:source_id' => array(), 'ex:source_id' => array(), 'in:merchant_id' => array(), 'ex:merchant_id' => array(), ); $allNetworks = $this->ids($this->allNetworks()); if($useSelected) { $selected['in:source_id'] []= $this->ids($this->selectedNetworks()); $selected['in:merchant_id'] []= $this->ids($this->selectedMerchants()); } else { $selected['in:source_id'] []= $allNetworks; } foreach($query as $params) { $fname = $params['field']; $value = $this->get($params, 'value'); $value2 = $this->get($params, 'value2'); $operator = strtolower($this->get($params, 'operator')); switch($fname) { case 'any': case 'name': case 'brand': case 'description': case 'category': $s = $this->fulltextFilter($operator, $value); if(!is_null($s[0])) { $filters []= "{$fname} {$s[0]} {$s[1]}"; } break; case 'tags': $operator = ($operator == 'in') ? "LIKE" : "!LIKE"; $filters []= "{$fname} {$operator} {$value}"; break; case 'currency': $filters []= "{$fname} = {$value}"; break; case 'price': case 'saleprice': case 'salediscount': $conv = $fname == 'salediscount' ? 'intval' : 'dfrapi_price_to_int'; $value = $conv($value); switch($operator) { case 'between': $value2 = $conv($value2); $filters []= "{$fname} > {$value}"; $filters []= "{$fname} < {$value2}"; break; case 'lt': $filters []= "{$fname} < {$value}"; break; case 'gt': $filters []= "{$fname} > {$value}"; break; } break; case 'source_id': case 'merchant_id': $key = ($operator == 'is') ? 'in' : 'ex'; $selected["$key:$fname"] []= $this->ary($value); break; case 'type': $ids = array(); foreach($this->allNetworks() as $net) { if($net['type'] == $value) $ids []= $net['_id']; } $selected["in:source_id"] []= $ids; break; case 'onsale': $value = ($operator == 'yes') ? '1' : '0'; $filters []= "{$fname} = {$value}"; break; case 'image': case 'thumbnail': $operator = ($operator == 'yes') ? '!EMPTY' : 'EMPTY'; $filters []= "image {$operator}"; break; case 'time_updated': $value = @date('Y-m-d H:i:s', strtotime($value)); switch($operator) { case 'between': $value2 = @date('Y-m-d H:i:s', strtotime($value2)); $filters []= "{$fname} > {$value}"; $filters []= "{$fname} < {$value2}"; break; case 'lt': $filters []= "{$fname} < {$value}"; break; case 'gt': $filters []= "{$fname} > {$value}"; break; } break; } } $s = $this->idFilter($selected['in:source_id'], $selected['ex:source_id']); if(is_null($s)) return array('error' => 'No networks selected'); if(!is_null($s[0]) && count($s[1]) < count($allNetworks)) $filters []= "source_id {$s[0]} ". implode(',', $s[1]); $s = $this->idFilter($selected['in:merchant_id'], $selected['ex:merchant_id']); if(is_null($s)) return array('error' => 'No merchants selected'); if(!is_null($s[0])) $filters []= "merchant_id {$s[0]} ". implode(',', $s[1]); return $filters; } }