HEX
Server: Apache/2.4.52 (Ubuntu)
System: Linux spn-python 5.15.0-89-generic #99-Ubuntu SMP Mon Oct 30 20:42:41 UTC 2023 x86_64
User: arjun (1000)
PHP: 8.1.2-1ubuntu2.20
Disabled: NONE
Upload Files
File: /var/www/html/insiders/wp-load/wp-content/plugins/internal-links/backend/editor.php
<?php
namespace ILJ\Backend;

use ILJ\Core\Options;
use ILJ\Core\Options\CacheToggleBtnSwitch;
use ILJ\Data\Content;
use ILJ\Database\Linkindex;
use ILJ\Helper\Help;
use ILJ\Type\KeywordList;
use ILJ\Database\Postmeta;
use ILJ\Database\Termmeta;
use ILJ\Helper\Capabilities;
use ILJ\Helper\IndexAsset as IndexAsset;
use ILJ\Helper\Statistic;

/**
 * Admin views
 *
 * Responsible for all view elements which are required on the backend
 *
 * @package ILJ\Backend
 *
 * @since 1.0.0
 */
class Editor {

	const ILJ_ADMINVIEW_NONCE                 = '_ilj_adminview_nonce';
	const ILJ_ACTION_AFTER_KEYWORDS_UPDATE    = 'ilj_after_keywords_update';
	const ILJ_EDITOR_HANDLE                   = 'ilj_editor';
	const ILJ_KEYWORDS_HANDLE                 = 'ilj_keywords';
	const ILJ_IS_BLACKLISTED                  = 'ilj_is_blacklisted';
	const ILJ_META_KEY_LIMITINCOMINGLINKS     = 'ilj_limitincominglinks';
	const ILJ_META_KEY_MAXINCOMINGLINKS       = 'ilj_maxincominglinks';
	const ILJ_META_KEY_BLACKLISTDEFINITION    = 'ilj_blacklistdefinition';
	const ILJ_META_KEY_LIMITLINKSPERPARAGRAPH = 'ilj_limitlinksperparagraph';
	const ILJ_META_KEY_LINKSPERPARAGRAPH      = 'ilj_linksperparagraph';
	const ILJ_META_KEY_LIMITOUTGOINGLINKS     = 'ilj_limitoutgoinglinks';
	const ILJ_META_KEY_MAXOUTGOINGLINKS       = 'ilj_maxoutgoinglinks';
	const ILJ_KEYWORD_METABOX_FOOTER_HOOK     = 'ilj_keyword_metabox_footer';
	const ILJ_MODAL = 'ilj_modal';

	/**
	 * Registers the keyword metabox on all public post types
	 *
	 * @since 1.0.0
	 *
	 * @return void
	 */
	public static function addKeywordMetaBox() {
		foreach (get_post_types(array('public' => true)) as $type) {
			add_meta_box(
				Postmeta::ILJ_META_KEY_LINKDEFINITION,
				__('Internal Links', 'internal-links'),
				array(__CLASS__, 'renderKeywordMetaBox'),
				$type,
				'side',
				'default'
			);
		}

		
	}

	/**
	 * Renders the keyword metabox
	 *
	 * @since 1.0.0
	 *
	 * @param  \WP_Post $post The post object of the current page
	 * @return void
	 */
	public static function renderKeywordMetaBox(\WP_Post $post) {
		$keyword_list      = KeywordList::fromMeta($post->ID, 'post', Postmeta::ILJ_META_KEY_LINKDEFINITION);
		$blacklist_keywords = KeywordList::fromMeta($post->ID, 'post', self::ILJ_META_KEY_BLACKLISTDEFINITION);

		wp_nonce_field(basename(__FILE__), self::ILJ_ADMINVIEW_NONCE);
		?>
		<p>
		<label for="<?php echo esc_attr(Postmeta::ILJ_META_KEY_LINKDEFINITION . '_keys'); ?>"><?php esc_html_e('The keywords', 'internal-links'); ?>:</label>
		<br />
		<input
				type="text"
				name="<?php echo esc_attr(Postmeta::ILJ_META_KEY_LINKDEFINITION . '_keys'); ?>"
				value="<?php echo esc_attr($keyword_list->encoded()); ?>" size="30"/>
		<?php
		
		?>
			<input type="text"
				   name="<?php echo esc_attr(self::ILJ_IS_BLACKLISTED); ?>"
				   value="<?php echo esc_attr(self::isBlacklisted($post->ID, 'post')); ?>"
				   style="display:none"/>

			<input type="text"
				   name="<?php echo esc_attr(self::ILJ_META_KEY_BLACKLISTDEFINITION); ?>"
				   value="<?php echo esc_attr($blacklist_keywords->encoded()); ?>"
				   size="30"
				   style="display:none"/>
					</p>
		<template id="ilj_keyword_metabox_footer">
			<?php
				$content = Content::from_post($post);
				/**
				 * This action is used to render content dynamically in to metabox footer.
				 * The HTML content inside <template> tag will rendered at the footer of editor.
				 *
				 * @param $content Content|null The content, null if its rendered on add post or add term page.
				 * @since 2.23.5
				 */
				do_action(self::ILJ_KEYWORD_METABOX_FOOTER_HOOK, $content);
			?>
		</template>
		<?php
	}

	/**
	 * Hooks in to {@link self::ILJ_KEYWORD_METABOX_FOOTER_HOOK} to add custom html to <template> tag
	 *
	 * @param Content|null $content The content, null if its rendered on add post or add term page.
	 * @return void
	 */
	public static function render_keyword_metabox_footer($content) {
		?>
		<div class="ilj-row">
			<div class="col-12 ilj-footer">
				<a href="https://internallinkjuicer.com/docs/editor/?utm_source=editor&utm_medium=help&utm_campaign=plugin"
				   rel="noopener" target="_blank" class="help">
					<span class="dashicons dashicons-editor-help"></span>
					<?php esc_html_e('Get help', 'internal-links'); ?>
				</a>
				<?php self::render_delete_cache_button($content); ?>
			</div>
		</div>
		<?php
	}

	/**
	 * Renders delete cache button inside metabox.
	 *
	 * @param Content|null $content The content, null if its rendered on add post or add term page.
	 * @return void
	 */
	private static function render_delete_cache_button($content) {
		if (!$content) {
			return;
		}
		$link = admin_url(
			sprintf( 'admin-ajax.php?action=%s&_wpnonce=%s&ilj_transient_id=%d&ilj_transient_type=%s&ilj_skip_notice=true',
				'ilj_clear_single_transient',
				wp_create_nonce('ilj_clear_single_transient'),
				$content->get_id(),
				$content->get_type()
			)
		);
		$cache_option = Options::getOption(CacheToggleBtnSwitch::getKey());
		if ($cache_option) {
		?>
		<div class="ilj-delete-cache-container">
			<button class="ilj-button-danger button" id="ilj-delete-cache" type="button" data-ilj-delete-cache-url="<?php echo esc_attr($link); ?>">
				<?php esc_html_e('Delete Cache', 'internal-links'); ?>
			</button>
			<span class="spinner is-active ilj-spinner ilj-hidden"></span>
		</div>
		<?php
		}
	}

	/**
	 * Responsible for saving keyword meta values and
	 * stores limit linking settings for posts and
	 * stores limit linking settings for posts
	 *
	 * @since 1.0.0
	 *
	 * @param  int      $post_id The ID of the post
	 * @param  \WP_Post $post    The post object
	 * @return void
	 */
	public static function saveKeywordMeta($post_id, \WP_Post $post) {
		if (is_null($post_id) || is_null($post)) {
			return;
		}

		if (!isset($_POST[self::ILJ_ADMINVIEW_NONCE]) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST[self::ILJ_ADMINVIEW_NONCE])), basename(__FILE__))
		) {
			return $post_id;
		}

		$post_type = get_post_type_object($post->post_type);

		if (!current_user_can($post_type->cap->edit_post, $post_id)) {
			return $post_id;
		}

		

		if (array_key_exists(self::ILJ_META_KEY_BLACKLISTDEFINITION, $_POST)) {
			$sanitized_blacklist_meta_value = sanitize_text_field(wp_unslash($_POST[self::ILJ_META_KEY_BLACKLISTDEFINITION]));
			$keywordsblacklist              = KeywordList::fromInput($sanitized_blacklist_meta_value);

			{
       update_post_meta(
   					$post_id,
   					self::ILJ_META_KEY_BLACKLISTDEFINITION,
   					array_slice($keywordsblacklist->getKeywords(), 0, 2)
   				);
   }
		}

		if (array_key_exists(self::ILJ_IS_BLACKLISTED, $_POST) && true == $_POST[self::ILJ_IS_BLACKLISTED]) {
			self::addToBlacklist($post_id, 'post');
		} else {
			self::removeFromBlacklist($post_id, 'post');
		}

		if (array_key_exists(Postmeta::ILJ_META_KEY_LINKDEFINITION . '_keys', $_POST)) {

			$sanitized_meta_value = sanitize_text_field(wp_unslash($_POST[Postmeta::ILJ_META_KEY_LINKDEFINITION . '_keys']));
			$keywords             = KeywordList::fromInput($sanitized_meta_value);

			// Retrieve the old keywords before updating
			$old_keyword_list = KeywordList::fromMeta($post_id, 'post', Postmeta::ILJ_META_KEY_LINKDEFINITION);
			$old_keyword_count = $old_keyword_list->getCount();
			$update_status = self::set_keywords($post_id, $keywords);

			/**
			 * Fires after keyword meta got saved
			 *
			 * @since 1.0.0
			 */
			if (true == $update_status) {
				$post_id       = isset($_POST['post_ID']) ? intval($_POST['post_ID']) : 0;
				$post_status   = isset($_POST['post_status']) ? sanitize_text_field(wp_unslash($_POST['post_status'])) : '';
				$keyword_list  = KeywordList::fromMeta($post_id, 'post', Postmeta::ILJ_META_KEY_LINKDEFINITION);
				$keyword_count = $keyword_list->getCount();
				if ($old_keyword_count > 0 && 0 == $keyword_count) {
					Linkindex::delete_link_to($post_id, 'post');
					Statistic::updateStatisticsInfo();
				} elseif ($keyword_count > 0) {
					do_action(self::ILJ_ACTION_AFTER_KEYWORDS_UPDATE, $post_id, 'post', $post_status);
				}
			}
		}

	}

	/**
	 * Set keywords for a post id, returns boolean or int based on the value.
	 *
	 * @param int         $post_id  The post id.
	 * @param KeywordList $keywords The keyword list for post.
	 *
	 * @return bool|int
	 */
	public static function set_keywords($post_id, $keywords) {
		$prev_value = get_post_meta($post_id, Postmeta::ILJ_META_KEY_LINKDEFINITION, true);
		return update_post_meta(
			$post_id,
			Postmeta::ILJ_META_KEY_LINKDEFINITION,
			$keywords->getKeywords(),
			$prev_value
		);
	}

	/**
	 * Logic for adding the assets based on subscription
	 *
	 * @since 1.1.0
	 *
	 * @return void
	 */
	public static function addAssets() {
		$required_role = 'administrator';

		

		if (!current_user_can($required_role)) {
			return;
		}

		global $pagenow;

		if (in_array($pagenow, array('post-new.php', 'post.php'))) {

			// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- It gets the post type on the add/edit post admin dashboard page. No nonce verification needed.
			if (!isset($_GET['post_type'])) {
				self::registerAssets();
				return;
			}

			// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- It gets the post type on the add/edit post admin dashboard page. No nonce verification needed.
			$post_type = get_post_type_object(sanitize_text_field(wp_unslash($_GET['post_type'])));

			

			if (!$post_type || !$post_type->public) {
				return;
			}

			self::registerAssets();
		}

		
	}

	/**
	 * Registering the assets for editor frontend
	 *
	 * @since 1.1.0
	 *
	 * @return void
	 */
	private static function registerAssets() {
		add_action(
			'admin_enqueue_scripts',
			function () {
				\ILJ\Helper\Loader::enqueue_script('jquery-ui-sortable');
				\ILJ\Helper\Loader::register_script(Editor::ILJ_KEYWORDS_HANDLE, ILJ_URL . 'admin/js/ilj_keywords.js', array(), ILJ_VERSION);
				\ILJ\Helper\Loader::register_script(Editor::ILJ_EDITOR_HANDLE, ILJ_URL . 'admin/js/ilj_editor.js', array(), ILJ_VERSION);
				\ILJ\Helper\Loader::register_script(Editor::ILJ_MODAL, ILJ_URL . 'admin/js/ilj_modal.js', array(), ILJ_VERSION);
				wp_localize_script(Editor::ILJ_EDITOR_HANDLE, 'ilj_editor_duplicate', array(
					'nonce' => wp_create_nonce('ilj-editor-action'),
				));
				wp_localize_script(Editor::ILJ_EDITOR_HANDLE, 'ilj_editor_translation', array_merge(
					Editor::getTranslation(),
					array('nonce' => wp_create_nonce('render-keyword-meta-box-nonce'))
				));
				wp_add_inline_script(Editor::ILJ_EDITOR_HANDLE, 'const ilj_editor_basic_restriction = ' . wp_json_encode(Editor::getBasicRestrictions()), 'before');
				\ILJ\Helper\Loader::enqueue_script('ilj_tipso', ILJ_URL . 'admin/js/tipso.js', array(), ILJ_VERSION);
				\ILJ\Helper\Loader::enqueue_script(Editor::ILJ_KEYWORDS_HANDLE);
				\ILJ\Helper\Loader::enqueue_script(Editor::ILJ_EDITOR_HANDLE);
				\ILJ\Helper\Loader::enqueue_script(Editor::ILJ_MODAL);
				\ILJ\Helper\Loader::enqueue_style('ilj_tipso', ILJ_URL . 'admin/css/tipso.css', array(), ILJ_VERSION);
				\ILJ\Helper\Loader::enqueue_style(Editor::ILJ_EDITOR_HANDLE, ILJ_URL . 'admin/css/ilj_editor.css', array(), ILJ_VERSION);
				\ILJ\Helper\Loader::enqueue_style(Editor::ILJ_EDITOR_HANDLE, ILJ_URL . 'admin/css/ilj_modal.css', array(), ILJ_VERSION);
				\ILJ\Helper\Loader::enqueue_style('ilj_ui', ILJ_URL . 'admin/css/ilj_ui.css', array(), ILJ_VERSION);
			},
			10,
			1
		);

	}

	/**
	 * Returns the frontend translation
	 *
	 * @since 1.0.1
	 *
	 * @return array
	 */
	public static function getTranslation() {
		$translation = array(
			'add_keyword'                               => __('Add Keyword', 'internal-links'),
			'placeholder_keyword'                       => __('Keyword', 'internal-links'),
			'howto_case'                                => __('Keywords get used <strong>case insensitive</strong>', 'internal-links'),
			'howto_keyword'                             => __('Separate multiple keywords by commas', 'internal-links'),
			'howto_gap'                                 => __('Configure the gap dimension.', 'internal-links') . ' ' . __('It represents the number of keywords that appear between your other keywords dynamically.', 'internal-links') . ' ' . __('Learn more in our documentation:', 'internal-links') . '<br><strong><a target="_blank" rel="noopener" href="' . Help::getLinkUrl('editor/', 'gaps', 'gap help', 'editor') . '">' . __('Click here to open', 'internal-links') . '</a></strong>',
			'headline_gaps'                             => __('Keyword gaps', 'internal-links'),
			'add_gap'                                   => __('Add gap', 'internal-links'),
			'gap_type'                                  => __('Gap type', 'internal-links'),
			'type_min'                                  => __('Minimum', 'internal-links'),
			'type_exact'                                => __('Exact', 'internal-links'),
			'type_max'                                  => __('Maximum', 'internal-links'),
			'howto_gap_min'                             => __('Minimum amount of keywords within the gap.', 'internal-links') . ' ' . __('No upper limits.', 'internal-links'),
			'howto_gap_exact'                           => __('Exact amount of keywords within the gap.', 'internal-links'),
			'howto_gap_max'                             => __('Maximum amount of keywords within the gap.', 'internal-links'),
			'howto_links_per_paragraph'                 => __('Overrides the general setting for the current asset.', 'internal-links'),
			'howto_add_to_blacklist'                    => __('Toggle to add/remove from global blacklist.', 'internal-links'),
			'howto_limit_incoming_links'                => __('Toggle to add/remove incoming links limit.', 'internal-links'),
			'howto_limit_outgoing_links'                => __('Toggle to add/remove outgoing links limit.', 'internal-links'),
			'insert_gaps'                               => __('Insert gaps between keywords', 'internal-links'),
			'headline_configured_keywords'              => __('Configured keywords', 'internal-links'),
			'message_keyword_exists'                    => __('This keyword already exists.', 'internal-links'),
			'message_no_keyword'                        => __('No keyword defined.', 'internal-links'),
			'message_length_not_valid'                  => __('Length of given keyword not valid.', 'internal-links'),
			'message_multiple_placeholder'              => __('Multiple consecutive placeholders are not allowed.', 'internal-links'),
			'no_keywords'                               => __('No keywords configured.', 'internal-links'),
			'gap_hover_exact'                           => __('Exact keyword gap:', 'internal-links'),
			'gap_hover_max'                             => __('Maximum keyword gap:', 'internal-links'),
			'gap_hover_min'                             => __('Minimum keyword gap:', 'internal-links'),
			'limit_incoming_links'                      => __('Limit incoming Links:', 'internal-links'),
			'max_incoming_links'                        => __('Maximum incoming links:', 'internal-links'),
			'blacklist_incoming_links'                  => __('Keywords, that don`t get linked in the current content:', 'internal-links'),
			'message_limited_blacklist_keyword'         => __('With the free Basic version of the Iternal Link Juicer, you can block 2 keywords from being linked.', 'internal-links'),
			'message_limited_blacklist_keyword_upgrade' => sprintf('&raquo; <a href="%s">', get_admin_url(null, 'admin.php?page=' . AdminMenu::ILJ_MENUPAGE_SLUG . '-pricing')) . __('Upgrade to Pro and add unlimited keywords', 'internal-links') . '</a>',
			'headline_configured_keywords_blacklist'    => __('Configured keyword blacklist:', 'internal-links'),
			'is_blacklisted'                            => __('Is on global blacklist:', 'internal-links'),
			'limit_links_per_paragraph'                 => __('Limit links per paragraph:', 'internal-links'),
			'max_links_per_paragraph'                   => __('Maximum links per paragraph:', 'internal-links'),
			'limit_outgoing_links'                      => __('Limit outgoing Links:', 'internal-links'),
			'max_outgoing_links'                        => __('Maximum outgoing links:', 'internal-links'),
			'cache_cleared' 							=> __('Cache cleared.', 'internal-links'),
			'upgrade_to_pro_button_text' 				=> __('Upgrade to Pro', 'internal-links'),
			'upgrade_to_pro_link'						=> get_admin_url(null, 'admin.php?billing_cycle=annual&trial=true&page=' . AdminMenu::ILJ_MENUPAGE_SLUG . '-pricing'),
			'pro_feature_title'							=> __('This is a PRO Feature.', 'internal-links'),
			'keyword_duplicate_title'					=> __('Keyword Duplicate for:', 'internal-links')
		);
		return $translation;
	}

	/**
	 * Sets Basic version restrictions
	 *
	 * @version 1.2.15
	 *
	 * @return array
	 */
	protected static function getBasicRestrictions() {
		$current_screen     = get_current_screen();
		$basic_restrictions = array(
			'blacklist_limit' => 2,
			'is_active'       => true,
			'disable_title'   => 'class="pro-title"',
			'disable_setting' => 'pro-setting',
			'disabled'        => 'disabled',
			'lock_icon'       => '<span class="dashicons dashicons-lock tip" title="' . __('This feature is part of the Pro version', 'internal-links') . '"></span>',
			'current_screen'  => $current_screen->post_type,
		);

		

		return $basic_restrictions;
	}

	

	

	

	

	 

	

	/**
	 * Checks if an asset is on the blacklist
	 *
	 * @since 1.2.15
	 *
	 * @param  int    $id   The asset ID
	 * @param  string $type The asset type
	 * @return bool True if blacklisted , false if not
	 */
	public static function isBlacklisted($id, $type) {
		if ('post' == $type) {
			$postBlacklist = Options::getOption(\ILJ\Core\Options\Blacklist::getKey());
			$blacklisted   = false;
			if (is_array($postBlacklist)) {
				if (in_array($id, $postBlacklist)) {
					$blacklisted = true;
				}
			}
			return $blacklisted;
		}

		

		return false;
	}

	/**
	 * Removes an asset from blacklist
	 *
	 * @since 1.2.15
	 *
	 * @param  int    $id   The asset id
	 * @param  string $type The asset type
	 * @return void
	 */
	protected static function removeFromBlacklist($id, $type) {
		$blacklist = array();

		if ('post' == $type) {
			$blacklist = Options::getOption(\ILJ\Core\Options\Blacklist::getKey());
		}

		

		$blacklist = is_array($blacklist) ? $blacklist : array();

		if (($key = array_search($id, $blacklist)) !== false) {
			unset($blacklist[$key]);
		} else {
			return;
		}

		if ('post' == $type) {
			Options::setOption(\ILJ\Core\Options\Blacklist::getKey(), $blacklist);
		}

		
	}

	/**
	 * Adds ID to Blacklist Option of post/terms
	 *
	 * @since 1.2.15
	 *
	 * @param  int    $id   The asset id
	 * @param  string $type The asset type
	 * @return void
	 */
	protected static function addToBlacklist($id, $type) {
		$blacklist = array();

		if ('post' == $type) {
			$blacklist = Options::getOption(\ILJ\Core\Options\Blacklist::getKey());
		}

		

		$blacklist = is_array($blacklist) ? $blacklist : array();

		if (in_array($id, $blacklist)) {
			return;
		}

		$blacklist[] = $id;

		if ('post' == $type) {
			Options::setOption(\ILJ\Core\Options\Blacklist::getKey(), $blacklist);
		}

		
	}
	
	/**
	 * Ajax callback that reset keyword meta box for terms
	 *
	 * @return void
	 */
	public static function render_keyword_meta_box_callback() {
		if (!isset($_POST['nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['nonce'])), 'render-keyword-meta-box-nonce')) {
			die();
		}
		if (!current_user_can('manage_options')) {
			return;
		}
		ob_start();
		self::render_keyword_meta_box_taxonomy__premium_only(null, 'create');
		$output = ob_get_clean();

		wp_send_json_success($output);
	}
}