<?php
/**
 * Provides compatibility with Yoast SEO
 * 
 * @package  Page Generator Pro
 * @author   Tim Carr
 * @version  2.9.0
 */
class Page_Generator_Pro_Yoast_SEO {

    /**
     * Holds the base object.
     *
     * @since   2.9.0
     *
     * @var     object
     */
    public $base;

    /**
     * Constructor
     * 
     * @since   2.9.0
     *
     * @param   object $base    Base Plugin Class
     */
    public function __construct( $base ) {

        // Store base class
        $this->base = $base;

    	// Deprecated for Yoast SEO 10.0+, which simply inherits the Permalink of the Post
        // @TODO Can we safely remove this?
        add_filter( 'wpseo_sanitize_post_meta__yoast_wpseo_canonical', array( $this, 'wpseo_sanitize_post_meta__yoast_wpseo_canonical' ), 10, 4 );

        // Content Groups: Add Overwrite Section if Yoast SEO enabled
        add_filter( 'page_generator_pro_common_get_content_overwrite_sections', array( $this, 'add_overwrite_section' ) );

        // Content Groups: Ignore Yoast SEO meta keys if overwriting is disabled for Yoast SEO
        add_filter( 'page_generator_pro_generate_set_post_meta_ignored_keys', array( $this, 'prevent_post_meta_copy_to_generated_content' ), 10, 4 );

        // Term Groups: Fetch Term Meta, which is stored in wp_options, not wp_termmeta
        add_filter( 'page_generator_pro_groups_terms_get_term_meta', array( $this, 'groups_terms_get_term_meta' ), 10, 2 );

        // Term Groups: Ignore Yoast SEO meta keys
        add_filter( 'page_generator_pro_generate_set_term_meta_ignored_keys', array( $this, 'prevent_term_meta_copy_to_generated_term' ), 10, 4 );

        // Term Groups: Set Term Meta in Options, as that's where Yoast SEO stores it
        add_action( 'page_generator_pro_generate_set_term_meta', array( $this, 'groups_terms_set_term_meta' ), 10, 4 );

    }
      
    /**
     * When saving the Canonical URL field, revert Yoast SEO's sanitization, which strips curly braces
     *
     * @since   2.9.0
     *
     * @param   string  $clean          Sanitized Value
     * @param   string  $meta_value     Unsanitized Value
     * @param   array   $field_def      Meta Field Definition
     * @param   string  $meta_key       Meta Key
     * @return  string                  Value to save
     */
    public function wpseo_sanitize_post_meta__yoast_wpseo_canonical( $clean, $meta_value, $field_def, $meta_key ) {

        // Bail if no Post ID set
        if ( ! isset( $_POST['ID'] ) ) {
            return $clean;
        }

        // Get Post ID
        $group_id = absint( $_POST['ID'] );

        // Bail if not a Group
        if ( get_post_type( $group_id ) != $this->base->get_class( 'post_type' )->post_type_name ) {
            return $clean;
        }

        // Return non-sanitized value
        return $meta_value;

    }

    /**
     * Defines available content overwrite sections.
     *
     * @since   2.9.0
     *
     * @param   array   $sections    Content Overwrite Sections
     * @return  array                Content Overwrite Sections
     */
    public function add_overwrite_section( $sections ) {

        // Bail if Yoast SEO isn't active
        if ( ! $this->is_active() ) {
            return $sections;
        }

        // Add Yoast SEO
        $sections['yoast_seo'] = __( 'Yoast SEO', 'page-generator-pro' );

        // Return
        return $sections;

    }

    /**
     * Adds Yoast SEO Post Meta Keys to the array of excluded Post Meta Keys if Yoast SEO
     * metadata should not be overwritten on Content Generation
     *
     * @since   2.9.0
     *
     * @param   array   $ignored_keys   Ignored Keys (preg_match() compatible regex expressions are supported)
     * @param   int     $post_id        Generated Post ID
     * @param   array   $settings       Group Settings
     * @param   array   $post_args      wp_insert_post() / wp_update_post() arguments
     * @return  array   $ignored_keys   Ignored Keys
     */
    public function prevent_post_meta_copy_to_generated_content( $ignored_keys, $post_id, $settings, $post_args ) {

        // Determine if we want to create/replace Yoast SEO metdata
        $overwrite = ( isset( $post_args['ID'] ) && ! array_key_exists( 'yoast_seo', $settings['overwrite_sections'] ) ? false : true ); 

        // If overwriting is enabled, no need to exclude anything
        if ( $overwrite ) {
            return $ignored_keys;
        }

        // Add Yoast SEO Meta Keys so they are not overwritten on the Generated Post
        return array_merge( $ignored_keys, array(
            "/^_yoast_wpseo_(.*)/i"
        ) );

    }

    /**
     * When fetching a Term Group's metadata, Yoast SEO data won't be included, as it's stored
     * in wp_options, not wp_termmeta.
     *
     * This function fetches the Term Group's Yoast metadata, so it's available to the Term Group.
     *
     * @since   3.0.0
     *
     * @param   array   $meta   Metadata
     * @param   int     $id     Group ID
     * @return  array   $meta   Metadata
     */
    public function groups_terms_get_term_meta( $meta, $id ) {

        // Bail if Plugin isn't active
        if ( ! $this->is_active() ) {
            return $meta;
        }

        // Get Options data, which comprises of all Taxonomy Terms and their Metadata
        $yoast_taxonomy_meta = get_option( 'wpseo_taxonomy_meta' );
        
        // Bail if not an array
        if ( ! is_array( $yoast_taxonomy_meta ) ) {
            return $meta;
        }
        if ( ! count( $yoast_taxonomy_meta ) ) {
            return $meta;
        }

        // Bail if there's no Term Meta for any Term Group
        if ( ! isset( $yoast_taxonomy_meta['page-generator-tax'] ) ) {
            return $meta;
        }

        // Bail if there's no Term Meta for this Term Group
        if ( ! isset( $yoast_taxonomy_meta['page-generator-tax'][ $id ] ) ) {
            return $meta;
        }

        // If here, we have Term Meta for this Term Group
        // Return it
        return array_merge( $meta, $yoast_taxonomy_meta['page-generator-tax'][ $id ] );

    }

    /**
     * Adds Yoast SEO Term Meta Keys to the array of excluded Post Meta Keys if Yoast SEO
     * metadata should not be overwritten on Content Generation
     *
     * @since   3.0.0
     *
     * @param   array   $ignored_keys   Ignored Keys (preg_match() compatible regex expressions are supported)
     * @param   int     $post_id        Generated Post ID
     * @param   array   $settings       Group Settings
     * @param   array   $post_args      wp_insert_post() / wp_update_post() arguments
     * @return  array   $ignored_keys   Ignored Keys
     */
    public function prevent_term_meta_copy_to_generated_term( $ignored_keys, $post_id, $settings, $post_args ) {

        // Add Yoast SEO Meta Keys that are e.g. calculations, that should not be copied to the Generated Term
        return array_merge( $ignored_keys, array(
            'wpseo_linkdex',
            'wpseo_content_score',
        ) );

    }

    /**
     * Saves Term Meta for the Generated Term in the options table, as Yoast SEO requires it to be stored
     * there for Terms.
     *
     * @since   3.0.0
     *
     * @param   int     $term_id        Generated Term ID
     * @param   array   $term_meta      Group Term Meta
     * @param   array   $settings       Group Settings
     * @param   array   $term_args      wp_insert_term() / wp_update_term() arguments
     */
    public function groups_terms_set_term_meta( $term_id, $term_meta, $settings, $term_args ) {

        // Bail if Plugin isn't active
        if ( ! $this->is_active() ) {
            return;
        }

        // Iterate through meta, building the meta to store in the options array
        $options_term_meta = array();
        foreach ( $term_meta as $meta_key => $meta_value ) {
            // Skip if not a Yoast Meta Key
            if ( strpos( $meta_key, 'wpseo_' ) ) {
                continue;
            }

            $options_term_meta[ $meta_key ] = $meta_value;
        }

        // If no Term Meta exists, bail
        if ( empty( $options_term_meta ) || ! count( $options_term_meta ) ) {
            return;
        }

        // Get Options data, which comprises of all Taxonomy Terms and their Metadata
        $yoast_taxonomy_meta = get_option( 'wpseo_taxonomy_meta' );
        if ( ! is_array( $yoast_taxonomy_meta ) ) {
            $yoast_taxonomy_meta = array();
        }
        if ( ! isset( $yoast_taxonomy_meta[ $settings['taxonomy'] ] ) ) {
            $yoast_taxonomy_meta[ $settings['taxonomy'] ] = array();
        }

        // Overwrite existing Term Meta if it exists
        $yoast_taxonomy_meta[ $settings['taxonomy'] ][ $term_id ] = $options_term_meta;
        update_option( 'wpseo_taxonomy_meta', $yoast_taxonomy_meta );

    }

    /**
     * Checks if the Yoast SEO Plugin is active
     *
     * @since   2.9.0
     *
     * @return  bool    Yoast SEO Plugin Active
     */
    private function is_active() {

        // Assume Yoast SEO isn't active if we can't use WordPress' function
        if ( ! function_exists( 'is_plugin_active' ) ) {
            return false;
        }

        if ( is_plugin_active( 'wordpress-seo-premium/wp-seo-premium.php' ) ) {
            return true;
        }

        return is_plugin_active( 'wordpress-seo/wp-seo.php' );
        
    }

 }