Commit inicial - WordPress Análisis de Precios Unitarios

- 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>
This commit is contained in:
root
2025-11-03 21:04:30 -06:00
commit a22573bf0b
24068 changed files with 4993111 additions and 0 deletions

View File

@@ -0,0 +1,847 @@
<?php // phpcs:ignore WordPress.Files.FileName
/**
* Dashboard helper class
*
* @package AdvancedAds\Pro
* @author Advanced Ads <info@wpadvancedads.com>
*/
use AdvancedAds\Utilities\Conditional;
use AdvancedAds\Framework\Utilities\Params;
use GeoIp2\Exception\AddressNotFoundException;
/**
* WP Admin class for Geo Targeting.
*/
class Advanced_Ads_Geo_Admin {
/**
* Path to view files
*
* @var string
*/
private $views_path;
/**
* Initialize the plugin by loading admin scripts & styles and adding a
* settings page and menu.
*
* @since 1.0.0
*/
public function __construct() {
$this->views_path = plugin_dir_path( __FILE__ ) . '../admin/views';
add_action( 'advanced-ads-settings-init', [ $this, 'settings_init' ] );
// ajax request to download the database.
add_action( 'wp_ajax_advads_download_geolite_database', [ $this, 'download_database' ] );
// Add assets.
add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_admin_scripts' ] );
}
/**
* Add settings to settings page
*/
public function settings_init() {
// add new section.
add_settings_section(
'advanced_ads_geo_setting_section',
__( 'Geo Targeting', 'advanced-ads-pro' ),
'__return_empty_string',
Advanced_Ads_Pro::OPTION_KEY . '-settings'
);
// Add license key field.
add_settings_field(
'geo-maxmind-license-key',
__( 'MaxMind license key', 'advanced-ads-pro' ),
[ $this, 'render_settings_license_key_callback' ],
Advanced_Ads_Pro::OPTION_KEY . '-settings',
'advanced_ads_geo_setting_section'
);
// Add database field.
add_settings_field(
'geo-database-update',
__( 'MaxMind Database', 'advanced-ads-pro' ),
[ $this, 'render_settings_database' ],
Advanced_Ads_Pro::OPTION_KEY . '-settings',
'advanced_ads_geo_setting_section'
);
// add field for the targeting method.
if ( count( Advanced_Ads_Geo_Plugin::get_instance()->get_targeting_methods() ) > 1 ) {
add_settings_field(
'geo-license',
__( 'Method', 'advanced-ads-pro' ),
[ $this, 'render_settings_method_callback' ],
Advanced_Ads_Pro::OPTION_KEY . '-settings',
'advanced_ads_geo_setting_section'
);
}
// add assistant setting field.
add_settings_field(
'geo-locale',
__( 'Language of names', 'advanced-ads-pro' ),
[ $this, 'render_settings_locale_option_callback' ],
Advanced_Ads_Pro::OPTION_KEY . '-settings',
'advanced_ads_geo_setting_section'
);
}
/**
* Render MaxMind license key field.
*/
public function render_settings_license_key_callback() {
$use_filters = $this->is_using_custom_database();
$license_key = Advanced_Ads_Geo_Plugin::get_instance()->options( 'maxmind-license-key', '' );
include $this->views_path . '/setting-maxmind-license-key.php';
}
/**
* Render MaxMind database field.
*
* @return void
*/
public function render_settings_database() {
$last_update = get_option( ADVADS_SLUG . '-' . Advanced_Ads_Geo_Plugin::OPTIONS_SLUG . '-last-update-geolite2', false );
$next_update = $this->get_next_first_tuesday_timestamp();
// Check if the database files exist and do not contain errors.
$api = Advanced_Ads_Geo_Api::get_instance();
$correct_databases = $api->get_geo_ip2_city_reader() && $api->get_geo_ip2_country_reader();
$use_filters = $this->is_using_custom_database();
// Render download of the geo database.
include $this->views_path . '/setting-download.php';
}
/**
* Render option for the geo targeting method
*/
public function render_settings_method_callback() {
$method = Advanced_Ads_Geo_Plugin::get_instance()->options( 'method', 'default' );
$methods = Advanced_Ads_Geo_Plugin::get_instance()->get_targeting_methods();
include $this->views_path . '/setting-method.php';
}
/**
* Render option for language of the geo information
*/
public function render_settings_locale_option_callback() {
$locale = Advanced_Ads_Geo_Plugin::get_instance()->options( 'locale', 'en' );
include $this->views_path . '/setting-locale.php';
}
/**
* Allow static method call as visitor condition callback.
*
* @param string $name method name.
* @param mixed $arguments functions arguments.
*/
public static function __callStatic( $name, $arguments ) {
if ( 'metabox_geo' === $name ) {
( new self() )->metabox_geo( ...$arguments );
}
// else fail silently.
}
/**
* Add visitor condition box
*
* @param array $options ad options.
* @param int $index current index in conditions list.
* @param string $form_name form name of current condition.
*
* @return void
* @throws \MaxMind\Db\Reader\InvalidDatabaseException Corrupted DB files.
*/
private function metabox_geo( $options, $index = 0, $form_name = '' ) {
if ( empty( $options['type'] ) ) {
return;
}
$type_options = Advanced_Ads_Visitor_Conditions::get_instance()->conditions;
if ( ! isset( $type_options[ $options['type'] ] ) ) {
return;
}
$method = Advanced_Ads_Geo_Plugin::get_current_targeting_method();
$countries = Advanced_Ads_Geo_Api::get_countries();
// set defaults for all variables.
$my_country = '';
$my_country_iso_code = '';
$my_city = '';
$my_region = '';
$my_lat = 0.0;
$my_lon = 0.0;
switch ( $method ) {
case 'sucuri':
$my_country_iso_code = Advanced_Ads_Geo_Plugin::get_sucuri_country();
$my_country = $countries[ $my_country_iso_code ] ?? ' ';
$current_location = sprintf( '%s (%s)', $my_country, $my_country_iso_code );
break;
default:
// get information from the current user to help him debugging issues.
$api = Advanced_Ads_Geo_Api::get_instance();
$ip = $api->get_real_ip_address();
$error = false;
// get locale.
$locale = Advanced_Ads_Geo_Plugin::get_instance()->options( 'locale', 'en' );
if ( $ip ) {
try {
$reader = $api->get_geo_ip2_city_reader();
if ( $reader ) {
// Look up the IP address.
$record = $reader->city( $ip );
if ( ! empty( $record ) ) {
$my_city = ( $record->city->name ) ? $record->city->name : __( '(unknown city)', 'advanced-ads-pro' );
if ( isset( $record->city->names[ $locale ] ) && $record->city->names[ $locale ] ) {
$my_city = $record->city->names[ $locale ];
}
$my_country = ( isset( $record->country->names[ $locale ] ) && $record->country->names[ $locale ] )
? $record->country->names[ $locale ]
: $record->country->names['en'];
$my_country_iso_code = $record->country->isoCode;
// get first subdivision (region/state).
$my_region = ( isset( $record->subdivisions[0] ) && $record->subdivisions[0]->name ) ? $record->subdivisions[0]->name : __( '(unknown region)', 'advanced-ads-pro' );
if ( isset( $record->subdivisions[0] ) && isset( $record->subdivisions[0]->names[ $locale ] ) && $record->subdivisions[0]->names[ $locale ] ) {
$my_region = $record->subdivisions[0]->names[ $locale ];
}
if ( isset( $record->location ) && isset( $record->location->latitude ) && isset( $record->location->longitude ) ) {
$my_lat = $record->location->latitude;
$my_lon = $record->location->longitude;
}
}
} else {
$error = sprintf(
'%1$s %2$s',
__( 'Geo Databases not found.', 'advanced-ads-pro' ),
sprintf(
/* translators: 1: opening <a>-tag to Advanced Ads manual, 2: closing <a>-tag */
__( 'Please read the %1$sinstallation instructions%2$s.', 'advanced-ads-pro' ),
'<a href="https://wpadvancedads.com/manual/geo-targeting-condition/#Enabling_Geo-Targeting" target="_blank">',
'</a>'
)
);
}
} catch ( AddressNotFoundException $e ) {
$error = $e->getMessage() . ' ' . __( 'Maybe you are working on a local or secured environment.', 'advanced-ads-pro' );
}
} else {
$raw_ip = $api->get_raw_ip_address();
$error = '<span class="advads-notice-inline advads-error">' . __( 'Your IP address format is incorrect', 'advanced-ads-pro' ) . ' (' . $raw_ip . ')</span>';
}
if ( $error ) {
$current_location = '<span class="advads-notice-inline advads-error">' . $error . '</span>';
} else {
$current_location = $ip . ', ' . $my_country . ', ' . $my_region . ', ' . $my_city;
$current_location .= '<br/>' . __( 'Coordinates', 'advanced-ads-pro' ) . ': (' . $my_lat . ' / ' . $my_lon . ')';
}
}
// form name basis.
if ( method_exists( 'Advanced_Ads_Visitor_Conditions', 'get_form_name_with_index' ) ) {
$name = Advanced_Ads_Visitor_Conditions::get_form_name_with_index( $form_name, $index );
} else {
$name = Advanced_Ads_Visitor_Conditions::FORM_NAME . '[' . $index . ']';
}
$operator = isset( $options['operator'] ) ? $options['operator'] : 'is';
$geo_mode = isset( $options['geo_mode'] ) ? $options['geo_mode'] : 'classic';
?>
<input type="hidden" name="<?php echo esc_attr( $name ); ?>[type]" value="<?php echo esc_attr( $options['type'] ); ?>"/>
<input type="hidden" name="<?php echo esc_attr( $name ); ?>[value]" value="1"/>
<style type="text/css">
span.geomode {
display: inline-block;
clear: both;
margin: 0px 0px 5px 0px;
}
span.geomode input[type=radio] {
display: block;
float: left;
margin: 0px 5px 0px 5px;
}
</style>
<div style="margin-bottom: 10pt;">
<span class="geomode">
<?php // phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped ?>
<input id="radio_classic_<?php echo esc_attr( $index ); ?>" type="radio" name="<?php echo esc_attr( $name ); ?>[geo_mode]" <?php checked( $geo_mode, 'classic' ); ?> value="classic" onclick="advads_geo_admin.set_mode(<?php echo $index; ?>, this.value);">
<?php // phpcs:enable ?>
<label for="radio_classic_<?php echo esc_attr( $index ); ?>"><?php esc_html_e( 'by specific location', 'advanced-ads-pro' ); ?></label>
</span>
<span class="geomode">
<?php // phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped ?>
<input class="geomode" id="radio_latlon_<?php echo esc_attr( $index ); ?>" type="radio" name="<?php echo esc_attr( $name ); ?>[geo_mode]" <?php checked( $geo_mode, 'latlon' ); ?> value="latlon" onclick="advads_geo_admin.set_mode(<?php echo $index; ?>, this.value);">
<?php // phpcs:enable ?>
<label for="radio_latlon_<?php echo esc_attr( $index ); ?>"><?php esc_html_e( 'by radius', 'advanced-ads-pro' ); ?></label>
</span>
</div>
<div class="geomode" id="advads_geo_classic_<?php echo esc_attr( $index ); ?>"
<?php
if ( 'classic' !== $geo_mode ) {
echo ' style="display:none;"';
}
?>
>
<select name="<?php echo esc_attr( $name ); ?>[operator]">
<option value="is" <?php selected( 'is', $operator ); ?>><?php esc_html_e( 'is', 'advanced-ads-pro' ); ?></option>
<option value="is_not" <?php selected( 'is_not', $operator ); ?>><?php esc_html_e( 'is not', 'advanced-ads-pro' ); ?></option>
</select>
<?php
switch ( $method ) :
case 'sucuri':
$country = isset( $options['country'] ) ? $options['country'] : $my_country_iso_code;
?>
<div class="advads-conditions-select-wrap"><select name="<?php echo esc_attr( $name ); ?>[country]"><?php foreach ( $countries as $_code => $_title ) : ?>
<option value="<?php echo esc_attr( $_code ); ?>" <?php selected( $_code, $country ); ?>><?php echo esc_html( $_title ); ?></option>
<?php
endforeach;
?>
</select></div>
<?php
break;
default:
$country = isset( $options['country'] ) ? $options['country'] : $my_country_iso_code;
$region = isset( $options['region'] ) ? $options['region'] : '';
$city = isset( $options['city'] ) ? $options['city'] : '';
?>
<div class="advads-conditions-select-wrap"><select name="<?php echo esc_attr( $name ); ?>[country]"><?php foreach ( $countries as $_code => $_title ) : ?>
<option value="<?php echo esc_attr( $_code ); ?>" <?php selected( $_code, $country ); ?>><?php echo esc_html( $_title ); ?></option>
<?php endforeach; ?>
</select></div> <?php esc_html_e( 'or', 'advanced-ads-pro' ); ?>
<input type="text" name="<?php echo esc_attr( $name ); ?>[region]" value="<?php echo esc_attr( $region ); ?>" placeholder="<?php esc_html_e( 'State/Region', 'advanced-ads-pro' ); ?>"/>
<?php esc_html_e( 'or', 'advanced-ads-pro' ); ?>
<input type="text" name="<?php echo esc_attr( $name ); ?>[city]" value="<?php echo esc_attr( $city ); ?>" placeholder="<?php esc_html_e( 'City', 'advanced-ads-pro' ); ?>"/>
<?php
break;
endswitch;
?>
</div>
<div id="advads_geo_latlon_<?php echo esc_attr( $index ); ?>"
<?php
if ( 'latlon' !== $geo_mode ) {
echo ' style="display:none;"';
}
?>
>
<?php
switch ( $method ) :
case 'sucuri':
esc_html_e( 'This option cant be used if your site is using sucuri.net.', 'advanced-ads-pro' );
break;
default:
$lat = isset( $options['lat'] ) ? $options['lat'] : '';
$lon = isset( $options['lon'] ) ? $options['lon'] : '';
$distance = isset( $options['distance'] ) ? $options['distance'] : '';
$distance_condition = isset( $options['distance_condition'] ) ? $options['distance_condition'] : '';
$distance_unit = isset( $options['distance_unit'] ) ? $options['distance_unit'] : '';
?>
<select name="<?php echo esc_attr( $name ); ?>[distance_condition]">
<option value="lte" <?php selected( $distance_condition, 'lte' ); ?>><?php esc_html_e( 'Distance is less than or equal to', 'advanced-ads-pro' ); ?></option>
<option value="gt" <?php selected( $distance_condition, 'gt' ); ?>><?php esc_html_e( 'Distance is greater than', 'advanced-ads-pro' ); ?></option>
</select>
<input type="number" name="<?php echo esc_attr( $name ); ?>[distance]" maxlength="8" style="width:80pt;" value="<?php echo esc_attr( $distance ); ?>" placeholder="<?php esc_attr_e( 'Distance', 'advanced-ads-pro' ); ?>"/>
<select name="<?php echo esc_attr( $name ); ?>[distance_unit]">
<option value="km" <?php selected( $distance_unit, 'km' ); ?>><?php esc_html_e( 'kilometers (km)', 'advanced-ads-pro' ); ?></option>
<option value="mi" <?php selected( $distance_unit, 'mi' ); ?>><?php esc_html_e( 'miles (mi)', 'advanced-ads-pro' ); ?></option>
</select><br/><?php esc_html_e( 'from', 'advanced-ads-pro' ); ?><br/>
<?php // phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped ?>
<button type="button" class="button" onclick="advads_geo_admin.click_locname(<?php echo $index; ?>)"><?php esc_html_e( 'get coordinates', 'advanced-ads-pro' ); ?></button>
<?php // phpcs:enable ?>
<input type="number" step="any" id="advads_geo_input_lat_<?php echo esc_attr( $index ); ?>" style="width:80pt; text-align:right;" name="<?php echo esc_attr( $name ); ?>[lat]" value="<?php echo esc_attr( $lat ); ?>" placeholder="<?php esc_attr_e( 'Latitude', 'advanced-ads-pro' ); ?>" title="<?php esc_attr_e( 'Latitude', 'advanced-ads-pro' ); ?>"/> /
<input type="number" step="any" id="advads_geo_input_lon_<?php echo esc_attr( $index ); ?>" style="width:80pt; text-align:right;" name="<?php echo esc_attr( $name ); ?>[lon]" value="<?php echo esc_attr( $lon ); ?>" placeholder="<?php esc_attr_e( 'Longitude', 'advanced-ads-pro' ); ?>" title="<?php esc_attr_e( 'Longitude', 'advanced-ads-pro' ); ?>"/>
<br>
<?php
if ( '' !== $lat && '' !== $lon && $my_lat && $my_lon ) {
$distance = Advanced_Ads_Geo::calculate_distance( $my_lat, $my_lon, $lat, $lon, $distance_unit );
$current_location .= '<br/>' . esc_html__( 'Distance to center', 'advanced-ads-pro' ) . ' ( ' . $lat . ' / ' . $lon . ' ): ' . round( $distance, 1 ) . ' ' . $distance_unit;
}
break;
endswitch;
?>
</div>
<?php
$latlon_city = isset( $options['latlon_city'] ) ? $options['latlon_city'] : '';
?>
<div id="advads_geo_latlon_by_city_<?php echo esc_attr( $index ); ?>" style="display: none; margin:3pt; padding:3pt;">
<input id="advads_geo_input_search_city_<?php echo esc_attr( $index ); ?>" type="text" name="<?php echo esc_attr( $name ); ?>[latlon_city]" value="<?php echo esc_attr( $latlon_city ); ?>" placeholder="<?php esc_attr_e( 'City', 'advanced-ads-pro' ); ?>">
<?php // phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped ?>
<button type="button" class="button button-primary" onclick="advads_geo_admin.search_loc(<?php echo $index; ?>)"><?php esc_html_e( 'Search', 'advanced-ads-pro' ); ?></button>
<button type="button" class="button" onclick="advads_geo_admin.search_loc_close(<?php echo $index; ?>)"><?php esc_html_e( 'Cancel', 'advanced-ads-pro' ); ?></button>
<?php // phpcs:enable ?>
<p class="description"><?php esc_html_e( 'Enter the name of the city, click the search button and pick one of the results to set the coordinates of the center.', 'advanced-ads-pro' ); ?></p>
<div id="advads_geo_latlon_loading_<?php echo esc_attr( $index ); ?>" class="spinner is-active" style="display:none; float: none;"></div>
<div id="advads_geo_latlon_results_<?php echo esc_attr( $index ); ?>"></div>
</div>
<p class="description">
<?php echo esc_html( $type_options[ $options['type'] ]['description'] ); ?>
<a href="https://wpadvancedads.com/manual/geo-targeting-condition/?utm_source=advanced-ads&utm_medium=link&utm_campaign=condition-geo-location" class="advads-manual-link" target="_blank">
<?php esc_html_e( 'Manual', 'advanced-ads-pro' ); ?>
</a>
</p>
<div class="description">
<p>
<strong><?php esc_html_e( 'Location based on your IP address', 'advanced-ads-pro' ); ?>:</strong>
<br>
<?php
echo wp_kses(
$current_location,
[
'br' => [],
'span' => [ 'class' => true ],
'a' => [
'href' => true,
'target' => true,
],
]
);
?>
</p>
<?php $this->render_visitor_profile_information( $my_lat, $my_lon ); ?>
</div>
<?php
}
/**
* Download database
*
* @since 1.0.0
*/
public function download_database() {
check_ajax_referer( 'advanced-ads-admin-ajax-nonce', 'nonce' );
if ( ! Conditional::user_can( 'advanced_ads_manage_options' ) ) {
wp_send_json_error( __( 'You are not allowed to do this.', 'advanced-ads-pro' ), 400 );
}
$upload_full = Advanced_Ads_Geo_Plugin::get_instance()->get_upload_full();
if ( ! $upload_full ) {
wp_send_json_error( __( 'The upload dir is not available', 'advanced-ads-pro' ), 400 );
}
$license_key = sanitize_text_field( wp_unslash( Params::request( 'license_key', '' ) ) );
if ( empty( $license_key ) ) {
wp_send_json_error( __( 'Please provide a MaxMind license key', 'advanced-ads-pro' ), 400 );
}
$file_prefix = Advanced_Ads_Geo_Plugin::get_maxmind_file_prefix();
if ( '' === $file_prefix ) {
$file_prefix = $this->create_new_prefix();
$this->remove_obsolete_files();
}
// download source.
$download_urls = [
'city' => 'https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-City&suffix=tar.gz&license_key=' . $license_key,
'country' => 'https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-Country&suffix=tar.gz&license_key=' . $license_key,
];
// Paths where we will save files.
$filepaths = [
'city' => $upload_full . $file_prefix . '-GeoLite2-City.mmdb',
'country' => $upload_full . $file_prefix . '-GeoLite2-Country.mmdb',
];
// Names in the `tar.gz` archives.
$filenames_in_archive = [
'city' => 'GeoLite2-City.mmdb',
'country' => 'GeoLite2-Country.mmdb',
];
// create upload directory if not exists yet.
if ( ! file_exists( $upload_full ) ) {
// phpcs:disable WordPress.WP.AlternativeFunctions.file_system_operations_mkdir
mkdir( $upload_full );
// phpcs:enable
}
// Prevent directory listing.
if ( ! file_exists( $upload_full . 'index.html' ) ) {
// phpcs:disable WordPress.WP.AlternativeFunctions,WordPress.PHP.NoSilencedErrors.Discouraged
$handle = @fopen( $upload_full . 'index.html', 'w' );
fwrite( $handle, '' );
fclose( $handle );
// phpcs:enable
}
if ( function_exists( 'wp_raise_memory_limit' ) ) {
wp_raise_memory_limit();
}
$this->maybe_replace_tmp_dir();
foreach ( $download_urls as $key => $download_url ) {
// variable with the name of the database file to download.
$db_file = $filepaths[ $key ];
$filename = $filenames_in_archive[ $key ];
$result = $this->download_geolite2_database( $download_url, $db_file, $filename );
if ( ! isset( $result['state'] ) || ! $result['state'] ) {
wp_send_json_error( $result['message'], 400 );
}
}
// save geo options on db update.
$pro_plugin = Advanced_Ads_Pro::get_instance();
$pro_options = $pro_plugin->get_options();
if ( ! array_key_exists( Advanced_Ads_Geo_Plugin::OPTIONS_SLUG, $pro_options ) ) {
$pro_options[ Advanced_Ads_Geo_Plugin::OPTIONS_SLUG ] = [];
}
$pro_options[ Advanced_Ads_Geo_Plugin::OPTIONS_SLUG ]['maxmind-license-key'] = $license_key;
$pro_options[ Advanced_Ads_Geo_Plugin::OPTIONS_SLUG ]['locale'] = sanitize_text_field( wp_unslash( Params::request( 'locale', '' ) ) );
$pro_plugin->update_options( $pro_options );
update_option( ADVADS_SLUG . '-' . Advanced_Ads_Geo_Plugin::OPTIONS_SLUG . '-last-update-geolite2', time() );
wp_send_json_success( __( 'Database updated successfully!', 'advanced-ads-pro' ) );
}
/**
* Download GeoLite2 databases
*
* @param string $download_url The download url.
* @param string $db_file The target file.
* @param string $filename The target filename in the archive.
*
* @return array
*/
private function download_geolite2_database( $download_url, $db_file, $filename ) {
// download the file from MaxMind, this places into temporary location.
$temp_file = download_url( $download_url );
$result['state'] = false;
$result['message'] = __( 'Database update failed', 'advanced-ads-pro' );
// If we failed, through a message, otherwise proceed.
if ( is_wp_error( $temp_file ) ) {
$error_code = $temp_file->get_error_data()['code'] ?? '';
$error_body = $temp_file->get_error_data()['body'] ?? '';
$result['message'] = sprintf(
/* translators: 1: The download URL, 2: The HTTP error code, 3: The HTTP header title, 4: The response body */
__( 'Error downloading database from: %1$s - %2$s %3$s - %4$s', 'advanced-ads-pro' ),
wp_parse_url( $download_url, PHP_URL_HOST ), // Do not expose the license key from query string.
$error_code,
$temp_file->get_error_message(),
$error_body
);
error_log( 'Advanced Ads Geo: ' . $result['message'] ); // phpcs:ignore
} else {
// The dir where the archive was downloaded.
$temp_file_dir = dirname( $temp_file );
try {
$archive = new PharData( $temp_file );
// The dir extracted from the archive.
$extracted_dir = trailingslashit( $archive->current()->getFilename() );
// Full path to the dir extracted from the archive.
$extracted_dir_full = trailingslashit( $temp_file_dir ) . $extracted_dir;
$archive->extractTo(
$temp_file_dir,
$extracted_dir . $filename,
true
);
} catch ( Exception $e ) {
$result['message'] = sprintf(
/* translators: an error mesage. */
esc_html__( 'Could not open downloaded database for reading: %s', 'advanced-ads-pro' ),
$temp_file . ', ' . $e->getMessage()
);
error_log( 'Advanced Ads Geo: ' . $result['message'] ); // phpcs:ignore
return $result;
} finally {
wp_delete_file( $temp_file );
}
add_filter( 'filesystem_method', [ $this, 'set_direct_filesystem_method' ] );
WP_Filesystem();
global $wp_filesystem;
if ( ! isset( $wp_filesystem->method ) || 'direct' !== $wp_filesystem->method ) {
$result['message'] = __( 'Could not access filesystem', 'advanced-ads-pro' );
error_log( 'Advanced Ads Geo: ' . $result['message'] ); // phpcs:ignore
return $result;
}
// Move the file.
$renamed = $wp_filesystem->move( $extracted_dir_full . $filename, $db_file, true );
$wp_filesystem->delete( $extracted_dir_full, false, 'd' );
if ( ! $renamed ) {
/* translators: MaxMind database file name. */
$result['message'] = sprintf( __( 'Could not open database for writing %s', 'advanced-ads-pro' ), $db_file );
// Remove corrupted file.
$wp_filesystem->delete( $db_file, false, 'f' );
} else {
$result['message'] = '';
$result['state'] = true;
}
remove_filter( 'filesystem_method', [ $this, 'set_direct_filesystem_method' ] );
}
return $result;
}
/**
* Get timestamp of the next first Tuesday of a month (either this month or the next)
*
* @param string $time timestamp from which to get the next available Tuesday.
*
* @return int of the next Tuesday (midnight GMT)
* @since 1.0.0
*/
public function get_next_first_tuesday_timestamp( $time = 0 ) {
// we actually use Wednesday since it returns midnight.
if ( ! $time ) {
$time = time();
}
// current month.
// phpcs:disable WordPress.DateTime.RestrictedFunctions.date_date
$month = date( 'F', $time );
$year = date( 'Y', $time );
$next_tuesday_t = strtotime( "first Wednesday of $month $year" );
// if this is the past, get first Tuesday of next month.
if ( $next_tuesday_t < time() ) {
$next_month_t = strtotime( 'next month' );
$month = date( 'F', $next_month_t );
$year = date( 'Y', $next_month_t );
$next_tuesday_t = strtotime( "first Tuesday of $month $year" );
}
// phpcs:enable
return $next_tuesday_t;
}
/**
* Check if the databases are working
*/
public function check_database() {
$api = Advanced_Ads_Geo_Api::get_instance();
return $api->get_geo_lite_country_filename() && $api->get_geo_lite_city_filename();
}
/**
* Check if an updated version of the database might already be available
* we use the timestamp of the last update that actually happened and check,
* if the next first Tuesday of a month that followed is already in the past
*
* @return bool true, if update should be available
* @since 1.0.0
*/
public function is_update_available() {
// check if database is available.
if ( ! $this->check_database() ) {
return true;
}
// current time.
$now_t = time();
// get last update from the database.
$last_update_t = get_option( ADVADS_SLUG . '-' . Advanced_Ads_Geo_Plugin::OPTIONS_SLUG . '-last-update-geolite2', $now_t );
// return true, if last update is more than 31 days ago.
$month_in_seconds = 31 * DAY_IN_SECONDS;
if ( $month_in_seconds <= $now_t - $last_update_t ) {
return true;
}
// get next Tuesday following the update.
$next_tuesday_t = $this->get_next_first_tuesday_timestamp( $last_update_t );
if ( $next_tuesday_t < $now_t ) {
return true;
}
return false;
}
/**
* Check if license is valid
*
* @return bool true if license is valid
* @since 1.0.0
*/
public function license_valid() {
$status = Advanced_Ads_Admin_Licenses::get_instance()->get_license_status( 'advanced-ads-geo' );
if ( 'valid' === $status ) {
return true;
}
return false;
}
/**
* Register and enqueue admin-specific scripts.
*
* @return void
*/
public function enqueue_admin_scripts() {
if ( ! Conditional::is_screen_advanced_ads() ) {
return;
}
$handle = ADVADS_SLUG . '-' . Advanced_Ads_Geo_Plugin::OPTIONS_SLUG . '-admin-script';
wp_enqueue_script( $handle, plugin_dir_url( __FILE__ ) . '../admin/assets/admin.js', [], AAP_VERSION, true );
wp_localize_script(
$handle,
'advads_geo_translation',
[
/* translators: 1: The number of search results. */
'found_results' => __( 'Found %1$d results. Please pick the one, you want to use.', 'advanced-ads-pro' ),
'no_results' => __( 'Your search did not return any results.', 'advanced-ads-pro' ),
'could_not_retrieve_city' => __( 'There was an error connecting to the search service.', 'advanced-ads-pro' ),
/* translators: 1: A link to the geo location service. */
'manual_geo_search' => sprintf( __( 'You can search for the geo coordinates manually at %1$s.', 'advanced-ads-pro' ), '<a href="https://nominatim.openstreetmap.org/">nominatim.openstreetmap.org</a>' ),
'COOKIEPATH' => COOKIEPATH,
'COOKIE_DOMAIN' => COOKIE_DOMAIN,
'nonce' => wp_create_nonce( 'advanced-ads-admin-ajax-nonce' ),
]
);
}
/**
* As per MaxMind TOS, databases should not be puclicly accessible. Create a random prefix for that.
*/
private function create_new_prefix() {
$new_prefix = wp_generate_password( 32, false );
update_option( 'advanced-ads-geo-maxmind-file-prefix', $new_prefix );
return $new_prefix;
}
/**
* Remove files prefixed with an obsolete prefix.
*/
public function remove_obsolete_files() {
require_once ABSPATH . 'wp-admin/includes/file.php';
add_filter( 'filesystem_method', [ $this, 'set_direct_filesystem_method' ] );
WP_Filesystem();
global $wp_filesystem;
if ( ! isset( $wp_filesystem->method ) || 'direct' !== $wp_filesystem->method ) {
return;
}
$upload_full = Advanced_Ads_Geo_Plugin::get_instance()->get_upload_full();
if ( ! $upload_full ) {
return;
}
$files = $wp_filesystem->dirlist( $upload_full );
if ( ! $files ) {
return;
}
foreach ( $files as $file ) {
if ( preg_match( '/GeoLite2-.*?\.mmdb$/', $file['name'] )
|| 'tmp-' === substr( $file['name'], 0, 4 )
) {
$wp_filesystem->delete( $upload_full . $file['name'] );
}
}
remove_filter( 'filesystem_method', [ $this, 'set_direct_filesystem_method' ] );
}
/**
* Set direct filesystem method.
*/
public function set_direct_filesystem_method() {
return 'direct';
}
/**
* Create a new tmp dir inside the upload dir if the existing one does not contain enought space.
*/
private function maybe_replace_tmp_dir() {
if ( defined( 'WP_TEMP_DIR' ) ) {
return;
}
// phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
$available_tmp_space = @disk_free_space( get_temp_dir() );
// We need > 200 MB.
if ( ! $available_tmp_space || ( $available_tmp_space / MB_IN_BYTES ) < 200 ) {
$tmp_dir = Advanced_Ads_Geo_Plugin::get_instance()->get_upload_full()
. 'tmp-'
. Advanced_Ads_Geo_Plugin::get_maxmind_file_prefix();
if ( ! file_exists( $tmp_dir ) ) {
// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_mkdir,WordPress.PHP.NoSilencedErrors.Discouraged
@mkdir( $tmp_dir );
}
// phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
if ( @is_dir( $tmp_dir ) && wp_is_writable( $tmp_dir ) ) {
define( 'WP_TEMP_DIR', $tmp_dir );
}
}
}
/**
* Render a table with the current visitor profile cookie information if available.
*
* @param float $lat User's latitude.
* @param float $lon User's longitude.
*
* @return void
*/
private function render_visitor_profile_information( $lat, $lon ) {
$visitor_profile = new Advanced_Ads_Geo_Visitor_Profile();
if ( $visitor_profile->has_visitor_profile && $visitor_profile->is_different_from_current_location( $lat, $lon ) ) {
require $this->views_path . '/visitor-profile.php';
}
}
/**
* Check if custom database files are used via filters
*
* @return bool
*/
private function is_using_custom_database() {
$api = Advanced_Ads_Geo_Api::get_instance();
return has_filter( 'advanced-ads-geo-maxmind-geolite2-country-db-filepath' )
&& has_filter( 'advanced-ads-geo-maxmind-geolite2-city-db-filepath' )
&& $api->get_geo_ip2_city_reader()
&& $api->get_geo_ip2_country_reader();
}
}