AnsPress_Tag()

Description #

Tags addon for AnsPress

Source #

File: addons/free/tag.php

class AnsPress_Tag {

	/**
	 * Initialize the class
	 */
	public static function init() {
		ap_register_page( 'tag', __( 'Tag', 'anspress-question-answer' ), [ __CLASS__, 'tag_page' ], false );
		ap_register_page( 'tags', __( 'Tags', 'anspress-question-answer' ), [ __CLASS__, 'tags_page' ] );

		anspress()->add_action( 'ap_form_addon-free_tag', __CLASS__, 'option_fields' );
		anspress()->add_action( 'widgets_init', __CLASS__, 'widget_positions' );
		anspress()->add_action( 'init', __CLASS__, 'register_question_tag', 1 );
		anspress()->add_action( 'ap_admin_menu', __CLASS__, 'admin_tags_menu' );
		anspress()->add_action( 'ap_display_question_metas', __CLASS__, 'ap_display_question_metas', 10, 2 );
		anspress()->add_action( 'ap_question_info', __CLASS__, 'ap_question_info' );
		anspress()->add_action( 'ap_assets_js', __CLASS__, 'ap_assets_js' );
		anspress()->add_action( 'ap_enqueue', __CLASS__, 'ap_localize_scripts' );
		anspress()->add_filter( 'term_link', __CLASS__, 'term_link_filter', 10, 3 );
		anspress()->add_action( 'ap_question_form_fields', __CLASS__, 'ap_question_form_fields' );
		anspress()->add_action( 'ap_processed_new_question', __CLASS__, 'after_new_question', 0, 2 );
		anspress()->add_action( 'ap_processed_update_question', __CLASS__, 'after_new_question', 0, 2 );
		anspress()->add_filter( 'ap_page_title', __CLASS__, 'page_title' );
		anspress()->add_filter( 'ap_breadcrumbs', __CLASS__, 'ap_breadcrumbs' );
		anspress()->add_action( 'wp_ajax_ap_tags_suggestion', __CLASS__, 'ap_tags_suggestion' );
		anspress()->add_action( 'wp_ajax_nopriv_ap_tags_suggestion', __CLASS__, 'ap_tags_suggestion' );
		anspress()->add_action( 'ap_rewrites', __CLASS__, 'rewrite_rules', 10, 3 );
		anspress()->add_filter( 'ap_main_questions_args', __CLASS__, 'ap_main_questions_args' );
		anspress()->add_filter( 'ap_current_page', __CLASS__, 'ap_current_page' );
		anspress()->add_action( 'posts_pre_query', __CLASS__, 'modify_query_archive', 9999, 2 );

		// List filtering.
		anspress()->add_filter( 'ap_list_filters', __CLASS__, 'ap_list_filters' );
		anspress()->add_action( 'ap_ajax_load_filter_qtag', __CLASS__, 'load_filter_tag' );
		anspress()->add_action( 'ap_ajax_load_filter_tags_order', __CLASS__, 'load_filter_tags_order' );
		anspress()->add_filter( 'ap_list_filter_active_qtag', __CLASS__, 'filter_active_tag', 10, 2 );
		anspress()->add_filter( 'ap_list_filter_active_tags_order', __CLASS__, 'filter_active_tags_order', 10, 2 );
	}

	/**
	 * Tag page layout.
	 *
	 * @since 4.1.0 Use `get_queried_object()` to get current term.
	 */
	public static function tag_page() {
		global $question_tag;
		$question_tag = get_queried_object();

		$question_args = array(
			'paged'      => max( 1, get_query_var( 'ap_paged' ) ),
			'tax_query'  => array(
				array(
					'taxonomy' => 'question_tag',
					'field'    => 'id',
					'terms'    => array( $question_tag->term_id ),
				),
			),
		);

		$question_args = apply_filters( 'ap_tag_question_query_args', $question_args );

		if ( $question_tag ) {
			anspress()->questions = ap_get_questions( $question_args );
			include( ap_get_theme_location( 'addons/tag/tag.php' ) );
		}

	}

	/**
	 * Tags page layout
	 */
	public static function tags_page() {

		global $question_tags, $ap_max_num_pages, $ap_per_page, $tags_rows_found;
		$paged 				= max( 1, get_query_var( 'paged' ) );
		$per_page     = (int) ap_opt( 'tags_per_page' );
		$per_page     = 0 === $per_page ? 1 : $per_page;
		$offset       = $per_page * ( $paged - 1);

		$tag_args = array(
			'taxonomy' => 'question_tag',
			'ap_tags_query' => true,
			'parent'        => 0,
			'number'        => $per_page,
			'offset'        => $offset,
			'hide_empty'    => false,
			'order'         => 'DESC',
		);

		$ap_sort = ap_isset_post_value( 'tags_order', 'count' );

		if ( 'new' === $ap_sort ) {
			$tag_args['orderby'] = 'id';
			$tag_args['order']   = 'DESC';
		} elseif ( 'name' === $ap_sort ) {
			$tag_args['orderby']    = 'name';
			$tag_args['order']      = 'ASC';
		} else {
			$tag_args['orderby'] = 'count';
		}

		if ( ap_isset_post_value( 'ap_s' ) ) {
			$tag_args['search'] = ap_sanitize_unslash( 'ap_s', 'r' );
		}

		/**
		 * Filter applied before getting tags.
		 *
		 * @var array
		 */
		$tag_args = apply_filters( 'ap_tags_shortcode_args', $tag_args );

		$query 		          = new WP_Term_Query( $tag_args );

		// Count terms.
		$tag_args['fields'] = 'count';
		$found_query        = new WP_Term_Query( $tag_args );
		$tags_rows_found    = $found_query->get_terms();
		$ap_max_num_pages   = ceil( $tags_rows_found / $per_page );
		$question_tags      = $query->get_terms();

		include ap_get_theme_location( 'addons/tag/tags.php' );
	}

	/**
	 * Register widget position.
	 */
	public static function widget_positions() {
		register_sidebar( array(
			'name'          => __( '(AnsPress) Tags', 'anspress-question-answer' ),
			'id'            => 'ap-tags',
			'before_widget' => '<div id="%1$s" class="ap-widget-pos %2$s">',
			'after_widget'  => '</div>',
			'description'   => __( 'Widgets in this area will be shown in anspress tags page.', 'anspress-question-answer' ),
			'before_title'  => '<h3 class="ap-widget-title">',
			'after_title'   => '</h3>',
		) );
	}

	/**
	 * Register tag taxonomy for question cpt.
	 *
	 * @return void
	 * @since 2.0
	 */
	public static function register_question_tag() {
		ap_add_default_options([
			'max_tags'        => 5,
			'min_tags'        => 1,
			'tags_per_page'   => 20,
			'tag_page_slug'   => 'tag',
		]);

		$tag_labels = array(
			'name' 				        => __( 'Question Tags', 'anspress-question-answer' ),
			'singular_name' 	    => _x( 'Tag', 'anspress-question-answer' ),
			'all_items' 		      => __( 'All Tags', 'anspress-question-answer' ),
			'add_new_item' 		    => _x( 'Add New Tag', 'anspress-question-answer' ),
			'edit_item' 		      => __( 'Edit Tag', 'anspress-question-answer' ),
			'new_item' 			      => __( 'New Tag', 'anspress-question-answer' ),
			'view_item' 		      => __( 'View Tag', 'anspress-question-answer' ),
			'search_items' 		    => __( 'Search Tag', 'anspress-question-answer' ),
			'not_found' 		      => __( 'Nothing Found', 'anspress-question-answer' ),
			'not_found_in_trash'  => __( 'Nothing found in Trash', 'anspress-question-answer' ),
			'parent_item_colon'   => '',
		);

		/**
		 * FILTER: ap_question_tag_labels
		 * Filter ic called before registering question_tag taxonomy
		 */
		$tag_labels = apply_filters( 'ap_question_tag_labels',  $tag_labels );
		$tag_args = array(
			'hierarchical' => true,
			'labels'       => $tag_labels,
			'rewrite'      => false,
		);

		/**
		 * FILTER: ap_question_tag_args
		 * Filter ic called before registering question_tag taxonomy
		 */
		$tag_args = apply_filters( 'ap_question_tag_args',  $tag_args );

		/**
		 * Now let WordPress know about our taxonomy
		 */
		register_taxonomy( 'question_tag', array( 'question' ), $tag_args );
	}

	/**
	 * Add tags menu in wp-admin.
	 */
	public static function admin_tags_menu() {
		add_submenu_page( 'anspress', __( 'Question Tags', 'anspress-question-answer' ), __( 'Tags', 'anspress-question-answer' ), 'manage_options', 'edit-tags.php?taxonomy=question_tag' );
	}

	/**
	 * Register option fields.
	 */
	public static function option_fields() {
		$opt = ap_opt();

		$form = array(
			'fields' => array(
				'tags_per_page' => array(
					'label'       => __( 'Tags to show', 'anspress-question-answer' ),
					'description' => __( 'Numbers of tags to show in tags page.', 'anspress-question-answer' ),
					'subtype'     => 'number',
					'value'       => $opt['tags_per_page'],
				),
				'max_tags' => array(
					'label'             => __( 'Maximum tags', 'anspress-question-answer' ),
					'description'       => __( 'Maximum numbers of tags that user can add when asking.', 'anspress-question-answer' ),
					'subtype'     => 'number',
					'value'       => $opt['max_tags'],
				),
				'min_tags' => array(
					'label'             => __( 'Minimum tags', 'anspress-question-answer' ),
					'description'       => __( 'minimum numbers of tags that user must add when asking.', 'anspress-question-answer' ),
					'subtype'     => 'number',
					'value'       => $opt['min_tags'],
				),
				'tag_page_slug' => array(
					'label' 	=> __( 'Tag page slug', 'anspress-question-answer' ),
					'desc' 		=> __( 'Slug for tag page', 'anspress-question-answer' ),
					'value'   => $opt['tag_page_slug'],
				),
			),
		);

		return $form;
	}


	/**
	 * Append meta display.
	 *
	 * @param  array $metas Display metas.
	 * @param  array $question_id Post ID.
	 * @return array
	 * @since 2.0
	 */
	public static function ap_display_question_metas( $metas, $question_id ) {
		if ( ap_post_have_terms( $question_id, 'question_tag' ) ) {
			$metas['tags'] = ap_question_tags_html( array( 'label' => '<i class="apicon-tag"></i>', 'show' => 1 ) ); }

		return $metas;
	}

	/**
	 * Hook tags after post.
	 *
	 * @param   object $post Post object.
	 * @return  string
	 * @since   1.0
	 */
	public static function ap_question_info( $post ) {

		if ( ap_question_have_tags() ) {
			echo '<div class="widget"><span class="ap-widget-title">' . esc_attr__( 'Tags', 'anspress-question-answer' ) . '</span>';
			echo '<div class="ap-post-tags clearfix">' . ap_question_tags_html( [ 'list' => true, 'label' => '' ] ) . '</div></div>'; // WPCS: xss okay.
		}
	}

	/**
	 * Enqueue scripts.
	 *
	 * @param array $js Javacript array.
	 * @return array
	 */
	public static function ap_assets_js( $js ) {
		$js['tags'] = [ 'dep' => [ 'anspress-main' ], 'footer' => true ];

		return $js;
	}

	/**
	 * Add translated strings to the javascript files
	 */
	public static function ap_localize_scripts() {
		$l10n_data = array(
			'deleteTag'            => __( 'Delete Tag', 'anspress-question-answer' ),
			'addTag'               => __( 'Add Tag', 'anspress-question-answer' ),
			'tagAdded'             => __( 'added to the tags list.', 'anspress-question-answer' ),
			'tagRemoved'           => __( 'removed from the tags list.', 'anspress-question-answer' ),
			'suggestionsAvailable' => __( 'Suggestions are available. Use the up and down arrow keys to read it.', 'anspress-question-answer' ),
		);

		wp_localize_script(
			'anspress-tags',
			'apTagsTranslation',
			$l10n_data
		);
	}

	/**
	 * Filter tag term link.
	 *
	 * @param  string $url      Default URL of taxonomy.
	 * @param  array  $term     Term array.
	 * @param  string $taxonomy Taxonomy type.
	 * @return string           New URL for term.
	 */
	public static function term_link_filter( $url, $term, $taxonomy ) {
		if ( 'question_tag' === $taxonomy ) {
			if ( get_option( 'permalink_structure' ) != '' ) {
				$opt = get_option( 'ap_tags_path', 'tags' );
				return home_url( $opt ) . '/' . $term->slug . '/';
			} else {
				return add_query_arg( [ 'ap_page' => 'tag', 'question_tag' => $term->slug ], home_url() );
			}
		}
		return $url;
	}

	/**
	 * Add tag field in question form.
	 *
	 * @param array $form AnsPress form arguments.
	 * @since 4.1.0
	 */
	public static function ap_question_form_fields( $form ) {
		$editing_id = ap_sanitize_unslash( 'id', 'r' );

		$form['fields']['tags'] = array(
			'label'     => __( 'Tags', 'anspress-question-answer' ),
			'desc' 		  => sprintf(
				// Translators: %1$d contain minimum tags required and %2$d contain maximum tags allowed.
				__( 'Tagging will helps others to easily find your question. Minimum %1$d and maximum %2$d tags.', 'anspress-question-answer' ),
				ap_opt( 'min_tags' ),
				ap_opt( 'max_tags' )
			),
			'type'      => 'tags',
			'array_max' => ap_opt( 'max_tags' ),
			'array_min' => ap_opt( 'min_tags' ),
			'js_options' => array(
				'create' => true,
			),
		);

		// Add value when editing post.
		if ( ! empty( $editing_id ) ) {
			$tags = get_the_terms( $editing_id, 'question_tag' );
			if ( $tags ) {
				$tags = wp_list_pluck( $tags, 'term_id' );
				$form['fields']['tags']['value'] = $tags;
			}
		}

		return $form;
	}

	/**
	 * Things to do after creating a question.
	 *
	 * @param  integer $post_id Post ID.
	 * @param  object  $post Post object.
	 * @since 1.0
	 */
	public static function after_new_question( $post_id, $post ) {
		$values = anspress()->get_form( 'question' )->get_values();
		if ( isset( $values['tags'] ) ) {
			wp_set_object_terms( $post_id, $values['tags']['value'], 'question_tag' );
		}
	}

	/**
	 * Tags page title.
	 *
	 * @param  string $title Title.
	 * @return string
	 */
	public static function page_title( $title ) {
		if ( is_question_tags() ) {
			$title = ap_opt( 'tags_page_title' );
		} elseif ( is_question_tag() ) {
			$tag_id = sanitize_title( get_query_var( 'q_tag' ) );
			$tag = get_term_by( 'slug', $tag_id, 'question_tag' ); // @codingStandardsIgnoreLine.
			$title = $tag->name;
		}

		return $title;
	}

	/**
	 * Hook into AnsPress breadcrums to show tags page.
	 *
	 * @param  array $navs Breadcrumbs navs.
	 * @return array
	 */
	public static function ap_breadcrumbs( $navs ) {

		if ( is_question_tag() ) {
			$tag_id = sanitize_title( get_query_var( 'q_tag' ) );
			$tag = get_term_by( 'slug', $tag_id, 'question_tag' ); // @codingStandardsIgnoreLine.
			$navs['page'] = array( 'title' => __( 'Tags', 'anspress-question-answer' ), 'link' => ap_get_link_to( 'tags' ), 'order' => 8 );

			if ( $tag ) {
				$navs['tag'] = array(
					'title' => $tag->name,
					'link'  => get_term_link( $tag, 'question_tag' ), // @codingStandardsIgnoreLine.
					'order' => 8,
				);
			}
		} elseif ( is_question_tags() ) {
			$navs['page'] = array( 'title' => __( 'Tags', 'anspress-question-answer' ), 'link' => ap_get_link_to( 'tags' ), 'order' => 8 );
		}

		return $navs;
	}

	/**
	 * Handle tags suggestion on question form
	 */
	public static function ap_tags_suggestion() {
		$keyword = ap_sanitize_unslash( 'q', 'r' );

		$tags = get_terms( 'question_tag', array(
			'orderby'    => 'count',
			'order'      => 'DESC',
			'hide_empty' => false,
			'search'     => $keyword,
			'number'     => 8,
		));

		if ( $tags ) {
			$items = array();
			foreach ( $tags as $k => $t ) {
				$items [ $k ] = $t->slug;
			}

			$result = array( 'status' => true, 'items' => $items );
			wp_send_json( $result );
		}

		wp_send_json( array( 'status' => false ) );
	}

	/**
	 * Add category pages rewrite rule.
	 *
	 * @param  array $rules AnsPress rules.
	 * @return array
	 */
	public static function rewrite_rules( $rules, $slug, $base_page_id ) {
		$base_slug = get_page_uri( ap_opt( 'tags_page' ) );
		update_option( 'ap_tags_path', $base_slug, true );

		$cat_rules = array(
			$base_slug . '/([^/]+)/page/?([0-9]{1,})/?$' => 'index.php?question_tag=$matches[#]&ap_paged=$matches[#]&ap_page=tag',
			$base_slug . '/([^/]+)/?$' => 'index.php?question_tag=$matches[#]&ap_page=tag',
		);

		return $cat_rules + $rules;
	}

	/**
	 * Filter main questions query args. Modify and add tags args.
	 *
	 * @param  array $args Questions args.
	 * @return array
	 */
	public static function ap_main_questions_args( $args ) {
		global $wp;
		$query = $wp->query_vars;

		$current_filter = ap_get_current_list_filters( 'qtag' );
		$tags_operator = ! empty( $wp->query_vars['ap_tags_operator'] ) ? $wp->query_vars['ap_tags_operator'] : 'IN';

		if ( isset( $query['ap_tags'] ) && is_array( $query['ap_tags'] ) ) {
			$args['tax_query'][] = array(
				'taxonomy' => 'question_tag',
				'field'    => 'slug',
				'terms'    => $query['ap_tags'],
				'operator' => $tags_operator,
			);
		} elseif ( ! empty( $current_filter ) ) {
			$args['tax_query'][] = array(
				'taxonomy' => 'question_tag',
				'field'    => 'term_id',
				'terms'    => $current_filter,
			);
		}

		return $args;
	}

	/**
	 * Add tags sorting in list filters
	 *
	 * @return array
	 */
	public static function ap_list_filters( $filters ) {
		global $wp;

		if ( ! isset( $wp->query_vars['ap_tags'] ) ) {
			$filters['qtag'] = array(
				'title'    => __( 'Tag', 'anspress-question-answer' ),
				'search'   => true,
				'multiple' => true,
			);
		}

		if ( 'tags' === ap_current_page() ) {
			return array( 'tags_order' => array(
				'title'    => __( 'Order', 'anspress-question-answer' ),
			) );
		}

		return $filters;
	}

	/**
	 * Ajax callback for loading order by filter.
	 *
	 * @since 4.0.0
	 */
	public static function load_filter_tag() {
		$filter = ap_sanitize_unslash( 'filter', 'r' );
		check_ajax_referer( 'filter_' . $filter, '__nonce' );
		$search = ap_sanitize_unslash( 'search', 'r', false );

		ap_ajax_json( array(
			'success'  => true,
			'items'    => ap_get_tag_filter( $search ),
			'multiple' => true,
			'nonce'    => wp_create_nonce( 'filter_' . $filter ),
		));
	}

	/**
	 * Ajax callback for loading order by filter for tags.
	 *
	 * @since 4.0.0
	 */
	public static function load_filter_tags_order() {
		$filter = ap_sanitize_unslash( 'filter', 'r' );
		check_ajax_referer( 'filter_' . $filter, '__nonce' );

		ap_ajax_json( array(
			'success'  => true,
			'items'    => array(
				[ 'key' => 'tags_order', 'value' => 'popular', 'label' => __( 'Popular', 'anspress-question-answer' ) ],
				[ 'key' => 'tags_order', 'value' => 'new', 'label' => __( 'New', 'anspress-question-answer' ) ],
				[ 'key' => 'tags_order', 'value' => 'name', 'label' => __( 'Name', 'anspress-question-answer' ) ],
			),
			'nonce'    => wp_create_nonce( 'filter_' . $filter ),
		));
	}

	/**
	 * Output active tag in filter
	 *
	 * @since 4.0.0
	 */
	public static function filter_active_tag( $active, $filter ) {
		$current_filters = ap_get_current_list_filters( 'qtag' );

		if ( ! empty( $current_filters ) ) {
			$args = array(
				'hierarchical'  => true,
				'hide_if_empty' => true,
				'number'        => 2,
				'include'       => $current_filters,
			);

			$terms = get_terms( 'question_tag', $args );

			if ( $terms ) {
				$active_terms = [];
				foreach ( (array) $terms as $t ) {
					$active_terms[] = $t->name;
				}

				$count = count( $current_filters );
				$more_label = sprintf( __( ', %d+', 'anspress-question-answer' ), $count - 2 );

				return ': <span class="ap-filter-active">' . implode( ', ', $active_terms ) . ( $count > 2 ? $more_label : ''  ) . '</span>';
			}
		}
	}

	/**
	 * Output active tags_order in filter
	 *
	 * @since 4.1.0
	 */
	public static function filter_active_tags_order( $active, $filter ) {
		$tags_order = ap_get_current_list_filters( 'tags_order' );
		$tags_order = ! empty ( $tags_order ) ? $tags_order : 'popular';

		$orders = array(
			'popular' => __( 'Popular', 'anspress-question-answer' ),
			'new'     => __( 'New', 'anspress-question-answer' ),
			'name'    => __( 'Name', 'anspress-question-answer' ),
		);

		$active = isset( $orders[ $tags_order ] ) ? $orders[ $tags_order ] : '';

		return ': <span class="ap-filter-active">' . $active . '</span>';
	}

	/**
	 * Modify current page to show tag archive.
	 *
	 * @param string $query_var Current page.
	 * @return string
	 * @since 4.1.0
	 */
	public static function ap_current_page( $query_var ) {
		if ( 'tags' === $query_var && 'tag' === get_query_var( 'ap_page' ) ) {
			return 'tag';
		}

		return $query_var;
	}

	/**
	 * Modify main query to show tag archive.
	 *
	 * @param array|null $posts Array of objects.
	 * @param object     $query Wp_Query object.
	 *
	 * @return array|null
	 * @since 4.1.0
	 */
	public static function modify_query_archive( $posts, $query ) {
		if ( $query->is_main_query() &&
			$query->is_tax( 'question_tag' ) &&
			'tag' === get_query_var( 'ap_page' ) ) {

			$query->found_posts = 1;
			$query->max_num_pages = 1;
			$page = get_page( ap_opt( 'tags_page' ) );
			$page->post_title = get_queried_object()->name;
			$posts = [ $page ];
		}

		return $posts;
	}
}

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Add your comment