<?php
/**
 * This file contains the class Daim_Ajax, used to include ajax actions.
 *
 * @package interlinks-manager
 */

/**
 * This class should be used to include ajax actions.
 */
class Daim_Ajax {

	/**
	 * The instance of the Daim_Ajax class.
	 *
	 * @var Daim_Ajax
	 */
	protected static $instance = null;

	/**
	 * The instance of the Daim_Shared class.
	 *
	 * @var Daim_Shared
	 */
	private $shared = null;

	/**
	 * The constructor of the Daim_Ajax class.
	 */
	private function __construct() {

		// Assign an instance of the plugin info.
		$this->shared = Daim_Shared::get_instance();

		// Ajax requests --------------------------------------------------------.

		// For logged-in and not-logged-in users --------------------------------.
		add_action( 'wp_ajax_track_internal_link', array( $this, 'track_internal_link' ) );
		add_action( 'wp_ajax_nopriv_track_internal_link', array( $this, 'track_internal_link' ) );

		// For logged-in users --------------------------------------------------.
		add_action( 'wp_ajax_generate_interlinks_suggestions', array( $this, 'generate_interlinks_suggestions' ) );
		add_action( 'wp_ajax_generate_interlinks_optimization', array( $this, 'generate_interlinks_optimization' ) );
		add_action( 'wp_ajax_daim_wizard_generate_ail', array( $this, 'daim_wizard_generate_ail' ) );
		add_action( 'wp_ajax_daim_get_taxonomies', array( $this, 'daim_get_taxonomies' ) );
		add_action( 'wp_ajax_daim_get_terms', array( $this, 'daim_get_terms' ) );
	}

	/**
	 * Return an istance of this class.
	 */
	public static function get_instance() {

		if ( null === self::$instance ) {
			self::$instance = new self();
		}

		return self::$instance;
	}

	/**
	 * Ajax handler used to track internal links in the front-end.
	 */
	public function track_internal_link() {

		// Check the referer.
		if ( ! check_ajax_referer( 'daim', 'security', false ) ) {
			echo 'Invalid AJAX Request';
			die();}

		// Sanitization.
		$link_type      = isset( $_POST['link_type'] ) && sanitize_key( $_POST['link_type'] ) === 'ail' ? $link_type = 0 : $link_type = 1;
		$source_post_id = isset( $_POST['source_post_id'] ) ? intval( $_POST['source_post_id'], 10 ) : null;
		$target_url     = isset( $_POST['target_url'] ) ? mb_substr( esc_url_raw( wp_unslash( $_POST['target_url'] ) ), 0, 2038 ) : null;

		// Validation.
		if ( is_null( $source_post_id ) || is_null( $target_url ) ) {
			echo 'invalid-data';
			die();
		}

		// Get the current time.
		$date     = current_time( 'mysql' );
		$date_gmt = current_time( 'mysql', 1 );

		/**
		 * Remove all the filter associated with 'the_title' to get with the
		 * function get_the_title() the raw title saved in the posts table.
		 */
		remove_all_filters( 'the_title' );
		$post_title = get_the_title( $source_post_id );

		// Verify if the post with the link exists.
		if ( get_post_status( $source_post_id ) === false ) {
			echo 'The post doesn\'t exists.';
			die(); }

		// Save into the database.
		global $wpdb;

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery
		$query_result = $wpdb->query(
			$wpdb->prepare(
				"INSERT INTO {$wpdb->prefix}daim_hits SET 
            source_post_id = %d,
            post_title = %s,
            post_permalink = %s,
            post_edit_link = %s,
            target_url = %s,
            link_type = %s,
            date = %s,
            date_gmt = %s",
				$source_post_id,
				$post_title,
				get_the_permalink( $source_post_id ),
				get_edit_post_link( $source_post_id, 'url' ),
				$target_url,
				$link_type,
				$date,
				$date_gmt
			)
		);

		if ( false === $query_result ) {
			echo 'error';
		} else {
			echo 'success';
		}

		die();
	}

	/**
	 * Ajax handler used to generate a list of suggestions in the "Interlinks
	 * Suggestions" meta box.
	 */
	public function generate_interlinks_suggestions() {

		// Check the referer.
		if ( ! check_ajax_referer( 'daim', 'security', false ) ) {
			echo 'Invalid AJAX Request';
			die();}

		// Check the capability.
		if ( ! current_user_can( get_option( $this->shared->get( 'slug' ) . '_interlinks_suggestions_mb_required_capability' ) ) ) {
			echo 'Invalid Capability';
			die();}

		// Set the PHP "Max Execution Time" and "Memory Limit" based on the values defined in the options.
		$this->shared->set_met_and_ml();

		// Get the post id for which the suggestions should be generated.
		$post_id = isset( $_POST['post_id'] ) ? intval( $_POST['post_id'], 10 ) : null;

		// Get the options values.
		$option_title      = get_option( $this->shared->get( 'slug' ) . '_suggestions_titles' );// consider, ignore.
		$option_post_type  = get_option( $this->shared->get( 'slug' ) . '_suggestions_post_type' );// require, consider, ignore.
		$option_categories = get_option( $this->shared->get( 'slug' ) . '_suggestions_categories' );// require, consider, ignore.
		$option_tags       = get_option( $this->shared->get( 'slug' ) . '_suggestions_tags' );// require, consider, ignore.

		/**
		 * Create a query to get the posts that belong to the selected
		 * 'Pool Post Types'.
		 */
		$post_types_a          = maybe_unserialize( get_option( $this->shared->get( 'slug' ) . '_suggestions_pool_post_types' ) );
		$pool_post_types_query = '';
		if ( is_array( $post_types_a ) ) {
			foreach ( $post_types_a as $key => $value ) {

				if ( ! preg_match( '/[a-z0-9_-]+/', $value ) ) {
					continue;}

				$pool_post_types_query .= "post_type = '" . $value . "'";
				if ( count( $post_types_a ) - 1 !== $key ) {
					$pool_post_types_query .= ' or ';}
			}
		}
		if ( strlen( $pool_post_types_query ) > 0 ) {
			$pool_post_types_query = ' AND (' . $pool_post_types_query . ')';}

		/**
		 * Step1: $option_title.
		 *
		 * If $option_title is set to 'consider' compare each word that appears
		 * in the current post title with the ones that appears in every other
		 * available post and increase the score by 10 for each word.
		 *
		 * if $option_title is set to 'ignore' create an array with all the
		 * posts and 0 as the score.
		 *
		 * The array that saves the score is the $posts_ranking_a array.
		 */
		if ( 'consider' === $option_title ) {

			// get the current post title.
			$current_post_title = get_the_title( $post_id );

			/*
			 * Extract all the words from the current post title and save them
			 * in the $shared_words array.
			 */

			/*
			 * Save in $shared_words all the single words available in the title
			 * of the current post
			 */
			$shared_words = explode( ' ', $current_post_title );

			// Remove empty elements from the array.
			$shared_words = array_filter( $shared_words );

			/**
			 * Execute the query to get the posts that belong to the selected
			 * 'Pool Post Types'.
			 */
			global $wpdb;
			$limit_posts_analysis = intval( get_option( $this->shared->get( 'slug' ) . '_limit_posts_analysis' ), 10 );
			// phpcs:disable WordPress.DB.DirectDatabaseQuery,WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $pool_post_types_query is already prepared.
			$results = $wpdb->get_results(
				$wpdb->prepare( "SELECT ID, post_type, post_title FROM {$wpdb->prefix}posts WHERE post_status = 'publish' $pool_post_types_query ORDER BY post_date DESC LIMIT %d", $limit_posts_analysis ),
				ARRAY_A
			);
			// phpcs:enable

			/**
			* Compare each word that appears in the current post title with the
			* ones that appears in every other available post and increase the
			* score by 10 for each word
			 */
			foreach ( $results as $key => $single_result ) {

				$score = 0;

				// Assign 10 points for the word matches.
				foreach ( $shared_words as $key => $needle ) {
					if ( strpos( $single_result['post_title'], $needle ) !== false ) {
						$score = $score + 10;
					}
				}

				// Save post data in the $posts_ranking_a array.
				$posts_ranking_a[] = array(
					'id'        => $single_result['ID'],
					'post_type' => $single_result['post_type'],
					'score'     => $score,
				);

			}
		} else {

			// Create an array with all the posts and 0 as score ----------------.
			global $wpdb;
			$limit_posts_analysis = intval( get_option( $this->shared->get( 'slug' ) . '_limit_posts_analysis' ), 10 );

			// phpcs:disable WordPress.DB.DirectDatabaseQuery,WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $pool_post_types_query is already prepared.
			$results = $wpdb->get_results(
				$wpdb->prepare( "SELECT ID, post_type FROM {$wpdb->prefix}posts WHERE post_status = 'publish' $pool_post_types_query ORDER BY post_date DESC LIMIT %d", $limit_posts_analysis ),
				ARRAY_A
			);
			// phpcs:enable

			// Cycle through all the posts.
			foreach ( $results as $key => $single_result ) {

				// Save post data in the $posts_ranking_a array.
				$posts_ranking_a[] = array(
					'id'        => $single_result['ID'],
					'post_type' => $single_result['post_type'],
					'score'     => 0,
				);

			}
		}

		/*
		 * step2: $option_post_type
		 *
		 * If $option_post_type is set to 'require' remove from the array
		 * $posts_ranking_a all the posts that don't belong to this post type.
		 *
		 * If $option_post_type is set to 'consider' add 20 to all the posts
		 * that belong to this post type on the $posts_ranking_a array.
		 *
		 * If $option_post_type is set to 'ignore' do nothing.
		 *
		 */

		// Proceed with this step only if the $posts_ranking_a exists and it's not empty.
		if ( isset( $posts_ranking_a ) && ( count( $posts_ranking_a ) > 0 ) ) {

			// Get the post type of this post.
			$current_post_type = get_post_type( $post_id );

			switch ( $option_post_type ) {

				case 'require':
					foreach ( $posts_ranking_a as $pra_key => $pra_value ) {
						if ( $pra_value['post_type'] !== $current_post_type ) {
							unset( $posts_ranking_a[ $pra_key ] );
						}
					}

					break;

				case 'consider':
					foreach ( $posts_ranking_a as $pra_key => $pra_value ) {
						if ( $pra_value['post_type'] === $current_post_type ) {
							$posts_ranking_a[ $pra_key ]['score'] = $posts_ranking_a[ $pra_key ]['score'] + 20;
						}
					}

					break;

				case 'ignore':
					break;

			}
		}

		/*
		 * step3: $option_categories
		 *
		 * If $option_categories is set to 'require' remove from the
		 * $posts_ranking_a array all the posts that don't have any category
		 * that the current post have
		 *
		 * If the $option_categories is set to 'consider' add 20 to all the
		 * posts that have the category that the current post have ( add 20 for
		 * each category found )
		 *
		 * if $option_categories is set to 'ignore' do nothing
		 *
		 * Please note that this option is applied only to the posts that have
		 * the "category" taxonomy and that are associated with one or more
		 * categories
		 */

		// Proceed with this step only if the $posts_ranking_a exists and it's not empty.
		if ( isset( $posts_ranking_a ) && ( count( $posts_ranking_a ) > 0 ) ) {

			if ( in_array( 'category', get_object_taxonomies( get_post_type( $post_id ) ), true ) ) {

				// Get an array with a list of the id of the categories.
				$current_post_categories = wp_get_post_categories( $post_id );

				if ( is_array( $current_post_categories ) && count( $current_post_categories ) > 0 ) {

					switch ( $option_categories ) {

						case 'require':
							foreach ( $posts_ranking_a as $pra_key => $pra_value ) {
								$found                    = false;
								$iterated_post_categories = wp_get_post_categories( $pra_value['id'] );
								foreach ( $current_post_categories as $cpc_key => $cpc_value ) {
									if ( in_array( $cpc_value, $iterated_post_categories, true ) ) {
										$found = true;
									}
								}
								if ( ! $found ) {
									unset( $posts_ranking_a[ $pra_key ] );
								}
							}

							break;

						case 'consider':
							foreach ( $posts_ranking_a as $pra_key => $pra_value ) {
								$found                    = false;
								$iterated_post_categories = wp_get_post_categories( $pra_value['id'] );
								foreach ( $current_post_categories as $cpc_key => $cpc_value ) {
									if ( in_array( $cpc_value, $iterated_post_categories, true ) ) {
										$found = true;
									}
								}
								if ( $found ) {
									$posts_ranking_a[ $pra_key ]['score'] = $posts_ranking_a[ $pra_key ]['score'] + 20;
								}
							}

							break;

						case 'ignore':
							break;

					}
				}
			}
		}

		/*
		 * step4: $option_tags
		 *
		 * If $option_tags is set to 'require' remove from the $posts_ranking_a
		 * array all posts that don't have any tag that the current post have
		 *
		 * If the $option_tags is set to 'consider' add 20 to all the
		 * posts that have the tag that the current post have ( add 20 for
		 * each tag found )
		 *
		 * if $option_tags is set to 'ignore' do nothing
		 *
		 * Please note that this option is applied only to the posts that have
		 * the "post_tag" taxonomy and that are associated with one or more
		 * tags
		 */

		// Proceed with this step only if the $posts_ranking_a exists and it's not empty.
		if ( isset( $posts_ranking_a ) && ( count( $posts_ranking_a ) > 0 ) ) {

			if ( in_array( 'post_tag', get_object_taxonomies( get_post_type( $post_id ) ), true ) ) {

				// Get an array with a list of the id of the categories.
				$current_post_tags = wp_get_post_tags( $post_id );

				if ( is_array( $current_post_tags ) && count( $current_post_tags ) > 0 ) {

					switch ( $option_tags ) {

						case 'require':
							foreach ( $posts_ranking_a as $pra_key => $pra_value ) {
								$found              = false;
								$iterated_post_tags = wp_get_post_tags( $pra_value['id'] );
								foreach ( $current_post_tags as $cpt_key => $cpt_value ) {
									if ( in_array( $cpt_value, $iterated_post_tags, true ) ) {
										$found = true;
									}
								}
								if ( ! $found ) {
									unset( $posts_ranking_a[ $pra_key ] );
								}
							}

							break;

						case 'consider':
							foreach ( $posts_ranking_a as $pra_key => $pra_value ) {
								$found              = false;
								$iterated_post_tags = wp_get_post_tags( $pra_value['id'] );
								foreach ( $current_post_tags as $cpt_key => $cpt_value ) {
									if ( in_array( $cpt_value, $iterated_post_tags, true ) ) {
										$found = true;
									}
								}
								if ( $found ) {
									$posts_ranking_a[ $pra_key ]['score'] = $posts_ranking_a[ $pra_key ]['score'] + 20;
								}
							}

							break;

						case 'ignore':
							break;

					}
				}
			}
		}

		if ( ! isset( $posts_ranking_a ) || count( $posts_ranking_a ) <= 5 ) {

			echo '<p>' . esc_html__( 'There are no interlinks suggestions at the moment, please use this functionality when you have at least five posts (other than the current one) that match the criteria you defined in the "Suggestions" options.', 'interlinks-manager') . '</p>';

			die();

		}

		/**
		 * Remove the current post from the $post_ranking_a ( The current post
		 * obviously should not be displayed as an interlinks suggestion ).
		 */
		foreach ( $posts_ranking_a as $key => $value ) {
			if ( $value['id'] === $post_id ) {
				unset( $posts_ranking_a[ $key ] );
			}
		}

		/*
		 * Order the $post_ranking_a with descending order based on the 'score'
		 */
		usort( $posts_ranking_a, array( $this->shared, 'usort_callback_1' ) );

		/*
		 * Create the $id_list_a[] array with the reference to the first
		 * $pool_size elements of $posts_ranking_a
		 */
		$id_list_a = array();
		$counter   = 1;
		$pool_size = intval( get_option( $this->shared->get( 'slug' ) . '_suggestions_pool_size' ), 10 );
		foreach ( $posts_ranking_a as $key => $value ) {
			if ( $counter > $pool_size ) {
				continue;}
			$id_list_a[] = $value['id'];
			++$counter;
		}

		/*
		 * Get the post URLs and anchors and generate the HTML content of the list
		 * based on the $id_list_a
		 */

		// Generate the list content and take 5 random posts from the pool $id_list_a.
		$random_id_a = array();
		for ( $i = 1;$i <= 5;$i++ ) {

			/**
			 * Avoid to include the same id multiple times in the list of random
			 * IDs taken from the pool.
			 */
			do {
				$rand_key  = array_rand( $id_list_a, 1 );
				$random_id = $id_list_a[ $rand_key ];
			} while ( in_array( $random_id, $random_id_a, true ) );

			// Get the post type object of the post type associated with the suggested post.
			$post_type_key    = get_post_type( $random_id );
			$post_type_object = get_post_type_object( $post_type_key );

			// Generate the single suggestions.
			echo '<div class="daim-interlinks-suggestions-item">';
			echo '<div class="daim-interlinks-suggestions-container-left">';
			echo '<a class="daim-interlinks-suggestions-link" data-index="' . esc_attr( $i ) . '" href="' . esc_url( get_permalink( $random_id ) ) . '">' . esc_html( get_the_title( $random_id ) ) . '</a>';
			echo '<div class="daim-interlinks-suggestions-post-type">' . esc_html( $post_type_object->labels->singular_name ) . '</div>';
			echo '</div>';
			echo '<div class="daim-interlinks-suggestions-copy-button" data-index="' . esc_attr( $i ) . '">';
			$this->shared->echo_icon_svg( 'clipboard-icon-svg' );
			echo '</div>';
			echo '</div>';

			$random_id_a[] = $random_id;

		}

		die();
	}

	/**
	 * Ajax handler used to generate the content of the "Interlinks Optimization" meta box.
	 */
	public function generate_interlinks_optimization() {

		// Check the referer.
		if ( ! check_ajax_referer( 'daim', 'security', false ) ) {
			echo 'Invalid AJAX Request';
			die();}

		// Check the capability.
		if ( ! current_user_can( get_option( $this->shared->get( 'slug' ) . '_interlinks_optimization_mb_required_capability' ) ) ) {
			echo 'Invalid Capability';
			die();}

		// Get data.
		$post_id = isset( $_POST['post_id'] ) ? intval( $_POST['post_id'], 10 ) : null;

		// Generate the HTML of the meta-box.
		$this->shared->generate_interlinks_optimization_metabox_html( get_post( $post_id ) );

		die();
	}

	/**
	 * Ajax handler used to generate the AIL based on the data available in the table of the Wizard menu.
	 *
	 * This method is called when the "Generate Autolinks" button available in the Wizard menu is clicked.
	 */
	public function daim_wizard_generate_ail() {

		// Check the referer.
		if ( ! check_ajax_referer( 'wizard_nonce', 'security', false ) ) {
			echo 'Invalid AJAX Request';
			die();
		}

		// Check the capability.
		if ( ! current_user_can( get_option( $this->shared->get( 'slug' ) . '_wizard_menu_required_capability' ) ) ) {
			echo 'Invalid Capability';
			die();
		}

		// Get the default values of the AIL from the plugin options.
		$default_title                            = get_option( $this->shared->get( 'slug' ) . '_default_title' );
		$default_open_new_tab                     = get_option( $this->shared->get( 'slug' ) . '_default_open_new_tab' );
		$default_use_nofollow                     = get_option( $this->shared->get( 'slug' ) . '_default_use_nofollow' );
		$default_activate_post_types              = get_option( $this->shared->get( 'slug' ) . '_default_activate_post_types' );
		$default_categories                       = get_option( $this->shared->get( 'slug' ) . '_default_categories' );
		$default_tags                             = get_option( $this->shared->get( 'slug' ) . '_default_tags' );
		$default_term_group_id                    = get_option( $this->shared->get( 'slug' ) . '_default_term_group_id' );
		$default_case_insensitive_search          = get_option( $this->shared->get( 'slug' ) . '_default_case_insensitive_search' );
		$default_left_boundary                    = get_option( $this->shared->get( 'slug' ) . '_default_string_before' );
		$default_right_boundary                   = get_option( $this->shared->get( 'slug' ) . '_default_string_after' );
		$default_keyword_before                   = get_option( $this->shared->get( 'slug' ) . '_default_keyword_before' );
		$default_keyword_after                    = get_option( $this->shared->get( 'slug' ) . '_default_keyword_after' );
		$default_max_number_autolinks_per_keyword = get_option( $this->shared->get( 'slug' ) . '_default_max_number_autolinks_per_keyword' );
		$default_priority                         = get_option( $this->shared->get( 'slug' ) . '_default_priority' );

		// get the name.
		$name = isset( $_POST['name'] ) ? sanitize_text_field( wp_unslash( $_POST['name'] ) ) : null;

		// get the category_id.
		$category_id = isset( $_POST['category_id'] ) ? intval( $_POST['category_id'], 10 ) : null;

		// get the data of the table.
		$table_data_a = isset( $_POST['table_data'] ) ? $this->shared->sanitize_table_data( wp_unslash( $_POST['table_data'] ) ) : null; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized

		// Validation -------------------------------------------------------------------------------------------------.
		if ( mb_strlen( $name ) === 0 || mb_strlen( $name ) > 100 ) {
			echo 'invalid name';
			die();
		}

		global $wpdb;

		// add the new data.
		$values        = array();
		$place_holders = array();
		$query         = "INSERT INTO {$wpdb->prefix}daim_autolinks (
            name,
            category_id,
            keyword,
            url,
            title,
            string_before,
            string_after,
            keyword_before,
            keyword_after,
            activate_post_types,
            categories,
            tags,
            term_group_id,
            max_number_autolinks,
            case_insensitive_search,
            open_new_tab,
            use_nofollow,
            priority
        ) VALUES ";

		// Set the PHP "Max Execution Time" and "Memory Limit" based on the values defined in the options.
		$this->shared->set_met_and_ml();

		foreach ( $table_data_a as $row_index => $row_data ) {

			$keyword = sanitize_text_field( $row_data[0] );
			$url     = substr( esc_url_raw( 'https://example.com' . $row_data[1] ), 19 );
			$title   = sanitize_text_field( $row_data[2] );

			// validation on "Keyword".
			if ( strlen( trim( $keyword ) ) === 0 || strlen( $keyword ) > 255 ) {
				continue;
			}

			/*
			 * Do not allow only numbers as a keyword. Only numbers in a keyword would cause the index of the protected block to
			 * be replaced. For example the keyword "1" would cause the "1" present in the index of the following protected
			 * blocks to be replaced with an autolink:
			 *
			 * - [pb]1[/pb]
			 * - [pb]31[/pb]
			 * - [pb]812[/pb]
			 */
			if ( preg_match( '/^\d+$/', $keyword ) === 1 ) {
				continue;
			}

			/**
			 * Do not allow to create specific keywords that would be able to replace the start delimiter of the
			 * protected block [pb], part of the start delimiter, the end delimited [/pb] or part of the end delimiter.
			 */
			if ( preg_match( '/^\[$|^\[p$|^\[pb$|^\[pb]$|^\[\/$|^\[\/p$|^\[\/pb$|^\[\/pb\]$|^\]$|^b\]$|^pb\]$|^\/pb\]$|^p$|^pb$|^pb\]$|^\/$|^\/p$|^\/pb$|^\/pb]$|^b$|^b\$/i', $keyword ) === 1 ) {
				continue;
			}

			/**
			 * Do not allow to create specific keywords that would be able to replace the start delimiter of the
			 * autolink [ail], part of the start delimiter, the end delimited [/ail] or part of the end delimiter.
			 */
			if ( ! preg_match( '/^\[$|^\[a$|^\[ai$|^\[ail$|^\[ail\]$|^a$|^ai$|^ail$|^ail\]$|^i$|^il$|^il\]$|^l$|^l\]$|^\]$|^\[$|^\[\/$|^\[\/a$|^\[\/ai$|^\[\/ail$|^\[\/ail\]$|^\/$|^\/]$|^\/a$|^\/ai$|^\/ail$|^\/ail\]$/i', $keyword ) === 1 ) {
				continue;
			}

			// Validation on "Target".
			if ( strlen( trim( $url ) ) === 0 ||
				strlen( $keyword ) > 2083 ||
				! preg_match( '/^(?!(http|https|fpt|file):\/\/)[-A-Za-z0-9+&@#\/%?=~_|$!:,.;]+$/', $url ) ) {
				continue;
			}

			// Validation on "Title".
			if ( strlen( $title ) > 1024 ) {
				continue;
			}

			// If the title is not defined use the default title.
			if ( strlen( trim( $title ) ) === 0 ) {
				$title = $default_title;
			}

			array_push(
				$values,
				$name,
				$category_id,
				$keyword,
				$url,
				$title,
				$default_left_boundary,
				$default_right_boundary,
				$default_keyword_before,
				$default_keyword_after,
				maybe_serialize( $default_activate_post_types ),
				maybe_serialize( $default_categories ),
				maybe_serialize( $default_tags ),
				$default_term_group_id,
				$default_max_number_autolinks_per_keyword,
				$default_case_insensitive_search,
				$default_open_new_tab,
				$default_use_nofollow,
				$default_priority
			);

			$place_holders[] = "(
            '%s',
            '%d',
            '%s',
            '%s',
            '%s',
            '%s',
            '%s',
            '%s',
            '%s',
            '%s',
            '%s',
            '%s',
            '%d',
            '%d',
            '%d',
            '%d',
            '%d',
            '%d'
            )";

		}

		if ( count( $values ) > 0 ) {

			// Add the rows.
			$query .= implode( ', ', $place_holders );
			//phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.NotPrepared -- The query is prepared here.
			$result = $wpdb->query(
				$wpdb->prepare( $query, $values )
			);
			//phpcs:enable

			if ( false === $result ) {
				$output = 'error';
			} else {
				$output = $result;
			}
		} else {

			// Do not add the rows and set $output to 0 as the number of rows added.
			$output = 0;

		}

		if ( 'error' === $output ) {
			$this->shared->save_dismissible_notice(
				__( 'Now rows have been added.', 'interlinks-manager'),
				'error'
			);
		} else {
			$this->shared->save_dismissible_notice(
				$output . ' ' . __( 'rows have been added.', 'interlinks-manager'),
				'updated'
			);
		}

		// Send output.
		echo esc_html( $output );
		die();
	}

	/**
	 * Get the list of taxonomies associated with the provided post type.
	 */
	public function daim_get_taxonomies() {

		// check the referer.
		if ( ! check_ajax_referer( 'daim', 'security', false ) ) {
			esc_html_e( 'Invalid AJAX Request', 'interlinks-manager');
			die();
		}

		// check the capability.
		if ( ! current_user_can( get_option( $this->shared->get( 'slug' ) . '_term_groups_menu_required_capability' ) ) ) {
			esc_html_e( 'Invalid Capability', 'interlinks-manager');
			die();
		}

		// get the data.
		$post_type = isset( $_POST['post_type'] ) ? sanitize_key( $_POST['post_type'] ) : null;

		$taxonomies = get_object_taxonomies( $post_type );

		$taxonomy_obj_a = array();
		if ( is_array( $taxonomies ) && count( $taxonomies ) > 0 ) {
			foreach ( $taxonomies as $key => $taxonomy ) {
				$taxonomy_obj_a[] = get_taxonomy( $taxonomy );
			}
		}

		echo wp_json_encode( $taxonomy_obj_a );
		die();
	}

	/**
	 * Get the list of terms associated with the provided taxonomy.
	 */
	public function daim_get_terms() {

		// check the referer.
		if ( ! check_ajax_referer( 'daim', 'security', false ) ) {
			esc_html_e( 'Invalid AJAX Request', 'deextamp' );
			die();
		}

		// check the capability.
		if ( ! current_user_can( get_option( $this->shared->get( 'slug' ) . '_term_groups_menu_required_capability' ) ) ) {
			esc_html_e( 'Invalid Capability', 'interlinks-manager');
			die();
		}

		// get the data.
		$taxonomy = isset( $_POST['taxonomy'] ) ? sanitize_key( $_POST['taxonomy'] ) : null;

		$terms = get_terms(
			array(
				'hide_empty' => 0,
				'orderby'    => 'term_id',
				'order'      => 'DESC',
				'taxonomy'   => $taxonomy,
			)
		);

		if ( is_object( $terms ) && get_class( $terms ) === 'WP_Error' ) {
			return '0';
		} else {
			echo wp_json_encode( $terms );
		}

		die();
	}
}
