file = $file; self::$instance->version = get_plugin_data( self::$instance->file, false, false )['Version'] ?? ''; self::$instance->setup_constants(); self::$instance->load_textdomain(); self::$instance->includes(); self::$instance->hooks(); self::$instance->functions = new AffiliateWP_Affiliate_Area_Tabs_Functions(); } return self::$instance; } /** * Throw error on object clone * * The whole idea of the singleton design pattern is that there is a single * object therefore, we don't want the object to be cloned. * * @since 1.0.0 * @access protected * @return void */ public function __clone() { // Cloning instances of the class is forbidden. _doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin’ huh?', 'affiliatewp-affiliate-area-tabs' ), '1.0' ); } /** * Disable unserializing of the class * * @since 1.0.0 * @access protected * @return void */ public function __wakeup() { // Unserializing instances of the class is forbidden. _doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin’ huh?', 'affiliatewp-affiliate-area-tabs' ), '1.0' ); } /** * Constructor Function * * @since 1.0.0 * @access private */ private function __construct() { self::$instance = $this; } /** * Reset the instance of the class * * @since 1.0.0 * @access public * @static */ public static function reset() { self::$instance = null; } /** * Setup plugin constants * * @access private * @since 1.0.0 * @return void */ private function setup_constants() { // Plugin version. if ( ! defined( 'AFFWP_AAT_VERSION' ) ) { define( 'AFFWP_AAT_VERSION', $this->version ); } // Plugin Folder Path. if ( ! defined( 'AFFWP_AAT_PLUGIN_DIR' ) ) { define( 'AFFWP_AAT_PLUGIN_DIR', plugin_dir_path( $this->file ) ); } // Plugin Folder URL. if ( ! defined( 'AFFWP_AAT_PLUGIN_URL' ) ) { define( 'AFFWP_AAT_PLUGIN_URL', plugin_dir_url( $this->file ) ); } // Plugin Root File. if ( ! defined( 'AFFWP_AAT_PLUGIN_FILE' ) ) { define( 'AFFWP_AAT_PLUGIN_FILE', $this->file ); } } /** * Loads the plugin language files * * @access public * @since 1.0.0 * @return void */ public function load_textdomain() { // Set filter for plugin's languages directory. $lang_dir = dirname( plugin_basename( $this->file ) ) . '/languages/'; $lang_dir = apply_filters( 'affiliatewp_affiliate_area_tabs_languages_directory', $lang_dir ); // Traditional WordPress plugin locale filter. $locale = apply_filters( 'plugin_locale', get_locale(), 'affiliatewp-affiliate-area-tabs' ); $mofile = sprintf( '%1$s-%2$s.mo', 'affiliatewp-affiliate-area-tabs', $locale ); // Setup paths to current locale file. $mofile_local = $lang_dir . $mofile; $mofile_global = WP_LANG_DIR . '/affiliatewp-affiliate-area-tabs/' . $mofile; if ( file_exists( $mofile_global ) ) { // Look in global /wp-content/languages/affiliatewp-affiliate-area-tabs/ folder. load_textdomain( 'affiliatewp-affiliate-area-tabs', $mofile_global ); } elseif ( file_exists( $mofile_local ) ) { // Look in local /wp-content/plugins/affiliatewp-affiliate-area-tabs/languages/ folder. load_textdomain( 'affiliatewp-affiliate-area-tabs', $mofile_local ); } else { // Load the default language files. load_plugin_textdomain( 'affiliatewp-affiliate-area-tabs', false, $lang_dir ); } } /** * Include necessary files * * @access private * @since 1.0.0 * @return void */ private function includes() { // Functions class. require_once AFFWP_AAT_PLUGIN_DIR . 'includes/class-functions.php'; // Upgrade class. require_once AFFWP_AAT_PLUGIN_DIR . 'includes/class-upgrades.php'; /** * Compatibility class. * This provides compatibility with AffiliateWP v1.8 - v2.1.6.1 */ if ( $this->has_1_8() && ! $this->has_2_1_7() ) { require_once AFFWP_AAT_PLUGIN_DIR . 'includes/class-compatibility.php'; } // Admin class. if ( is_admin() ) { require_once AFFWP_AAT_PLUGIN_DIR . 'includes/class-admin.php'; } } /** * Setup the default hooks and actions * * @since 1.0.0 * * @return void */ private function hooks() { // plugin meta. add_filter( 'plugin_row_meta', [ $this, 'plugin_meta' ], null, 2 ); // Render the tab content. add_filter( 'affwp_render_affiliate_dashboard_tab', [ $this, 'render_custom_tab' ], 10, 2 ); // Redirect if non-affiliate tries to access a tab's page. add_action( 'template_redirect', [ $this, 'redirect' ] ); // Apply the same restriction to every non-front-end reader, since template_redirect // does not fire for REST or sitemap requests. add_filter( 'rest_page_query', [ $this, 'exclude_protected_pages' ], 10, 2 ); add_filter( 'rest_prepare_page', [ $this, 'gate_protected_page_response' ], 10, 2 ); add_filter( 'wp_sitemaps_posts_query_args', [ $this, 'exclude_protected_from_sitemap' ], 10, 2 ); // User has at least AffiliateWP version 2.1.7. if ( $this->has_2_1_7() ) { /** * Filter the tabs in the Affiliate Area and in the admin. * * @since 1.1 * @since 1.2 Increased priority to 9999 so we can better listen for other tabs being added. E.g. Direct Link Tracking. */ add_filter( 'affwp_affiliate_area_tabs', [ $this, 'affiliate_area_tabs' ], 9999 ); } // Hide tabs in the Affiliate Area. add_filter( 'affwp_affiliate_area_show_tab', [ $this, 'hide_existing_tabs' ], 10, 2 ); } /** * Filter an existing tab's content * * @since 1.1.2 * @param string $content The tab content. * @param string $active_tab The slug of the active tab. * * @return string $content The content to show in the tab. */ public function render_custom_tab( $content, $active_tab ) { if ( ! $this->functions->is_custom_tab( $active_tab ) ) { // Not a custom tab, return the content. return $content; } // Only active affiliates (or admins) may read custom-tab content. if ( ! $this->viewer_may_read_tab_pages() ) { return $content; } // Get the tab's content. $content = $this->custom_tab_content( $active_tab ); // Return the $content. return $content; } /** * The custom tab's content. * * @since 1.1.2 * @param string $active_tab The slug of the active tab. * * @return void */ public function custom_tab_content( $active_tab ) { ?>
functions->get_custom_tab_content( $active_tab ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Page content, rendered like the_content. ?>
settings->get( 'affiliate_area_tabs', [] ); if ( $tabs ) { foreach ( $tabs as $key => $tab_array ) { if ( isset( $tab_array['slug'] ) && $tab_array['slug'] === $tab && ( isset( $tab_array['hide'] ) && 'yes' === $tab_array['hide'] ) ) { $show = false; } } } return $show; } /** * Affiliate Area Tabs. * * @since 1.2 * * @param array $tabs Array of tabs. * @return array $tabs The tabs to show in the Affiliate Area */ public function affiliate_area_tabs( $tabs ) { // Get the Affiliate Area Tabs. $affiliate_area_tabs = affiliate_wp()->settings->get( 'affiliate_area_tabs' ); if ( $affiliate_area_tabs ) { $new_tabs = []; $saved_tab_slugs = []; // Create a new array in the needed format of tab slug => tab title. foreach ( $affiliate_area_tabs as $key => $tab ) { if ( isset( $tab['slug'] ) ) { $new_tabs[ $tab['slug'] ] = $tab['title']; /** * If the saved tab slug exists inside $affiliate_area_tabs, but not in $tabs (tabs from filter), * and it's not a custom tab added via the admin then it should be unset from $affiliate_area_tabs immediately. */ if ( ! array_key_exists( $tab['slug'], $tabs ) && ! $this->functions->is_custom_tab( $tab['slug'] ) ) { /** * Tabs added by add-ons should always be visible in the admin tab list * and only visible in the Affiliate Area if the affiliate has access. */ if ( array_key_exists( $tab['slug'], $this->functions->add_on_tabs() ) && ! is_admin() ) { unset( $new_tabs[ $tab['slug'] ] ); } else { unset( $new_tabs[ $tab['slug'] ] ); } } // Store an array of tab slugs. $saved_tab_slugs[] = $tab['slug']; } } /** * If the tab slug exists in $tabs (added via filter), but not in $affiliate_area_tabs (because its already been saved), * and the tab slug isn't a custom tab (it's ID will be 0), append the tab to the end of $affiliate_area_tabs. * That way it can be re-ordered by admin and saved into its new location. */ foreach ( $tabs as $tab_slug => $tab_title ) { if ( ! in_array( $tab_slug, $saved_tab_slugs ) && ! $this->functions->is_custom_tab( $tab_slug ) ) { $new_tabs[ $tab_slug ] = $tab_title; } } return $new_tabs; } return $tabs; } /** * Determine if the user is on version 1.8 of AffiliateWP or newer * * @since 1.1 * * @return boolean */ public function has_1_8() { $return = true; if ( version_compare( AFFILIATEWP_VERSION, '1.8', '<' ) ) { $return = false; } return $return; } /** * Determine if the user is on version 2.1.7 of AffiliateWP or later. * * @since 1.2 * * @return boolean */ public function has_2_1_7() { $return = true; if ( version_compare( AFFILIATEWP_VERSION, '2.1.7', '<' ) ) { $return = false; } return $return; } /** * Determine if the user is on version 2.6 of AffiliateWP or later. * * @since 1.2.9 * * @return boolean */ public function has_2_6() { $return = true; if ( version_compare( AFFILIATEWP_VERSION, '2.6', '<' ) ) { $return = false; } return $return; } /** * Determines if the post content has blocks. * * @since 1.2.9 * * @param string $post_content Post content. * @return bool True if the post content has blocks, otherwise false. */ public function has_blocks( $post_content ) { $return = true; if ( ! function_exists( 'has_blocks' ) || ! has_blocks( $post_content ) ) { $return = false; } return $return; } /** * Redirect to affiliate login page if content is accessed. * * @since 1.0.1 * @return void */ public function redirect() { $protected = (array) affiliatewp_affiliate_area_tabs()->functions->protected_page_ids(); if ( empty( $protected ) ) { return; } // On archives the queried object is a term or user whose ID can collide with a page ID. if ( ! is_singular() ) { return; } $post_id = get_queried_object_id(); if ( ! in_array( (int) $post_id, array_map( 'absint', $protected ), true ) ) { return; } if ( $this->viewer_may_read_tab_pages() ) { return; } $redirect = affiliate_wp()->settings->get( 'affiliates_page' ) ? get_permalink( affiliate_wp()->settings->get( 'affiliates_page' ) ) : site_url(); $redirect = apply_filters( 'affiliatewp-affiliate-area-tabs', $redirect ); wp_safe_redirect( $redirect ); exit; } /** * Whether the current viewer may read the pages backing custom tabs. * * Matches the rule AffiliateWP applies to the Affiliate Area dashboard: active affiliates * only. Administrators are allowed through so the page stays editable and previewable. * * @since 1.4.3 * * @return bool */ public function viewer_may_read_tab_pages() { if ( current_user_can( 'manage_affiliate_options' ) ) { return true; } return affwp_is_affiliate() && affwp_is_active_affiliate(); } /** * Removes protected tab pages from REST collection queries for viewers who may not read them. * * @since 1.4.3 * * @param array $args Query args. * @param \WP_REST_Request $request REST request. * @return array */ public function exclude_protected_pages( $args, $request ) { $protected = (array) affiliatewp_affiliate_area_tabs()->functions->protected_page_ids(); // Editors, shop managers and other page editors still need the page in the block editor. if ( empty( $protected ) || $this->viewer_may_read_tab_pages() || current_user_can( 'edit_pages' ) ) { return $args; } $args['post__not_in'] = array_merge( (array) ( isset( $args['post__not_in'] ) ? $args['post__not_in'] : array() ), array_map( 'absint', $protected ) ); return $args; } /** * Strips a protected tab page's body from any REST response for viewers who may not read it. * * @since 1.4.3 * * @param \WP_REST_Response $response Response. * @param \WP_Post $post Post. * @return \WP_REST_Response */ public function gate_protected_page_response( $response, $post ) { $protected = (array) affiliatewp_affiliate_area_tabs()->functions->protected_page_ids(); if ( ! in_array( (int) $post->ID, array_map( 'absint', $protected ), true ) || $this->viewer_may_read_tab_pages() || current_user_can( 'edit_post', $post->ID ) ) { return $response; } $data = $response->get_data(); foreach ( array( 'content', 'excerpt' ) as $field ) { if ( isset( $data[ $field ] ) ) { $data[ $field ] = array( 'rendered' => '', 'protected' => true ); } } $response->set_data( $data ); return $response; } /** * Keeps protected tab pages out of the sitemap. * * @since 1.4.3 * * @param array $args Query args. * @param string $post_type Post type. * @return array */ public function exclude_protected_from_sitemap( $args, $post_type ) { if ( 'page' !== $post_type ) { return $args; } $args['post__not_in'] = array_merge( (array) ( isset( $args['post__not_in'] ) ? $args['post__not_in'] : array() ), array_map( 'absint', (array) affiliatewp_affiliate_area_tabs()->functions->protected_page_ids() ) ); return $args; } /** * Modify plugin metalinks. * * @access public * @since 1.0.0 * @param array $links The current links array. * @param string $file A specific plugin table entry. * @return array $links The modified links array */ public function plugin_meta( $links, $file ) { if ( plugin_basename( $this->file ) === $file ) { $plugins_link = [ '' . __( 'More add-ons', 'affiliatewp-affiliate-area-tabs' ) . '', ]; $links = array_merge( $links, $plugins_link ); } return $links; } } /** * The main function responsible for returning the one true AffiliateWP_Affiliate_Area_Tabs * Instance to functions everywhere. * * Use this function like you would a global variable, except without needing * to declare the global. * * Example: * * @since 1.0 * @return object The one true AffiliateWP_Affiliate_Area_Tabs Instance */ function affiliatewp_affiliate_area_tabs() { return AffiliateWP_Affiliate_Area_Tabs::instance(); } }