$directory ] ); $_directory = ! empty( $directories ) ? reset( $directories ) : false; } elseif ( is_string( $directory ) ) { $directories = wp_list_filter( adqs_get_directories(), [ 'slug' => $directory ] ); $_directory = ! empty( $directories ) ? reset( $directories ) : false; } elseif ( is_object( $directory ) && isset( $directory->taxonomy ) && $directory->taxonomy === 'adqs_listing_types' ) { $_directory = $directory; } else { return false; } if ( ! $_directory || is_wp_error( $_directory ) ) { return false; } return $_directory; } /** * Get all directory types. * * @deprecated Use adqs_get_directories() instead. * * @param array $args * @return array */ function adqs_get_directory_types( array $args = [] ) { return adqs_get_directories( $args ); } /** * Get all directories. * * @param array $args { * Optional. Array of arguments to filter the directories. Default empty array. * * @type bool $hide_empty Optional. Whether to hide empty directories. Default false. * @type string $orderby Optional. How to order directories. Accepts 'name' or 'term_id'. Default 'name'. * @type string $order Optional. Whether to order directories in ascending or descending order. * Accepts 'ASC' or 'DESC'. Default 'ASC'. * @type string $fields Optional. Whether to return full term objects or specific fields. * Accepts 'all', 'ids', 'names', 'slugs', 'id=>name' or 'id=>slug'. Default 'all'. * } * @return array */ function adqs_get_directories( array $args = [] ): array { $defaults = [ 'hide_empty' => false, 'orderby' => 'name', 'order' => 'ASC', 'fields' => 'all', ]; $args = wp_parse_args( $args, $defaults ); $args['taxonomy'] = 'adqs_listing_types'; $fields = $args['fields']; // Do not pass fields to get_terms() unset( $args['fields'] ); // Build a cache key from the arguments to ensure unique caching per query variation $cache_key = 'adqs_directories_' . md5( serialize( $args ) ); $directories = wp_cache_get( $cache_key ); if ( false !== $directories ) { return $fields === 'all' ? $directories : adqs_filter_directories_by_fields( $directories, $fields ); } $directories = get_terms( $args ); if ( is_wp_error( $directories ) || empty( $directories ) ) { return []; } $directories = array_map( static function ( $directory ) { $directory->post_type = get_term_meta( $directory->term_id, 'adqs_directory_post_type', true ); return $directory; }, $directories ); wp_cache_set( $cache_key, $directories ); return $fields === 'all' ? $directories : adqs_filter_directories_by_fields( $directories, $fields ); } /** * Filter directories by specific fields. * * @param array $directories Array of directory term objects. * @param string $fields The fields to filter by. Accepts 'ids', 'names', 'slugs', 'id=>name', or 'id=>slug'. * * @return array */ function adqs_filter_directories_by_fields( array $directories, string $fields ): array { if ( empty( $directories ) ) { return []; } if ( $fields === 'ids' ) { return array_column( $directories, 'term_id' ); } if ( $fields === 'names' ) { return array_column( $directories, 'name' ); } if ( $fields === 'slugs' ) { return array_column( $directories, 'slug' ); } if ( $fields === 'id=>name' ) { return array_column( $directories, 'name', 'term_id' ); } if ( $fields === 'id=>slug' ) { return array_column( $directories, 'slug', 'term_id' ); } return $directories; } /** * Get all directory post types. * * @deprecated Use adqs_get_directory_post_types() instead. * * @return array */ function adqs_get_all_dynamic_post_types(): array { return adqs_get_directory_post_types(); } /** * Get all directory post types. * * @return array */ function adqs_get_directory_post_types(): array { $directories = adqs_get_directories(); if ( empty( $directories ) ) { return []; } $post_types = []; foreach ( $directories as $directory ) { if ( ! post_type_exists( $directory->post_type ) ) { continue; } $post_types[] = $directory->post_type; } return $post_types; } /** * Get all directory taxonomies. * * @deprecated Use `adqs_get_directory_taxonomies()` instead. * * @param string $post_type * @return array */ function adqs_get_all_dynamic_taxonomies(): array { return adqs_get_directory_taxonomies(); } /** * Get all directory taxonomies. * * @param string $post_type * @param string $output Optional. The type of output to return in the array. Accepts either * 'names' or 'objects'. Default 'names'. * * @return array */ function adqs_get_directory_taxonomies( $post_type = '', $output = 'names' ) { if ( ! empty( $post_type ) ) { $taxonomies = get_object_taxonomies( $post_type, $output ); // Remove adqs_listing_types taxonomy if ( $output === 'names' ) { $taxonomies = array_diff( $taxonomies, [ 'adqs_listing_types' ] ); } else { $taxonomies = array_filter( $taxonomies, function ( $taxonomy ) { return is_object( $taxonomy ) ? $taxonomy->name !== 'adqs_listing_types' : true; } ); } return array_values( $taxonomies ); } $directory_post_types = adqs_get_directory_post_types(); $all_taxonomies = []; foreach ( $directory_post_types as $directory_post_type ) { $taxonomies = get_object_taxonomies( $directory_post_type, $output ); if ( is_array( $taxonomies ) ) { $all_taxonomies = array_merge( $all_taxonomies, $taxonomies ); } } $all_taxonomies = array_unique( $all_taxonomies, SORT_REGULAR ); // Remove adqs_listing_types taxonomy from results. if ( $output === 'names' ) { $all_taxonomies = array_diff( $all_taxonomies, [ 'adqs_listing_types' ] ); } else { $all_taxonomies = array_filter( $all_taxonomies, function ( $taxonomy ) { return is_object( $taxonomy ) ? $taxonomy->name !== 'adqs_listing_types' : true; } ); } return array_values( $all_taxonomies ); // Re-index array } /** * Get dynamic post type slug for a given term. * * @deprecated Use adqs_get_post_type_by_directory() instead. * * @return string|false The post type slug or false if not found. */ function adqs_get_dynamic_post_type_slug( $directory_id ) { return adqs_get_post_type_by_directory( $directory_id ); } /** * Get directory by post type. * * @param string $post_type * * @return array|bool|WP_Term */ function adqs_get_directory_by_post_type( $post_type ) { if ( empty( $post_type ) || strpos( $post_type, 'adqs_' ) !== 0 ) { return false; } $post_type_object = get_post_type_object( $post_type ); if ( ! $post_type_object ) { return false; } $directory_id = $post_type_object->rewrite['slug']; if ( empty( $directory_id ) ) { return false; } return get_term_by( 'slug', $directory_id, 'adqs_listing_types' ); } /** * Get taxonomy key for a given post type. * * Since taxonomies are now shared across all post types, this returns static taxonomy names. * * @param string $post_type Deprecated/unused now (kept for backwards compatibility). * @param string $taxonomy_key * * @return string */ function adqs_get_directory_taxonomy_slug( $post_type, $taxonomy_key = 'category' ) { // Map the old taxonomy keys to the new ones. $taxonomy_key_mapping = [ 'categories' => 'category', 'locations' => 'location', 'tags' => 'tag', ]; if ( array_key_exists( $taxonomy_key, $taxonomy_key_mapping ) ) { $taxonomy_key = $taxonomy_key_mapping[ $taxonomy_key ]; } // Return static taxonomy names $static_taxonomies = [ 'category' => 'adqs_category', 'location' => 'adqs_location', 'tag' => 'adqs_tags', ]; return $static_taxonomies[ $taxonomy_key ] ?? ''; } /** * Get current post type inside the loop or single view of listing or term. * * @return string */ function adqs_get_current_post_type() { // First try to get from current query $post_type = get_post_type(); // If still empty, try to get from global post if ( empty( $post_type ) && ! empty( $GLOBALS['post'] ) ) { $post_type = $GLOBALS['post']->post_type; } // If still empty, try to get from query vars if ( empty( $post_type ) && ! empty( $GLOBALS['wp_query']->query_vars['post_type'] ) ) { $post_type = $GLOBALS['wp_query']->query_vars['post_type']; } // If still empty, check if we're on a taxonomy archive if ( empty( $post_type ) && is_tax() ) { $queried_object = get_queried_object(); if ( $queried_object && isset( $queried_object->taxonomy ) ) { // Try to find which post type this taxonomy belongs to $taxonomy_obj = get_taxonomy( $queried_object->taxonomy ); if ( $taxonomy_obj && ! empty( $taxonomy_obj->object_type ) ) { $post_type = $taxonomy_obj->object_type[0]; } } } return $post_type; } /** * Get the correct taxonomy for a given post type and taxonomy type. * * Since taxonomies are now shared across all post types, this returns static taxonomy names. * * @param string $post_type The post type (deprecated/unused now, kept for backwards compatibility). * @param string $taxonomy_key The taxonomy type (category, location, tag) * @return string The taxonomy slug */ function adqs_get_taxonomy_for_post_type( $post_type = '', $taxonomy_key = 'category' ) { // Map taxonomy keys to static taxonomy slugs $taxonomy_mapping = [ 'category' => 'adqs_category', 'categories' => 'adqs_category', 'location' => 'adqs_location', 'locations' => 'adqs_location', 'tag' => 'adqs_tags', 'tags' => 'adqs_tags', ]; // Normalize the key $taxonomy_key = strtolower( $taxonomy_key ); return $taxonomy_mapping[ $taxonomy_key ] ?? ''; } /** * Get a directory post type. * * @param int|string|object $directory Directory term ID, slug, or object. * @return string */ function adqs_get_post_type_by_directory( $directory ) { $directory = adqs_maybe_get_directory( $directory ); if ( ! $directory ) { return ''; } return (string) get_term_meta( $directory->term_id, 'adqs_directory_post_type', true ); } /** * Get post type from directory type term ID or slug. * * @deprecated Use adqs_get_post_type_by_directory() instead. * * @param string|int|WP_Term $directory Directory term ID, slug or object. * @return string */ function adqs_get_post_type_from_directory_type( $directory ) { return adqs_get_post_type_by_directory( $directory ); } /** * Check post_type if it is a directory post type. * * @param string $post_type * @return bool */ function adqs_is_directory_post_type( $post_type ) { if ( strpos( $post_type, 'adqs_' ) !== 0 ) { return false; } return in_array( $post_type, adqs_get_directory_post_types(), true ); } /** * Check taxonomy if it is a directory taxonomy. * * @param string $taxonomy * @return bool */ function adqs_is_directory_taxonomy( $taxonomy ) { return in_array( $taxonomy, adqs_get_directory_taxonomies(), true ); } /** * Create or update a directory * * @param array $args { * Directory arguments * * @type int $directory_id Optional. Directory ID for updates (0 for new directory) * @type string $singular_name Required. Directory singular name * @type string $plural_name Required. Directory plural name * @type string $slug Required. Directory slug * } * @return int|WP_Error Directory term ID on success, WP_Error on failure */ function adqs_upsert_directory( $args = [] ) { $defaults = [ 'directory_id' => 0, 'singular_name' => '', 'plural_name' => '', 'slug' => '', ]; $args = wp_parse_args( $args, $defaults ); // Extract and sanitize arguments $directory_id = absint( $args['directory_id'] ); $singular_name = sanitize_text_field( $args['singular_name'] ); $plural_name = sanitize_text_field( $args['plural_name'] ); $slug = sanitize_title( $args['slug'] ); // Validate directory exists if updating if ( ! empty( $directory_id ) && ! term_exists( $directory_id, 'adqs_listing_types' ) ) { return new WP_Error( 'invalid_directory', __( 'Invalid directory.', 'adirectory' ) ); } // Check required fields $missing_fields = []; if ( empty( $plural_name ) ) { $missing_fields[] = __( 'Plural Name', 'adirectory' ); } if ( empty( $singular_name ) ) { $missing_fields[] = __( 'Singular Name', 'adirectory' ); } if ( empty( $slug ) ) { $missing_fields[] = __( 'Slug', 'adirectory' ); } if ( ! empty( $missing_fields ) ) { $error_message = sprintf( /* translators: %s required fields label */ esc_html__( '%s fields are required.', 'adirectory' ), implode( ', ', $missing_fields ) ); return new WP_Error( 'missing_fields', $error_message ); } // Check for duplicates $directories = adqs_get_directories(); if ( ! is_wp_error( $directories ) ) { foreach ( $directories as $directory ) { // Skip validation for current directory being edited if ( $directory_id && $directory->term_id === $directory_id ) { continue; } // Check plural name if ( $plural_name === get_term_meta( $directory->term_id, 'adqs_directory_plural_name', true ) ) { $error_message = sprintf( /* translators: %s: plural name */ __( 'A directory with plural name "%s" already exists. Please choose a different name.', 'adirectory' ), $plural_name ); return new WP_Error( 'duplicate_plural_name', $error_message ); } // Check singular name if ( $directory->name === $singular_name ) { $error_message = sprintf( /* translators: %s: singular name */ __( 'A directory with singular name "%s" already exists. Please choose a different name.', 'adirectory' ), $singular_name ); return new WP_Error( 'duplicate_singular_name', $error_message ); } // Check slug if ( $directory->slug === $slug ) { $error_message = sprintf( /* translators: %s: slug */ __( 'A directory with slug "%s" already exists. Please choose a different slug.', 'adirectory' ), $slug ); return new WP_Error( 'duplicate_slug', $error_message ); } // Check post type $post_type = get_term_meta( $directory->term_id, 'adqs_directory_post_type', true ); if ( $post_type === 'adqs_' . $slug ) { $error_message = sprintf( /* translators: %s: post type */ __( 'A directory with post type "adqs_%s" already exists. Please choose a different slug.', 'adirectory' ), $slug ); return new WP_Error( 'duplicate_post_type', $error_message ); } } } // Create or update directory if ( empty( $directory_id ) ) { // Create new directory $directory = wp_insert_term( $singular_name, 'adqs_listing_types', [ 'slug' => $slug ] ); if ( is_wp_error( $directory ) ) { return $directory; } $directory_id = $directory['term_id']; update_term_meta( $directory_id, 'adqs_directory_post_type', adqs_create_post_type_key( $slug ) ); } else { // Update existing directory $directory = wp_update_term( $directory_id, 'adqs_listing_types', [ 'name' => $singular_name, 'slug' => $slug, ] ); if ( is_wp_error( $directory ) ) { return $directory; } } // Update directory meta update_term_meta( $directory_id, 'adqs_directory_plural_name', $plural_name ); /** * Fires after a directory is created or updated * * @param int $directory_id Directory term ID * @param array $args Directory arguments used * @param bool $is_new Whether this is a new directory */ do_action( 'adqs_directory_upserted', $directory_id, $args, empty( $args['directory_id'] ) ); return $directory_id; } /** * Create directory post type key from directory name. * * @param string $slug_or_singular_name Directory singular name or slug. * @return string */ function adqs_create_post_type_key( $slug_or_singular_name ) { $post_type = 'adqs_' . sanitize_title( $slug_or_singular_name ); return substr( $post_type, 0, 20 ); } /** * Schedule rewrite rules flush to happen on next admin page load or frontend init * This prevents performance issues by not flushing on every page load */ function adqs_schedule_rewrite_flush(): void { update_option( 'adqs_flush_rewrite_rules', true, false ); } /** * Check if rewrite rules need to be flushed and flush them if needed * Should be called during init hook */ function adqs_maybe_flush_rewrite_rules() { if ( get_option( 'adqs_flush_rewrite_rules' ) ) { flush_rewrite_rules(); delete_option( 'adqs_flush_rewrite_rules' ); /** * Fires after rewrite rules have been flushed */ do_action( 'adqs_rewrite_rules_flushed' ); } } /** * Force flush rewrite rules immediately * Use this only when absolutely necessary (e.g., during plugin activation) */ function adqs_flush_rewrite_rules() { flush_rewrite_rules(); delete_option( 'adqs_flush_rewrite_rules' ); // Clear any scheduled flush /** * Fires after rewrite rules have been flushed */ do_action( 'adqs_rewrite_rules_flushed' ); } /** * Get rewrite rule status * * @return bool True if rewrite rules are scheduled to be flushed */ function adqs_is_rewrite_flush_scheduled() { return (bool) get_option( 'adqs_flush_rewrite_rules' ); } /** * Get directory id by post type. * * @deprecated Use adqs_get_directory_id_by_post_type() instead. * * @param string $post_type Post type slug. * @return int|false Directory id or 0 if not found. */ function adqs_get_term_id_by_post_type_slug( $post_type ) { return adqs_get_directory_id_by_post_type( $post_type ); } /** * Get directory id by post type. * * @param string $post_type Post type slug. * @return int Directory id or 0 if not found. */ function adqs_get_directory_id_by_post_type( $post_type ) { $directory = adqs_get_directory_by_post_type( $post_type ); if ( ! $directory ) { return 0; } return $directory->term_id; } function adqs_get_directories_available() { $directories = adqs_get_directories(); if ( empty( $directories ) ) { return []; } $directories = array_map( static function ( $directory ) { return [ 'id' => $directory->term_id, 'name' => $directory->name, ]; }, $directories ); return $directories; } /** * Update term directory assignments. * * @param int $term_id Term ID. * @param array $directory_ids Array of directory IDs. * @param bool $append Whether to append to existing directories. * @return void */ function adqs_update_term_directories( $term_id, array $directory_ids = [], $append = false ) { if ( empty( $directory_ids ) ) { return; } $directory_ids = wp_parse_id_list( $directory_ids ); $directory_ids = array_filter( $directory_ids ); if ( empty( $directory_ids ) ) { return; } if ( $append ) { $old_directory_ids = adqs_get_term_directories( $term_id ); $directory_ids = array_merge( $old_directory_ids, $directory_ids ); $directory_ids = array_unique( $directory_ids ); } $directory_ids = array_values( $directory_ids ); update_term_meta( $term_id, 'adqs_directory_ids', $directory_ids ); foreach ( $directory_ids as $directory_id ) { update_term_meta( $term_id, 'adqs_directory_' . absint( $directory_id ), true ); } } /** * Update location directory assignments. * * @param int $location_id Location term ID. * @param array $directory_ids Array of directory IDs. * @param bool $append Whether to append to existing directories. * @return void */ function adqs_update_location_directories( $location_id, array $directory_ids = [], $append = false ) { adqs_update_term_directories( $location_id, $directory_ids, $append ); } /** * Update category directory assignments. * * @param int $category_id Category term ID. * @param array $directory_ids Array of directory IDs. * @param bool $append Whether to append to existing directories. * @return void */ function adqs_update_category_directories( $category_id, array $directory_ids = [], $append = false ) { adqs_update_term_directories( $category_id, $directory_ids, $append ); } /** * Delete all directory assignments for a term. * * @param int $term_id Term ID. * @return void */ function adqs_delete_term_directories( $term_id ) { $directory_ids = adqs_get_term_directories( $term_id ); delete_term_meta( $term_id, 'adqs_directory_ids' ); if ( empty( $directory_ids ) ) { return; } global $wpdb; $meta_keys = array_map( function ( $id ) { return 'adqs_directory_' . $id; }, $directory_ids ); $placeholders = implode( ', ', array_fill( 0, count( $meta_keys ), '%s' ) ); $format = "DELETE FROM {$wpdb->termmeta} WHERE term_id = %d AND meta_key IN ($placeholders)"; $args = array_merge( [ $term_id ], $meta_keys ); $sql = $wpdb->prepare( $format, ...$args ); $wpdb->query( $sql ); } /** * Get directory IDs assigned to a term. * * @param int $term_id Term ID. * @return int[] */ function adqs_get_term_directories( $term_id ) { $directories = (array) get_term_meta( $term_id, 'adqs_directory_ids', true ); if ( empty( $directories ) ) { return []; } $directory_ids = wp_parse_id_list( $directories ); $directory_ids = array_filter( $directory_ids ); // Remove 0 ids return $directory_ids; } /** * Get directory IDs assigned to a location. * * @param int $location_id Location term ID. * @return int[] */ function adqs_get_location_directories( $location_id ) { return adqs_get_term_directories( $location_id ); } /** * Get directory IDs assigned to a category. * * @param int $category_id Category term ID. * @return int[] */ function adqs_get_category_directories( $category_id ) { return adqs_get_term_directories( $category_id ); } /** * Get directory names assigned to a term. * * @param int $term_id Term ID. * @return string */ function adqs_get_term_directory_names( $term_id ) { $term_directories = adqs_get_term_directories( $term_id ); $directories = adqs_get_directories( [ 'fields' => 'id=>name', ] ); $directories = array_map( static function ( $directory_id ) use ( $directories ) { return $directories[ $directory_id ] ?? null; }, $term_directories ); $directories = array_filter( $directories ); return ! empty( $directories ) ? implode( ', ', $directories ) : ''; } /** * Get current directory ID from request. * * @return int */ function adqs_get_current_directory() { $directory = null; if ( ! empty( $_REQUEST['directory_type'] ) ) { $directory = sanitize_text_field( wp_unslash( $_REQUEST['directory_type'] ) ); } elseif ( ! empty( $_REQUEST['adqs_listing_type'] ) ) { $directory = sanitize_text_field( wp_unslash( $_REQUEST['adqs_listing_type'] ) ); } elseif ( ! empty( $_REQUEST['form_data'] ) ) { $form_data = wp_unslash( $_REQUEST['form_data'] ); parse_str( $form_data, $datas ); $directory = sanitize_text_field( $datas['directory_type'] ?? '' ); } elseif ( isset( $_REQUEST['post_type'] ) ) { $directory = adqs_get_directory_id_by_post_type( sanitize_text_field( $_REQUEST['post_type'] ) ); } elseif ( get_post() ) { $post = get_post(); $directory = adqs_get_directory_id_by_post_type( $post->post_type ); } if ( ! $directory && wp_doing_ajax() ) { $referer = esc_url_raw( $_SERVER['HTTP_REFERER'] ); if ( preg_match( '/post_type=([^&]+)/', $referer, $matches ) ) { $post_type = sanitize_text_field( $matches[1] ); } elseif ( preg_match( '/post\.php\?post=(\d+)/', $referer, $matches ) ) { $post_type = get_post_type( absint( $matches[1] ) ); } if ( adqs_is_directory_post_type( $post_type ) ) { $directory = adqs_get_directory_id_by_post_type( $post_type ); } } if ( empty( $directory ) ) { return 0; } $directory = adqs_maybe_get_directory( $directory ); if ( ! $directory ) { return 0; } return $directory->term_id; }