Vue.php 16.4 KB
<?php
namespace AIOSEO\Plugin\Common\Traits\Helpers;

use AIOSEO\Plugin\Common\Models;
use AIOSEO\Plugin\Common\Tools;

// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Contains all Vue related helper methods.
 *
 * @since 4.1.4
 */
trait Vue {
	/**
	 * Returns the data for Vue.
	 *
	 * @since 4.0.0
	 *
	 * @param  string $page The current page.
	 * @return array        The data.
	 */
	public function getVueData( $page = null ) {
		$postTypeObj = get_post_type_object( get_post_type( get_the_ID() ) );
		$screen      = get_current_screen();

		$isStaticHomePage = 'page' === get_option( 'show_on_front' );
		$staticHomePage   = intval( get_option( 'page_on_front' ) );
		$data = [
			'page'             => $page,
			'screen'           => [
				'base'        => $screen->base,
				'postType'    => $screen->post_type,
				'blockEditor' => isset( $screen->is_block_editor ) ? $screen->is_block_editor : false,
				'new'         => isset( $screen->action ) && 'add' === $screen->action
			],
			'internalOptions'  => aioseo()->internalOptions->all(),
			'options'          => aioseo()->options->all(),
			'dynamicOptions'   => aioseo()->dynamicOptions->all(),
			'settings'         => aioseo()->settings->all(),
			'tags'             => aioseo()->tags->all( true ),
			'nonce'            => wp_create_nonce( 'wp_rest' ),
			'urls'             => [
				'domain'            => $this->getSiteDomain(),
				'mainSiteUrl'       => $this->getSiteUrl(),
				'home'              => home_url(),
				'restUrl'           => rest_url(),
				'publicPath'        => plugin_dir_url( AIOSEO_FILE ),
				'rssFeedUrl'        => get_bloginfo( 'rss2_url' ),
				'generalSitemapUrl' => aioseo()->sitemap->helpers->getUrl( 'general' ),
				'rssSitemapUrl'     => aioseo()->sitemap->helpers->getUrl( 'rss' ),
				'robotsTxtUrl'      => $this->getSiteUrl() . '/robots.txt',
				'blockedBotsLogUrl' => wp_upload_dir()['baseurl'] . '/aioseo/logs/aioseo-bad-bot-blocker.log',
				'upgradeUrl'        => apply_filters( 'aioseo_upgrade_link', AIOSEO_MARKETING_URL ),
				'staticHomePage'    => 'page' === get_option( 'show_on_front' ) ? get_edit_post_link( get_option( 'page_on_front' ), 'url' ) : null,
				'connect'           => add_query_arg( [
					'siteurl'  => site_url(),
					'homeurl'  => home_url(),
					'redirect' => rawurldecode( base64_encode( admin_url( 'index.php?page=aioseo-connect' ) ) )
				], defined( 'AIOSEO_CONNECT_URL' ) ? AIOSEO_CONNECT_URL : 'https://connect.aioseo.com' ),
				'aio'               => [
					'wizard'           => admin_url( 'index.php?page=aioseo-setup-wizard' ),
					'dashboard'        => admin_url( 'admin.php?page=aioseo' ),
					'settings'         => admin_url( 'admin.php?page=aioseo-settings' ),
					'localSeo'         => admin_url( 'admin.php?page=aioseo-local-seo' ),
					'featureManager'   => admin_url( 'admin.php?page=aioseo-feature-manager' ),
					'sitemaps'         => admin_url( 'admin.php?page=aioseo-sitemaps' ),
					'seoAnalysis'      => admin_url( 'admin.php?page=aioseo-seo-analysis' ),
					'searchAppearance' => admin_url( 'admin.php?page=aioseo-search-appearance' ),
					'socialNetworks'   => admin_url( 'admin.php?page=aioseo-social-networks' ),
					'tools'            => admin_url( 'admin.php?page=aioseo-tools' ),
					'monsterinsights'  => admin_url( 'admin.php?page=aioseo-monsterinsights' )
				],
				'admin'             => [
					'widgets'          => admin_url( 'widgets.php' ),
					'optionsReading'   => admin_url( 'options-reading.php' ),
					'scheduledActions' => admin_url( '/tools.php?page=action-scheduler&status=pending&s=aioseo' ),
					'generalSettings'  => admin_url( 'options-general.php' )
				]
			],
			'backups'          => [],
			'importers'        => [],
			'data'             => [
				'server'              => [
					'apache' => null,
					'nginx'  => null
				],
				'robots'              => [
					'defaultRules'      => [],
					'hasPhysicalRobots' => null,
					'rewriteExists'     => null,
					'sitemapUrls'       => []
				],
				'logSizes'            => [
					'badBotBlockerLog' => null
				],
				'status'              => [],
				'htaccess'            => '',
				'multisite'           => is_multisite(),
				'network'             => is_network_admin(),
				'mainSite'            => is_main_site(),
				'subdomain'           => defined( 'SUBDOMAIN_INSTALL' ) && SUBDOMAIN_INSTALL,
				'isWooCommerceActive' => $this->isWooCommerceActive(),
				'isBBPressActive'     => class_exists( 'bbPress' ),
				'staticHomePage'      => $isStaticHomePage ? $staticHomePage : false,
				'staticBlogPage'      => $this->getBlogPageId(),
				'staticBlogPageTitle' => get_the_title( $this->getBlogPageId() ),
				'isDev'               => $this->isDev(),
				'isSsl'               => is_ssl(),
				'hasUrlTrailingSlash' => '/' === user_trailingslashit( '' )
			],
			'user'             => [
				'email'          => wp_get_current_user()->user_email,
				'roles'          => $this->getUserRoles(),
				'customRoles'    => $this->getCustomRoles(),
				'canManage'      => aioseo()->access->canManage(),
				'capabilities'   => aioseo()->access->getAllCapabilities(),
				'unfilteredHtml' => current_user_can( 'unfiltered_html' ),
				'locale'         => function_exists( 'get_user_locale' ) ? get_user_locale() : get_locale()
			],
			'plugins'          => $this->getPluginData(),
			'postData'         => [
				'postTypes'    => $this->getPublicPostTypes( false, false, true ),
				'taxonomies'   => $this->getPublicTaxonomies( false, true ),
				'archives'     => $this->getPublicPostTypes( false, true, true ),
				'postStatuses' => $this->getPublicPostStatuses()
			],
			'notifications'    => Models\Notification::getNotifications( false ),
			'addons'           => aioseo()->addons->getAddons(),
			'version'          => AIOSEO_VERSION,
			'helpPanel'        => json_decode( aioseo()->help->getDocs() ),
			'scheduledActions' => [
				'sitemaps' => []
			]
		];

		if ( is_multisite() && ! is_network_admin() ) {
			switch_to_blog( $this->getNetworkId() );
			$options = aioseo()->options->noConflict();
			$options->initNetwork();
			$data['networkOptions'] = $options->all();
			restore_current_blog();
		}

		if ( 'post' === $page ) {
			$postId              = get_the_ID();
			$post                = Models\Post::getPost( $postId );

			$data['currentPost'] = [
				'context'                        => 'post',
				'tags'                           => aioseo()->tags->getDefaultPostTags( $postId ),
				'id'                             => $postId,
				'priority'                       => ! empty( $post->priority ) ? $post->priority : 'default',
				'frequency'                      => ! empty( $post->frequency ) ? $post->frequency : 'default',
				'permalink'                      => get_the_permalink(),
				'title'                          => ! empty( $post->title ) ? $post->title : aioseo()->meta->title->getPostTypeTitle( $postTypeObj->name ),
				'description'                    => ! empty( $post->description ) ? $post->description : aioseo()->meta->description->getPostTypeDescription( $postTypeObj->name ),
				'keywords'                       => ! empty( $post->keywords ) ? $post->keywords : wp_json_encode( [] ),
				'keyphrases'                     => ! empty( $post->keyphrases )
					? json_decode( $post->keyphrases )
					: json_decode( '{"focus":{},"additional":[]}' ),
				'page_analysis'                  => ! empty( $post->page_analysis )
					? json_decode( $post->page_analysis )
					: Models\Post::getPageAnalysisDefaults(),
				'loading'                        => [
					'focus'      => false,
					'additional' => [],
				],
				'type'                           => $postTypeObj->labels->singular_name,
				'postType'                       => 'type' === $postTypeObj->name ? '_aioseo_type' : $postTypeObj->name,
				'isSpecialPage'                  => $this->isSpecialPage( $postId ),
				'isWooCommercePageWithoutSchema' => $this->isWooCommercePageWithoutSchema( $postId ),
				'seo_score'                      => (int) $post->seo_score,
				'pillar_content'                 => ( (int) $post->pillar_content ) === 0 ? false : true,
				'canonicalUrl'                   => $post->canonical_url,
				'default'                        => ( (int) $post->robots_default ) === 0 ? false : true,
				'noindex'                        => ( (int) $post->robots_noindex ) === 0 ? false : true,
				'noarchive'                      => ( (int) $post->robots_noarchive ) === 0 ? false : true,
				'nosnippet'                      => ( (int) $post->robots_nosnippet ) === 0 ? false : true,
				'nofollow'                       => ( (int) $post->robots_nofollow ) === 0 ? false : true,
				'noimageindex'                   => ( (int) $post->robots_noimageindex ) === 0 ? false : true,
				'noodp'                          => ( (int) $post->robots_noodp ) === 0 ? false : true,
				'notranslate'                    => ( (int) $post->robots_notranslate ) === 0 ? false : true,
				'maxSnippet'                     => null === $post->robots_max_snippet ? -1 : (int) $post->robots_max_snippet,
				'maxVideoPreview'                => null === $post->robots_max_videopreview ? -1 : (int) $post->robots_max_videopreview,
				'maxImagePreview'                => $post->robots_max_imagepreview,
				'modalOpen'                      => false,
				'tabs'                           => ( ! empty( $post->tabs ) )
					? json_decode( $post->tabs )
					: json_decode( Models\Post::getDefaultTabsOptions() ),
				'generalMobilePrev'              => false,
				'socialMobilePreview'            => false,
				'og_object_type'                 => ! empty( $post->og_object_type ) ? $post->og_object_type : 'default',
				'og_title'                       => $post->og_title,
				'og_description'                 => $post->og_description,
				'og_image_custom_url'            => $post->og_image_custom_url,
				'og_image_custom_fields'         => $post->og_image_custom_fields,
				'og_image_type'                  => ! empty( $post->og_image_type ) ? $post->og_image_type : 'default',
				'og_video'                       => ! empty( $post->og_video ) ? $post->og_video : '',
				'og_article_section'             => ! empty( $post->og_article_section ) ? $post->og_article_section : '',
				'og_article_tags'                => ! empty( $post->og_article_tags ) ? $post->og_article_tags : wp_json_encode( [] ),
				'twitter_use_og'                 => ( (int) $post->twitter_use_og ) === 0 ? false : true,
				'twitter_card'                   => $post->twitter_card,
				'twitter_image_custom_url'       => $post->twitter_image_custom_url,
				'twitter_image_custom_fields'    => $post->twitter_image_custom_fields,
				'twitter_image_type'             => $post->twitter_image_type,
				'twitter_title'                  => $post->twitter_title,
				'twitter_description'            => $post->twitter_description,
				'schema_type'                    => ( ! empty( $post->schema_type ) ) ? $post->schema_type : 'default',
				'schema_type_options'            => ( ! empty( $post->schema_type_options ) )
					? json_decode( Models\Post::getDefaultSchemaOptions( $post->schema_type_options ) )
					: json_decode( Models\Post::getDefaultSchemaOptions() ),
				'metaDefaults'                   => [
					'title'       => aioseo()->meta->title->getPostTypeTitle( $postTypeObj->name ),
					'description' => aioseo()->meta->description->getPostTypeDescription( $postTypeObj->name )
				],
				'linkAssistant'                  => [
					'modalOpen' => false
				]
			];

			if ( ! $post->exists() ) {
				$oldPostMeta = aioseo()->migration->meta->getMigratedPostMeta( $postId );
				foreach ( $oldPostMeta as $k => $v ) {
					if ( preg_match( '#robots_.*#', $k ) ) {
						$oldPostMeta[ preg_replace( '#robots_#', '', $k ) ] = $v;
						continue;
					}
					if ( 'canonical_url' === $k ) {
						$oldPostMeta['canonicalUrl'] = $v;
					}
				}
				$data['currentPost'] = array_merge( $data['currentPost'], $oldPostMeta );
			}
		}

		if ( 'sitemaps' === $page ) {
			try {
				if ( as_next_scheduled_action( 'aioseo_static_sitemap_regeneration' ) ) {
					$data['scheduledActions']['sitemap'][] = 'staticSitemapRegeneration';
				}
			} catch ( \Exception $e ) {
				// Do nothing.
			}
		}

		if ( 'setup-wizard' === $page ) {
			$data['users']     = $this->getSiteUsers( [ 'administrator', 'editor', 'author' ] );
			$data['importers'] = aioseo()->importExport->plugins();
		}

		if ( 'search-appearance' === $page ) {
			$data['users'] = $this->getSiteUsers( [ 'administrator', 'editor', 'author' ] );
			$data['data'] += [
				'staticHomePageTitle'       => $isStaticHomePage ? aioseo()->meta->title->getTitle( $staticHomePage ) : '',
				'staticHomePageDescription' => $isStaticHomePage ? aioseo()->meta->description->getDescription( $staticHomePage ) : '',
			];
		}

		if ( 'social-networks' === $page ) {
			$data['data'] += [
				'staticHomePageOgTitle'            => $isStaticHomePage ? aioseo()->social->facebook->getTitle( $staticHomePage ) : '',
				'staticHomePageOgDescription'      => $isStaticHomePage ? aioseo()->social->facebook->getDescription( $staticHomePage ) : '',
				'staticHomePageTwitterTitle'       => $isStaticHomePage ? aioseo()->social->twitter->getTitle( $staticHomePage ) : '',
				'staticHomePageTwitterDescription' => $isStaticHomePage ? aioseo()->social->twitter->getDescription( $staticHomePage ) : '',
			];
		}

		if ( 'tools' === $page ) {
			$data['backups']        = array_reverse( aioseo()->backup->all() );
			$data['importers']      = aioseo()->importExport->plugins();
			$data['data']['server'] = [
				'apache' => $this->isApache(),
				'nginx'  => $this->isNginx()
			];
			$data['data']['robots'] = [
				'defaultRules'      => $page ? aioseo()->robotsTxt->getDefaultRules() : [],
				'hasPhysicalRobots' => aioseo()->robotsTxt->hasPhysicalRobotsTxt(),
				'rewriteExists'     => aioseo()->robotsTxt->rewriteRulesExist(),
				'sitemapUrls'       => array_merge( aioseo()->sitemap->helpers->getSitemapUrls(), $this->extractSitemapUrlsFromRobotsTxt() )
			];
			$data['data']['logSizes'] = [
				'badBotBlockerLog' => $this->convertFileSize( aioseo()->badBotBlocker->getLogSize() )
			];
			$data['data']['status']   = Tools\SystemStatus::getSystemStatusInfo();
			$data['data']['htaccess'] = aioseo()->htaccess->getContents();
		}

		if ( 'settings' === $page ) {
			$data['breadcrumbs']['defaultTemplate'] = aioseo()->helpers->encodeOutputHtml( aioseo()->breadcrumbs->frontend->getDefaultTemplate() );
		}

		$loadedAddons = aioseo()->addons->getLoadedAddons();
		if ( ! empty( $loadedAddons ) ) {
			foreach ( $loadedAddons as $addon ) {
				if ( isset( $addon->helpers ) && method_exists( $addon->helpers, 'getVueData' ) ) {
					$data = $addon->helpers->getVueData( $data, $page, isset( $post ) ? $post : null );
				}
			}
		}

		return $data;
	}

	/**
	 * Returns Jed-formatted localization data. Added for backwards-compatibility.
	 *
	 * @since 4.0.0
	 *
	 * @param  string $domain Translation domain.
	 * @return array          The information of the locale.
	 */
	public function getJedLocaleData( $domain ) {
		$translations = get_translations_for_domain( $domain );

		$locale = [
			'' => [
				'domain' => $domain,
				'lang'   => is_admin() && function_exists( 'get_user_locale' ) ? get_user_locale() : get_locale(),
			],
		];

		if ( ! empty( $translations->headers['Plural-Forms'] ) ) {
			$locale['']['plural_forms'] = $translations->headers['Plural-Forms'];
		}

		foreach ( $translations->entries as $msgid => $entry ) {
			$locale[ $msgid ] = $entry->translations;
		}

		// If any of the translated strings incorrectly contains HTML line breaks, we need to return or else the admin is no longer accessible.
		$json = wp_json_encode( $locale );
		if ( preg_match( '/<br[\s\/\\\\]*>/', $json ) ) {
			return [];
		}

		return $locale;
	}

	/**
	 * Extracts existing sitemap URLs from the robots.txt file.
	 *
	 * We need this in case users have existing sitemap directives added to their robots.txt file.
	 *
	 * @since 4.0.10
	 *
	 * @return array An array with robots.txt sitemap directives.
	 */
	private function extractSitemapUrlsFromRobotsTxt() {
		// First, we need to remove our filter, so that it doesn't run unintentionally.
		remove_filter( 'robots_txt', [ aioseo()->robotsTxt, 'buildRules' ], 10000 );
		$robotsTxt = apply_filters( 'robots_txt', '', true );
		add_filter( 'robots_txt', [ aioseo()->robotsTxt, 'buildRules' ], 10000, 2 );

		if ( ! $robotsTxt ) {
			return [];
		}

		$lines = explode( "\n", $robotsTxt );
		if ( ! is_array( $lines ) || ! count( $lines ) ) {
			return [];
		}

		return aioseo()->robotsTxt->extractSitemapUrls( explode( "\n", $robotsTxt ) );
	}
}