/** * Intercept EDD's [downloads] shortcode * @since 2.0.4 */ function edd_downloads_query($query) { if (!empty(FWP()->facet->query_args)) { $query = array_merge($query, FWP()->facet->query_args); } return $query; }
/** * Initialize classes and WP hooks */ function init() { // i18n $this->load_textdomain(); // is_plugin_active include_once ABSPATH . 'wp-admin/includes/plugin.php'; // classes foreach (array('helper', 'ajax', 'facet', 'indexer', 'display', 'upgrade') as $f) { include FACETWP_DIR . "/includes/class-{$f}.php"; } new FacetWP_Upgrade(); FWP()->helper = new FacetWP_Helper(); FWP()->facet = new FacetWP_Facet(); FWP()->indexer = new FacetWP_Indexer(); FWP()->display = new FacetWP_Display(); FWP()->ajax = new FacetWP_Ajax(); // integrations foreach (array('searchwp', 'woocommerce', 'edd', 'acf') as $f) { include FACETWP_DIR . "/includes/integrations/{$f}/{$f}.php"; } include FACETWP_DIR . '/includes/functions.php'; // hooks add_action('admin_menu', array($this, 'admin_menu')); add_action('wp_enqueue_scripts', array($this, 'front_scripts')); add_action('admin_enqueue_scripts', array($this, 'admin_scripts')); add_filter('redirect_canonical', array($this, 'redirect_canonical'), 10, 2); }
/** * Index each product's stock status * @since 2.1.4 */ function index_stock_status($return, $params) { $facet = $params['facet']; $defaults = $params['defaults']; if ('woocommerce/stock_status' == $facet['source']) { if ('product' == get_post_type($defaults['post_id'])) { WC()->api->includes(); WC()->api->register_resources(new WC_API_Server('/')); $response = WC()->api->WC_API_Products->get_product($defaults['post_id']); $product = $response['product']; if ('variable' == $product['type']) { $in_stock = false; foreach ($product['variations'] as $variation) { if (true === $variation['in_stock']) { $in_stock = true; break; } } } else { $in_stock = $product['in_stock']; } $defaults['facet_value'] = (int) $in_stock; $defaults['facet_display_value'] = $in_stock ? __('In Stock', 'fwp') : __('Out of Stock', 'fwp'); FWP()->indexer->index_row($defaults); } return true; } return $return; }
public function term_link($link, $term, $taxonomy) { $facets = FWP()->helper->get_facets(); $taxes = $sources = array(); $permalink = FWP()->helper->get_setting('term_permalink', 'slug'); $permalink_type = FWP()->helper->get_setting('permalink_type', 'get'); $term = 'term_id' == $permalink ? $term->term_id : $term->slug; if (empty($facets)) { return $link; } foreach ($facets as $facet) { if (isset($facet['source'])) { $sources[$facet['name']] = $facet['source']; } } if (empty($sources)) { return $link; } foreach ($sources as $name => $source) { $source = str_replace('tax/', '', $source); if ($taxonomy == $source) { $post_type = get_post_type_archive_link('job_listing'); if ('get' == $permalink_type) { $url = add_query_arg('fwp_' . $name, $term, $post_type); } else { $url = $post_type . '#!/' . $name . '=' . $term; } return esc_url($url); } } return $link; }
function listable_facetwp_archive_query($query_args) { $uri = FWP()->facet->http_params['uri']; if (false !== strpos($uri, 'listing-category')) { $query_args['tax_query'][] = array('taxonomy' => 'job_listing_category', 'field' => 'slug', 'terms' => basename($uri)); } elseif (false !== strpos($uri, 'listing-type')) { $query_args['tax_query'][] = array('taxonomy' => 'job_listing_type', 'field' => 'slug', 'terms' => basename($uri)); } elseif (false !== strpos($uri, 'listing-region')) { $query_args['tax_query'][] = array('taxonomy' => 'job_listing_region', 'field' => 'slug', 'terms' => basename($uri)); } elseif (false !== strpos($uri, 'listing-tag')) { $query_args['tax_query'][] = array('taxonomy' => 'job_listing_tag', 'field' => 'slug', 'terms' => basename($uri)); } return $query_args; }
/** * Connect to the activation server to get update details */ function check_update($transient) { if (empty($transient->checked)) { return $transient; } $request = wp_remote_post('http://api.facetwp.com', array('body' => array('action' => 'version', 'slug' => $this->slug, 'license' => $this->license, 'host' => FWP()->helper->get_http_host()))); if (!is_wp_error($request) || 200 == wp_remote_retrieve_response_code($request)) { $response = unserialize($request['body']); if (!empty($response)) { if (version_compare($this->version, $response->version, '<')) { $transient->response['facetwp/index.php'] = (object) array('slug' => $this->slug, 'plugin' => FACETWP_BASENAME, 'new_version' => $response->version, 'url' => $response->url, 'package' => $response->package); } update_option('facetwp_activation', json_encode($response->activation)); } } return $transient; }
/** * Handle "source_other" setting */ function index_source_other($value, $params) { $facet = FWP()->helper->get_facet_by_name($params['facet_name']); if (!empty($facet['source_other'])) { $hierarchy = explode('/', substr($facet['source_other'], 4)); $value = get_field($hierarchy[0], $params['post_id'], false); // handle repeater values if (1 < count($hierarchy)) { array_shift($hierarchy); $value = $this->process_field_value($value, $hierarchy); return reset($value); // return first element } } return $value; }
public function get_facets($facets = false) { $facets = $facets ? $facets : listify_theme_mod('listing-archive-facetwp-defaults'); $_facets = array(); if (!is_array($facets)) { $facets = array_map('trim', explode(',', $facets)); } foreach ($facets as $key => $facet_name) { $facet = FWP()->helper->get_facet_by_name($facet_name); if (!$facet) { continue; } $_facets[] = $facet; } return $_facets; }
public $indexer; public $display; private static $instance; function __construct() { // setup variables define('FACETWP_VERSION', '2.2.8'); define('FACETWP_DIR', dirname(__FILE__)); define('FACETWP_URL', plugins_url(basename(FACETWP_DIR))); define('FACETWP_BASENAME', plugin_basename(__FILE__)); // get the gears turning include FACETWP_DIR . '/includes/class-updater.php'; include FACETWP_DIR . '/includes/class-init.php'; } /** * Singleton */ public static function instance() { if (!isset(self::$instance)) { self::$instance = new self(); } return self::$instance; } } function FWP() { return FacetWP::instance(); } $facetwp = FWP();
/** * Does a facet with the specified setting exist? * @return boolean * @since 1.4.0 */ function facet_setting_exists($setting_name, $setting_value) { foreach (FWP()->facet->facets as $f) { if (isset($f[$setting_name]) && $f[$setting_name] == $setting_value) { return true; } } return false; }
/** * Get ALL post IDs for the matching query * @return array An array of post IDs */ function get_filtered_post_ids() { global $wpdb; // Only get relevant post IDs $args = array_merge($this->query_args, array('fields' => 'ids', 'posts_per_page' => -1, 'paged' => 1, 'cache_results' => false)); $query = new WP_Query($args); $post_ids = (array) $query->posts; // Allow hooks to modify the default post IDs $post_ids = apply_filters('facetwp_pre_filtered_post_ids', $post_ids, $this); // Determine whether we need to store unfiltered post IDs $store_ids = apply_filters('facetwp_store_unfiltered_post_ids', false); if ($store_ids) { FWP()->unfiltered_post_ids = $post_ids; } foreach ($this->facets as $the_facet) { // Stop looping if (empty($post_ids)) { break; } $matches = array(); $selected_values = $the_facet['selected_values']; if (empty($selected_values)) { continue; } // Get the facet details $facet_type = $the_facet['type']; // Handle each facet if (isset($this->facet_types[$facet_type]) && !empty($selected_values)) { $hook_params = array('facet' => $the_facet, 'selected_values' => $selected_values); // Hook to support custom filter_posts() handler $matches = apply_filters('facetwp_facet_filter_posts', false, $hook_params); if (false === $matches) { $matches = $this->facet_types[$facet_type]->filter_posts($hook_params); } } // Skip this facet if ('continue' == $matches) { continue; } // Store post IDs per facet // Required for dropdowns and checkboxes in "or" mode if ($store_ids) { FWP()->or_values[$the_facet['name']] = $matches; } // Preserve post ID order for search facets if ('search' == $facet_type) { $this->is_search = true; $intersected_ids = array(); foreach ($matches as $match) { if (in_array($match, $post_ids)) { $intersected_ids[] = $match; } } $post_ids = $intersected_ids; } else { $post_ids = array_intersect($post_ids, $matches); } } // Return a zero array if no matches if (empty($post_ids)) { $post_ids = array(0); } // Reset any array keys $post_ids = array_values($post_ids); return apply_filters('facetwp_filtered_post_ids', $post_ids, $this); }
/** * After the final list of post IDs has been produced, * sort them by distance if needed */ function sort_by_distance($post_ids, $class) { $ordered_posts = FWP()->helper->facet_types['proximity']->ordered_posts; if (!empty($ordered_posts)) { // Sort the post IDs according to distance $intersected_ids = array(); foreach ($ordered_posts as $p) { if (in_array($p, $post_ids)) { $intersected_ids[] = $p; } } $post_ids = $intersected_ids; } return $post_ids; }
$message .= ' (' . __('expires', 'fwp') . ' ' . date('M j, Y', strtotime($activation->expiration)) . ')'; } else { $message = $activation->message; } } // Export feature $export = array(); $settings = FWP()->helper->settings; foreach ($settings['facets'] as $facet) { $export['facet-' . $facet['name']] = 'Facet - ' . $facet['label']; } foreach ($settings['templates'] as $template) { $export['template-' . $template['name']] = 'Template - ' . $template['label']; } // Data sources $sources = FWP()->helper->get_data_sources(); ?> <script src="<?php echo FACETWP_URL; ?> /assets/js/event-manager.js?ver=<?php echo FACETWP_VERSION; ?> "></script> <script src="<?php echo FACETWP_URL; ?> /assets/js/src/query-builder.js?ver=<?php echo FACETWP_VERSION; ?>
/** * Output facet scripts */ function front_scripts() { // Not enqueued - front.js needs to load before front_scripts() if (true === apply_filters('facetwp_load_assets', $this->load_assets)) { if (true === apply_filters('facetwp_load_css', true)) { echo '<link href="' . FACETWP_URL . '/assets/css/front.css?ver=' . FACETWP_VERSION . '" rel="stylesheet">' . "\n"; } echo '<script src="' . FACETWP_URL . '/assets/js/event-manager.js?ver=' . FACETWP_VERSION . '"></script>' . "\n"; echo '<script src="' . FACETWP_URL . '/assets/js/front.js?ver=' . FACETWP_VERSION . '"></script>' . "\n"; // Output the ajaxurl and HTTP params $this->ajaxurl(); foreach ($this->active_types as $type) { FWP()->helper->facet_types[$type]->front_scripts(); } } }
/** * Generate the facet HTML */ function render($params) { global $wpdb; $output = ''; $facet = $params['facet']; $selected_values = (array) $params['selected_values']; $where_clause = $params['where_clause']; // Orderby $orderby = 'counter DESC, f.facet_display_value ASC'; if ('display_value' == $facet['orderby']) { $orderby = 'f.facet_display_value ASC'; } elseif ('raw_value' == $facet['orderby']) { $orderby = 'f.facet_value ASC'; } // Visible results $num_visible = ctype_digit($facet['count']) ? $facet['count'] : 10; $max_depth = 0; $facet_parent_id = 0; // Determine the parent_id and depth if (!empty($selected_values[0])) { $value = $selected_values[0]; $taxonomy = str_replace('tax/', '', $facet['source']); // Associate array of term IDs with term information $depths = FWP()->helper->get_term_depths($taxonomy); // Lookup the term ID from its slug $sql = "\n SELECT t.term_id\n FROM {$wpdb->terms} t\n INNER JOIN {$wpdb->term_taxonomy} tt ON tt.term_id = t.term_id AND tt.taxonomy = %s\n WHERE t.slug = %s\n LIMIT 1"; $facet_parent_id = (int) $wpdb->get_var($wpdb->prepare($sql, $taxonomy, $value)); $max_depth = (int) $depths[$facet_parent_id]['depth']; $last_parent_id = $facet_parent_id; $prev_links = array(); for ($i = 0; $i <= $max_depth; $i++) { $prev_links[] = array('value' => $depths[$last_parent_id]['slug'], 'label' => $depths[$last_parent_id]['name']); $last_parent_id = (int) $depths[$last_parent_id]['parent_id']; } $prev_links[] = array('value' => '', 'label' => __('Any', 'fwp')); // Reverse the navigation $prev_links = array_reverse($prev_links); $num_links = count($prev_links); foreach ($prev_links as $counter => $prev_link) { if ($counter == $num_links - 1) { $active = ' checked'; } else { $active = ''; $prev_link['label'] = '‹ ' . $prev_link['label']; } if (0 < $counter) { $output .= '<div class="facetwp-depth">'; } $output .= '<div class="facetwp-link' . $active . '" data-value="' . $prev_link['value'] . '">' . $prev_link['label'] . '</div>'; } } $sql = "\n SELECT f.facet_value, f.facet_display_value, COUNT(*) AS counter\n FROM {$wpdb->prefix}facetwp_index f\n WHERE f.facet_name = '{$facet['name']}' {$where_clause} AND parent_id = '{$facet_parent_id}'\n GROUP BY f.facet_value\n ORDER BY {$orderby}"; $results = $wpdb->get_results($sql); $key = 0; if (!empty($prev_links)) { $output .= '<div class="facetwp-depth">'; } if (!empty($results)) { foreach ($results as $key => $result) { if ($key == (int) $num_visible) { $output .= '<div class="facetwp-collapsed facetwp-hidden">'; } $output .= '<div class="facetwp-link" data-value="' . $result->facet_value . '">'; $output .= $result->facet_display_value . ' <span class="facetwp-counter">(' . $result->counter . ')</span>'; $output .= '</div>'; } } if ($num_visible <= $key) { $output .= '</div>'; $output .= '<div class="facetwp-toggle">+ ' . __('More', 'fwp') . '</div>'; $output .= '<div class="facetwp-toggle facetwp-hidden">- ' . __('Less', 'fwp') . '</div>'; } for ($i = 0; $i <= $max_depth; $i++) { $output .= '</div>'; } if (!empty($prev_links)) { $output .= '</div>'; } return $output; }
/** * Output any front-end scripts */ function front_scripts() { FWP()->display->assets['flatpickr.css'] = FACETWP_URL . '/assets/js/flatpickr/flatpickr.css'; FWP()->display->assets['flatpickr.js'] = FACETWP_URL . '/assets/js/flatpickr/flatpickr.min.js'; ?> <script> (function($) { wp.hooks.addAction('facetwp/refresh/availability', function($this, facet_name) { var min = $this.find('.facetwp-date-min').val() || ''; var max = $this.find('.facetwp-date-max').val() || ''; var quantity = $this.find('.facetwp-quantity').val() || 1; FWP.facets[facet_name] = ('' != min && '' != max) ? [min, max, quantity] : []; }); wp.hooks.addFilter('facetwp/selections/availability', function(output, params) { return params.selected_values[0] + ' - ' + params.selected_values[1]; }); $(document).on('facetwp-loaded', function() { var $dates = $('.facetwp-type-availability .facetwp-date:not(.ready)'); if (0 === $dates.length) { return; } var flatpickr_opts = { //enableTime: true, minDate: new Date().toISOString().slice(0, 10), onReady: function(dateObj, dateStr, instance) { var $cal = $(instance.calendarContainer); if ($cal.find('.flatpickr-clear').length < 1) { $cal.append('<div class="flatpickr-clear">Clear</div>'); $cal.find('.flatpickr-clear').on('click', function() { instance.clear(); instance.close(); }); } } }; $dates.each(function() { var facet_name = $(this).closest('.facetwp-facet').attr('data-name'); var opts = wp.hooks.applyFilters('facetwp/set_options/availability', flatpickr_opts, { 'facet_name': facet_name }); new Flatpickr(this, opts); $(this).addClass('ready'); }); }); $(document).on('click', '.facetwp-availability-update', function() { FWP.autoload(); }); })(jQuery); </script> <?php }
/** * License activation */ function license() { $license = $_POST['license']; $request = wp_remote_post('http://api.facetwp.com', array('body' => array('action' => 'activate', 'slug' => 'facetwp', 'license' => $license, 'host' => FWP()->helper->get_http_host()))); if (!is_wp_error($request) || 200 == wp_remote_retrieve_response_code($request)) { update_option('facetwp_license', $license); update_option('facetwp_activation', $request['body']); echo $request['body']; } else { echo json_encode(array('status' => 'error', 'message' => __('Error', 'fwp') . ': ' . $request->get_error_message())); } exit; }
/** * An alternate to using do_shortcode() * @since 1.7.5 */ function facetwp_display() { $args = func_get_args(); $atts = isset($args[1]) ? array($args[0] => $args[1]) : array($args[0] => true); return FWP()->display->shortcode($atts); }
/** * Save a facet value to DB * This can be trigged by "facetwp_index_row" to handle multiple values * @since 1.2.5 */ function insert($params) { global $wpdb; // Only accept scalar values $value = $params['facet_value']; if ('' === $value || !is_scalar($value)) { return; } $wpdb->query($wpdb->prepare("INSERT INTO {$wpdb->prefix}facetwp_index\n (post_id, facet_name, facet_source, facet_value, facet_display_value, term_id, parent_id, depth) VALUES (%d, %s, %s, %s, %s, %d, %d, %d)", $params['post_id'], $params['facet_name'], $params['facet_source'], FWP()->helper->safe_value($value), $params['facet_display_value'], $params['term_id'], $params['parent_id'], $params['depth'])); }
/** * Index a single value. * * @since 1.0.0 * * @param array $value The array of values to index. Available keys in the array are: post_id, facet_name, * facet_source, facet_value, facet_display_value, term_id, parent_id, and depth. For more * information, see @link https://facetwp.com/documentation/facetwp_index_row/ * @param array $defaults Default values to use when indexing. */ public function index_row($value, $defaults) { FWP()->indexer->index_row(wp_parse_args($value, $defaults)); }
/** * Store unfiltered post IDs if a dropdown facet exists */ function store_unfiltered_post_ids($boolean) { if (FWP()->helper->facet_setting_exists('type', 'dropdown')) { return true; } return $boolean; }
/** * Store unfiltered post IDs if a checkbox facet exists * with ghosts or "OR" mode enabled */ function store_unfiltered_post_ids($boolean) { if (FWP()->helper->facet_setting_exists('ghosts', 'yes')) { return true; } if (FWP()->helper->facet_setting_exists('operator', 'or')) { return true; } return $boolean; }
/** * Index the 2nd data source * @since 2.1.1 */ function index_row($params, $class) { if ($class->is_overridden) { return $params; } $facet = FWP()->helper->get_facet_by_name($params['facet_name']); if ('slider' == $facet['type'] && !empty($facet['source_other'])) { $other_params = $params; $other_params['facet_source'] = $facet['source_other']; $rows = $class->get_row_data($other_params); $params['facet_display_value'] = $rows[0]['facet_display_value']; } return $params; }