- WordPress core y plugins - Tema Twenty Twenty-Four configurado - Plugin allow-unfiltered-html.php simplificado - .gitignore configurado para excluir wp-config.php y uploads 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
488 lines
14 KiB
PHP
Executable File
488 lines
14 KiB
PHP
Executable File
<?php // phpcs:ignoreFile
|
|
|
|
use AdvancedAds\Framework\Utilities\Params;
|
|
use AdvancedAds\Utilities\Conditional;
|
|
|
|
/**
|
|
* User interface for managing the 'ads.txt' file.
|
|
*/
|
|
class Advanced_Ads_Ads_Txt_Admin {
|
|
/**
|
|
* Ads.txt data management class
|
|
*
|
|
* @var Advanced_Ads_Ads_Txt_Strategy
|
|
*/
|
|
private $strategy;
|
|
|
|
/**
|
|
* Ads.txt frontend logic class
|
|
*
|
|
* @var Advanced_Ads_Ads_Txt_Public
|
|
*/
|
|
private $public;
|
|
|
|
/**
|
|
* AdSense network ID.
|
|
*/
|
|
const adsense = 'adsense';
|
|
|
|
const ACTION = 'wp_ajax_advads-ads-txt';
|
|
|
|
/**
|
|
* Whether the notices should be updated via AJAX because no cached data exists.
|
|
*
|
|
* @var bool
|
|
*/
|
|
private $notices_are_stale = false;
|
|
|
|
/**
|
|
* Constructor
|
|
*
|
|
* @param Advanced_Ads_Ads_Txt_Strategy $strategy Ads.txt data management class.
|
|
* @param Advanced_Ads_Ads_Txt_Public $public Ads.txt frontend logic class.
|
|
*/
|
|
public function __construct( Advanced_Ads_Ads_Txt_Strategy $strategy, Advanced_Ads_Ads_Txt_Public $public ) {
|
|
$this->strategy = $strategy;
|
|
$this->public = $public;
|
|
|
|
add_filter( 'advanced-ads-sanitize-settings', [ $this, 'toggle' ], 10, 1 );
|
|
add_action( 'pre_update_option_advanced-ads-adsense', [ $this, 'update_adsense_option' ], 10, 2 );
|
|
add_action( 'advanced-ads-settings-init', [ $this, 'add_settings' ] );
|
|
add_action( self::ACTION, [ $this, 'ajax_refresh_notices' ] );
|
|
}
|
|
|
|
|
|
/**
|
|
* Toggle ads.txt and add additional content.
|
|
*
|
|
* @param array $options Options.
|
|
* @return array $options Options.
|
|
*/
|
|
public function toggle( $options ) {
|
|
// phpcs:disable WordPress.Security.NonceVerification.Missing
|
|
$create = ! empty( Params::post( 'advads-ads-txt-create' ) );
|
|
$all_network = ! empty( Params::post( 'advads-ads-txt-all-network' ) );
|
|
$additional_content = trim( wp_unslash( Params::post( 'advads-ads-txt-additional-content', '' ) ) );
|
|
// phpcs:enable
|
|
|
|
$this->strategy->toggle( $create, $all_network, $additional_content );
|
|
$content = $this->get_adsense_blog_data();
|
|
$this->strategy->add_network_data( self::adsense, $content );
|
|
$r = $this->strategy->save_options();
|
|
|
|
if ( is_wp_error( $r ) ) {
|
|
add_settings_error(
|
|
'advanced-ads-adsense',
|
|
'adsense-ads-txt-created',
|
|
$r->get_error_message(),
|
|
'error'
|
|
);
|
|
}
|
|
|
|
return $options;
|
|
}
|
|
|
|
/**
|
|
* Update the 'ads.txt' file every time the AdSense settings are saved.
|
|
* The reason for not using `update_option_*` filter is that the function
|
|
* should also get called for newly added AdSense options.
|
|
*
|
|
* @param array $prev Previous options.
|
|
* @return array $new New options.
|
|
*/
|
|
public function update_adsense_option( $new, $prev ) {
|
|
if ( $new === $prev ) {
|
|
return $new;
|
|
}
|
|
$content = $this->get_adsense_blog_data( $new );
|
|
$this->strategy->add_network_data( self::adsense, $content );
|
|
$r = $this->strategy->save_options();
|
|
|
|
if ( is_wp_error( $r ) ) {
|
|
add_settings_error(
|
|
'advanced-ads-adsense',
|
|
'adsense-ads-txt-created',
|
|
$r->get_error_message(),
|
|
'error'
|
|
);
|
|
}
|
|
return $new;
|
|
}
|
|
|
|
/**
|
|
* Add setting fields.
|
|
*
|
|
* @param string $hook The slug-name of the settings page.
|
|
*/
|
|
public function add_settings( $hook ) {
|
|
$adsense_data = Advanced_Ads_AdSense_Data::get_instance();
|
|
$adsense_id = $adsense_data->get_adsense_id();
|
|
|
|
add_settings_section(
|
|
'advanced_ads_ads_txt_setting_section',
|
|
'ads.txt',
|
|
[ $this, 'render_ads_txt_section_callback' ],
|
|
$hook
|
|
);
|
|
|
|
add_settings_field(
|
|
'adsense-ads-txt-enable',
|
|
'',
|
|
[ $this, 'render_setting_toggle' ],
|
|
$hook,
|
|
'advanced_ads_ads_txt_setting_section'
|
|
);
|
|
|
|
add_settings_field(
|
|
'adsense-ads-txt-content',
|
|
'',
|
|
[ $this, 'render_setting_additional_content' ],
|
|
$hook,
|
|
'advanced_ads_ads_txt_setting_section'
|
|
);
|
|
}
|
|
|
|
public function render_ads_txt_section_callback() {}
|
|
|
|
/**
|
|
* Render toggle settings.
|
|
*/
|
|
public function render_setting_toggle() {
|
|
global $current_blog;
|
|
$domain = isset( $current_blog->domain ) ? $current_blog->domain : '';
|
|
|
|
$can_process_all_network = $this->can_process_all_network();
|
|
$is_all_network = $this->strategy->is_all_network();
|
|
|
|
$is_enabled = $this->strategy->is_enabled();
|
|
include dirname( __FILE__ ) . '/views/setting-create.php';
|
|
}
|
|
|
|
/**
|
|
* Render additional content settings.
|
|
*/
|
|
public function render_setting_additional_content() {
|
|
$content = $this->strategy->get_additional_content();
|
|
$notices = $this->get_notices();
|
|
$notices = $this->get_notices_markup( $notices );
|
|
|
|
$link = home_url( '/' ) . 'ads.txt';
|
|
$adsense_line = $this->get_adsense_blog_data();
|
|
include dirname( __FILE__ ) . '/views/setting-additional-content.php';
|
|
}
|
|
|
|
/**
|
|
* Check if other sites of the network can be processed by the user.
|
|
*
|
|
* @return bool
|
|
*/
|
|
private function can_process_all_network() {
|
|
return ! Advanced_Ads_Ads_Txt_Utils::is_subdir()
|
|
&& is_super_admin()
|
|
&& is_multisite();
|
|
}
|
|
|
|
/**
|
|
* Get notices.
|
|
*
|
|
* @return array Array of notices.
|
|
*/
|
|
public function get_notices() {
|
|
$url = home_url( '/' );
|
|
$parsed_url = wp_parse_url( $url );
|
|
$notices = [];
|
|
|
|
if ( ! isset( $parsed_url['scheme'] ) || ! isset ( $parsed_url['host'] ) ) {
|
|
return $notices;
|
|
}
|
|
|
|
$link = sprintf( '<a href="%1$s" target="_blank">%1$s</a>', esc_url( $url . 'ads.txt' ) );
|
|
$button = ' <button type="button" class="advads-ads-txt-action button" style="vertical-align: middle;" id="%s">%s</button>';
|
|
|
|
if ( ! $this->strategy->is_enabled() ) {
|
|
return $notices;
|
|
}
|
|
|
|
if ( Advanced_Ads_Ads_Txt_Utils::is_subdir() ) {
|
|
$notices[] = [
|
|
'advads-error-message',
|
|
sprintf(
|
|
/* translators: %s homepage link */
|
|
esc_html__( 'The ads.txt file cannot be placed because the URL contains a subdirectory. You need to make the file available at %s', 'advanced-ads' ),
|
|
sprintf( '<a href="%1$s" target="_blank">%1$s</a>', esc_url( $parsed_url['scheme'] . '://' . $parsed_url['host'] ) )
|
|
),
|
|
];
|
|
} else {
|
|
if ( null === ( $file = $this->get_notice( 'get_file_info', $url ) ) ) {
|
|
$this->notices_are_stale = true;
|
|
return $notices;
|
|
}
|
|
|
|
if ( ! is_wp_error( $file ) ) {
|
|
if ( $file['exists'] ) {
|
|
$notices[] = [
|
|
'',
|
|
sprintf(
|
|
/* translators: %s link of ads.txt */
|
|
esc_html__( 'The file is available on %s.', 'advanced-ads' ),
|
|
$link
|
|
),
|
|
];
|
|
} else {
|
|
$notices[] = [ '', esc_html__( 'The file was not created.', 'advanced-ads' ) ];
|
|
}
|
|
|
|
if ( $file['is_third_party'] ) {
|
|
/* translators: %s link */
|
|
$message = sprintf( esc_html__( 'A third-party file exists: %s', 'advanced-ads' ), $link );
|
|
|
|
if ( $this->can_edit_real_file() ) {
|
|
$message .= sprintf( $button, 'advads-ads-txt-remove-real', __( 'Import & Replace', 'advanced-ads' ) );
|
|
$message .= '<p class="description">'
|
|
. __( 'Move the content of the existing ads.txt file into Advanced Ads and remove it.', 'advanced-ads' )
|
|
. '</p>';
|
|
}
|
|
$notices['is_third_party'] = [ 'advads-error-message', $message ];
|
|
}
|
|
} else {
|
|
$notices[] = [
|
|
'advads-error-message',
|
|
sprintf(
|
|
/* translators: %s is replaced with an error message. */
|
|
esc_html__( 'An error occured: %s.', 'advanced-ads' ),
|
|
esc_html( $file->get_error_message() )
|
|
),
|
|
];
|
|
}
|
|
|
|
$need_file_on_root_domain = $this->get_notice( 'need_file_on_root_domain', $url );
|
|
if ( null === $need_file_on_root_domain ) {
|
|
$this->notices_are_stale = true;
|
|
return $notices;
|
|
}
|
|
|
|
if ( $need_file_on_root_domain ) {
|
|
$notices[] = [
|
|
'advads-ads-txt-nfor',
|
|
sprintf(
|
|
/* translators: %s the line that may need to be added manually */
|
|
esc_html__( 'If your site is located on a subdomain, you need to add the following line to the ads.txt file of the root domain: %s', 'advanced-ads' ),
|
|
// Without http://.
|
|
'<code>subdomain=' . esc_html( $parsed_url['host'] ) . '</code>'
|
|
),
|
|
];
|
|
}
|
|
}
|
|
|
|
return $notices;
|
|
}
|
|
|
|
/**
|
|
* Get HTML markup of the notices.
|
|
*
|
|
* @param array $notices Notices.
|
|
* @return string $r HTML markup.
|
|
*/
|
|
private function get_notices_markup( $notices ) {
|
|
if ( $this->notices_are_stale ) {
|
|
// Do not print `ul` to fetch notices via AJAX.
|
|
return '';
|
|
}
|
|
|
|
$r = '<ul id="advads-ads-txt-notices">';
|
|
foreach ( $notices as $notice ) {
|
|
$r .= sprintf( '<li class="%s">%s</li>', $notice[0], $notice[1] );
|
|
}
|
|
$r .= '</ul>';
|
|
return $r;
|
|
}
|
|
|
|
/**
|
|
* Check if the `ads.txt` file is displayed to visitors.
|
|
*
|
|
* @return bool True if displayed, False otherwise.
|
|
*/
|
|
public static function is_displayed() {
|
|
$url = home_url( '/' );
|
|
|
|
$file = self::get_notice( 'get_file_info', $url );
|
|
return is_array( $file ) && ! empty( $file['exists'] );
|
|
}
|
|
|
|
/**
|
|
* Get a notice.
|
|
*
|
|
* @return null/bool Boolean on success or null if no cached data exists.
|
|
* In the latter case, this function should be called using AJAX
|
|
* to get fresh data.
|
|
*/
|
|
public static function get_notice( $func, $url ) {
|
|
if ( ! method_exists( 'Advanced_Ads_Ads_Txt_Utils', $func ) ) {
|
|
return false;
|
|
}
|
|
|
|
$url = $url ? $url : home_url( '/' );
|
|
$key = self::get_transient_key();
|
|
$transient = get_transient( $key );
|
|
|
|
if ( ! wp_doing_ajax() || ! doing_action( self::ACTION ) ) {
|
|
return isset( $transient[ $func ] ) ? $transient[ $func ] : null;
|
|
}
|
|
|
|
$r = call_user_func( [ 'Advanced_Ads_Ads_Txt_Utils', $func ], $url );
|
|
|
|
$transient = is_array( $transient ) ? $transient : [];
|
|
$transient[ $func ] = $r;
|
|
set_transient( $key, $transient, WEEK_IN_SECONDS );
|
|
return $r;
|
|
}
|
|
|
|
/**
|
|
* Get Adsense data.
|
|
*
|
|
* @param array $new New data.
|
|
*
|
|
* @return string
|
|
*/
|
|
public function get_adsense_blog_data( $new = null ) {
|
|
if ( null === $new ) {
|
|
$new = Advanced_Ads_AdSense_Data::get_instance()->get_options();
|
|
}
|
|
|
|
$adsense_id = ! empty( $new['adsense-id'] ) ? trim( $new['adsense-id'] ) : '';
|
|
if ( ! $adsense_id ) {
|
|
return '';
|
|
}
|
|
|
|
$data = [
|
|
'domain' => 'google.com',
|
|
'account_id' => $adsense_id,
|
|
'account_type' => 'DIRECT',
|
|
'certification_authority' => 'f08c47fec0942fa0',
|
|
];
|
|
$result = implode( ', ', $data );
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Check if a third-party ads.txt file exists.
|
|
*/
|
|
public function ajax_refresh_notices() {
|
|
|
|
check_ajax_referer( 'advanced-ads-admin-ajax-nonce', 'nonce' );
|
|
|
|
if ( ! Conditional::user_can( 'advanced_ads_manage_options' ) ) {
|
|
return;
|
|
}
|
|
|
|
$response = [];
|
|
$action_notices = [];
|
|
|
|
$request_type = Params::request( 'type' );
|
|
if ( $request_type ) {
|
|
if ( 'remove_real_file' === $request_type ) {
|
|
$remove = $this->remove_real_file();
|
|
if ( is_wp_error( $remove ) ) {
|
|
$action_notices[] = [ 'advads-ads-txt-updated advads-notice-inline advads-error', $remove->get_error_message() ];
|
|
} else {
|
|
$action_notices[] = [
|
|
'advads-ads-txt-updated',
|
|
__( 'The ads.txt is now managed with Advanced Ads.', 'advanced-ads' )
|
|
];
|
|
$options = $this->strategy->get_options();
|
|
$response['additional_content'] = esc_textarea( $options['custom'] );
|
|
}
|
|
}
|
|
|
|
if ( 'create_real_file' === $request_type ) {
|
|
$action_notices[] = $this->create_real_file();
|
|
}
|
|
}
|
|
|
|
$notices = $this->get_notices();
|
|
$notices = array_merge( $notices, $action_notices );
|
|
$response['notices'] = $this->get_notices_markup( $notices );
|
|
|
|
wp_send_json( $response );
|
|
}
|
|
|
|
/**
|
|
* Connect to the filesystem.
|
|
*/
|
|
private function fs_connect() {
|
|
global $wp_filesystem;
|
|
$fs_connect = Advanced_Ads_Filesystem::get_instance()->fs_connect( [ ABSPATH ] );
|
|
|
|
if ( false === $fs_connect || is_wp_error( $fs_connect ) ) {
|
|
$message = __( 'Unable to connect to the filesystem. Please confirm your credentials.', 'advanced-ads' );
|
|
|
|
if ( $wp_filesystem instanceof WP_Filesystem_Base && is_wp_error( $wp_filesystem->errors ) && $wp_filesystem->errors->get_error_code() ) {
|
|
$message = esc_html( $wp_filesystem->errors->get_error_message() );
|
|
}
|
|
if ( is_wp_error( $fs_connect ) && $fs_connect->get_error_code() ) {
|
|
$message = esc_html( $fs_connect->get_error_message() );
|
|
}
|
|
return new WP_Error( 'can_not_connect', $message );
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Remove existing real ads.txt file.
|
|
*/
|
|
public function remove_real_file() {
|
|
global $wp_filesystem;
|
|
|
|
if ( ! $this->can_edit_real_file() ) {
|
|
return new WP_Error( 'not_main_site', __( 'Not the main blog', 'advanced-ads' ) );
|
|
}
|
|
|
|
$fs_connect = $this->fs_connect();
|
|
if ( is_wp_error( $fs_connect ) ) {
|
|
return $fs_connect;
|
|
}
|
|
|
|
$abspath = trailingslashit( $wp_filesystem->abspath() );
|
|
$file = $abspath . 'ads.txt';
|
|
if ( $wp_filesystem->exists( $file ) && $wp_filesystem->is_file( $file ) ) {
|
|
$data = $wp_filesystem->get_contents( $file );
|
|
|
|
$tp_file = new Advanced_Ads_Ads_Txt_Real_File();
|
|
$tp_file->parse_file( $data );
|
|
|
|
$aa_data = $this->public->get_frontend_output();
|
|
$aa_file = new Advanced_Ads_Ads_Txt_Real_File();
|
|
$aa_file->parse_file( $aa_data );
|
|
|
|
$tp_file->subtract( $aa_file );
|
|
$output = $tp_file->output();
|
|
$this->strategy->set_additional_content( $output );
|
|
$this->strategy->save_options();
|
|
|
|
if ( $wp_filesystem->delete( $file ) ) {
|
|
return true;
|
|
} else {
|
|
return new WP_Error( 'could_not_delete', __( 'Could not delete the existing ads.txt file', 'advanced-ads' ) );
|
|
}
|
|
} else {
|
|
return new WP_Error( 'not_found', __( 'Could not find the existing ads.txt file', 'advanced-ads' ) );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if the user is alowed to edit real file.
|
|
*/
|
|
private function can_edit_real_file() {
|
|
return is_super_admin();
|
|
}
|
|
|
|
|
|
/**
|
|
* Get transient key.
|
|
*/
|
|
public static function get_transient_key() {
|
|
return 'advanced_ads_ads_txt_ctp' . home_url( '/') ;
|
|
}
|
|
}
|