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,502 @@
<?php
/**
* Ad Repository.
*
* @package AdvancedAds
* @author Advanced Ads <info@wpadvancedads.com>
* @since 1.48.0
*/
namespace AdvancedAds\Ads;
use WP_Query;
use Exception;
use AdvancedAds\Constants;
use AdvancedAds\Abstracts\Ad;
use AdvancedAds\Admin\Metabox_Ad;
use AdvancedAds\Utilities\WordPress;
use AdvancedAds\Framework\Utilities\Arr;
use AdvancedAds\Framework\Utilities\Params;
use AdvancedAds\Framework\Utilities\Formatting;
defined( 'ABSPATH' ) || exit;
/**
* Ad Repository.
*
* phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.Found -- remove it later
*/
class Ad_Repository {
/**
* Ad options metakey
*
* @var string
*/
const OPTION_METAKEY = 'advanced_ads_ad_options';
/* CRUD Methods ------------------- */
/**
* Create a new ad in the database.
*
* @param Ad $ad Ad object.
*
* @return Ad
*/
public function create( &$ad ): Ad {
$id = wp_insert_post(
apply_filters(
'advanced-ads-new-ad-data',
[
'post_type' => Constants::POST_TYPE_AD,
'post_status' => $ad->get_status() ? $ad->get_status() : 'publish',
'post_author' => ! empty( $ad->get_author_id() ) ? $ad->get_author_id() : get_current_user_id(),
'post_title' => $ad->get_title() ? $ad->get_title() : __( 'New Ad', 'advanced-ads' ),
'post_content' => $ad->get_content() ? $ad->get_content() : __( 'New ad content goes here', 'advanced-ads' ),
'comment_status' => 'closed',
'ping_status' => 'closed',
],
$ad
),
true
);
if ( $id && ! is_wp_error( $id ) ) {
$ad->set_id( $id );
$this->update_post_meta( $ad );
$this->update_post_term( $ad );
$this->update_version( $ad );
$ad->apply_changes();
}
return $ad;
}
/**
* Read an ad from the database.
*
* @param Ad $ad Ad object.
* @throws Exception If invalid ad.
*
* @return void
*/
public function read( &$ad ): void {
$ad->set_defaults();
$post_object = get_post( $ad->get_id() );
if ( ! $ad->get_id() || ! $post_object || Constants::POST_TYPE_AD !== $post_object->post_type ) {
throw new Exception( esc_html__( 'Invalid ad.', 'advanced-ads' ) );
}
$ad->set_props(
[
'title' => $post_object->post_title,
'status' => $post_object->post_status,
'slug' => $post_object->post_name,
'content' => $post_object->post_content,
'author_id' => $post_object->post_author,
]
);
$this->read_ad_data( $ad );
$ad->set_object_read( true );
}
/**
* Update an existing ad in the database.
*
* @param Ad $ad Ad object.
*
* @return void
*/
public function update( &$ad ): void {
global $wpdb;
$changes = $ad->get_changes();
// Only update the post when the post data changes.
if ( array_intersect( [ 'title', 'status', 'content' ], array_keys( $changes ) ) ) {
$is_text_ad = $ad->is_type( [ 'plain', 'content' ] );
$post_data = [
'post_title' => $ad->get_title( 'edit' ),
'post_status' => $ad->get_status( 'edit' ) ? $ad->get_status( 'edit' ) : 'publish',
'post_type' => Constants::POST_TYPE_AD,
'post_content' => apply_filters(
'advanced-ads-pre-ad-save-' . $ad->get_type(),
$is_text_ad
? wp_unslash( $ad->get_content( 'edit' ) )
: apply_filters( 'content_save_pre', wp_unslash( $ad->get_content( 'edit' ) ) )
),
];
/**
* When updating this object, to prevent infinite loops, use $wpdb
* to update data, since wp_update_post spawns more calls to the
* save_post action.
*
* This ensures hooks are fired by either WP itself (admin screen save), or an update purely from CRUD.
*
* Use direct DB update for user-input ads to preserve literal content.
* Use wp_update_post for other ad types to maintain WordPress security standards.
*/
if ( doing_action( 'save_post' ) || $is_text_ad ) {
$GLOBALS['wpdb']->update( $GLOBALS['wpdb']->posts, $post_data, [ 'ID' => $ad->get_id() ] );
clean_post_cache( $ad->get_id() );
} else {
wp_update_post( array_merge( [ 'ID' => $ad->get_id() ], $post_data ) );
}
} else { // Only update post modified time to record this save event.
$wpdb->update( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
$wpdb->posts,
[
'post_modified' => current_time( 'mysql' ),
'post_modified_gmt' => current_time( 'mysql', 1 ),
],
[
'ID' => $ad->get_id(),
]
);
clean_post_cache( $ad->get_id() );
}
$this->update_post_meta( $ad );
$this->update_post_term( $ad );
$ad->apply_changes();
}
/**
* Delete an ad from the database.
*
* @param Ad $ad Ad object or Ad id.
* @param bool $force_delete Whether to bypass Trash and force deletion. Default false.
*
* @return void
*/
public function delete( &$ad, $force_delete = false ): void {
// Early bail!!
if ( ! $ad || ! $ad->get_id() ) {
return;
}
if ( $force_delete ) {
wp_delete_post( $ad->get_id(), true );
$ad->set_id( 0 );
} else {
wp_trash_post( $ad->get_id() );
$ad->set_status( 'trash' );
}
}
/* Finder Methods ------------------- */
/**
* Get an ad by its ID.
*
* @param int $id The ID of the ad to retrieve.
*
* @return Ad|null
*/
public function get_ad_by_id( $id ) {
return wp_advads_get_ad( $id );
}
/**
* Get ads belonging to a specific group.
*
* @param int $group_id The ID of the group.
*
* @return Ad[]
*/
public function get_ads_by_group_id( $group_id ): array {
$group = wp_advads_get_group( $group_id );
return $group->get_ads();
}
/**
* Get ads associated with a specific placement.
*
* @param int $placement_id The ID of the placement.
*
* @return array
*/
public function get_ads_by_placement_id( $placement_id ): array {
$placement = wp_advads_get_placement( $placement_id );
$item = $placement->get_item_object();
if ( is_a_group( $item ) ) {
return $item->get_ads();
}
if ( is_an_ad( $item ) ) {
return [ $item ];
}
return [];
}
/**
* Get ads of a specific type.
*
* @param string $type The type of ads to retrieve.
*
* @return array
*/
public function get_ads_by_type( $type ): array {
return [];
}
/**
* Get all ads object.
*
* @return array
*/
public function get_all_ads(): array {
static $advads_all_ads;
if ( isset( $advads_all_ads ) ) {
return $advads_all_ads;
}
$advads_all_ads = [];
foreach ( $this->get_ads_dropdown() as $post_id => $name ) {
$advads_all_ads[ $post_id ] = wp_advads_get_ad( $post_id );
}
return $advads_all_ads;
}
/**
* Get all ads as dropdown.
*
* @return array
*/
public function get_ads_dropdown(): array {
$query = $this->query(
[
'orderby' => 'title',
'order' => 'ASC',
],
true
);
return $query->have_posts() ? wp_list_pluck( $query->posts, 'post_title', 'ID' ) : [];
}
/**
* Query ads based on the provided arguments.
*
* @param array $args The arguments to customize the query.
* @param bool $improve_query Whether to improve the query speed.
*
* @return WP_Query The WP_Query object containing the results of the query.
*/
public function query( $args, $improve_query = false ): WP_Query {
$args = wp_parse_args(
$args,
[
'posts_per_page' => -1,
'post_status' => [ 'publish', 'future', 'draft' ],
]
);
// Strict mode.
$args['post_type'] = Constants::POST_TYPE_AD;
if ( $improve_query ) {
$args = WordPress::improve_wp_query( $args );
}
return new WP_Query( $args );
}
/* Additional Methods ------------------- */
/**
* Read ad data. Can be overridden by child classes to load other props.
*
* @param Ad $ad Ad object.
*
* @return void
*/
private function read_ad_data( &$ad ): void {
$post_meta_values = get_post_meta( $ad->get_id(), self::OPTION_METAKEY, true );
if ( empty( $post_meta_values ) || ! is_array( $post_meta_values ) ) {
$post_meta_values = [];
}
$post_meta_values = $this->migrate_values( $post_meta_values );
$display_conditions = $post_meta_values['conditions'] ?? [];
$visitor_conditions = $post_meta_values['visitors'] ?? [];
if ( ! Arr::accessible( $display_conditions ) ) {
$display_conditions = [];
}
if ( ! Arr::accessible( $visitor_conditions ) ) {
$visitor_conditions = [];
}
$ad->set_props( $post_meta_values );
$ad->set_props(
[
'display_conditions' => $display_conditions,
'visitor_conditions' => $visitor_conditions,
'has_weekdays' => $post_meta_values['weekdays']['enabled'] ?? false,
'weekdays' => $post_meta_values['weekdays']['day_indexes'] ?? [],
]
);
}
/**
* Update ad data. Can be overridden by child classes to load other props.
*
* @param Ad $ad Ad object.
*
* @return void
*/
private function update_post_meta( &$ad ): void {
$post_data = Metabox_Ad::get_post_data();
$ad->set_prop( 'last_save_version', ADVADS_VERSION );
// Pre save.
if ( method_exists( $ad, 'pre_save' ) ) {
$ad->pre_save( $post_data );
}
// Filters to manipulate options or add more to be saved.
do_action( 'advanced-ads-ad-pre-save', $ad, $post_data );
$meta_keys = $ad->get_data_keys();
$meta_keys = array_combine( $meta_keys, $meta_keys );
$meta_values = [];
foreach ( $meta_keys as $meta_key => $prop ) {
$value = method_exists( $ad, "get_$prop" )
? $ad->{"get_$prop"}( 'edit' )
: $ad->get_prop( $prop, 'edit' );
$value = is_string( $value ) ? wp_slash( $value ) : $value;
switch ( $prop ) {
case 'clearfix':
case 'allow_php':
case 'has_weekdays':
case 'reserve_space':
case 'allow_shortcodes':
$value = Formatting::bool_to_string( $value );
break;
case 'description':
$value = esc_textarea( $value );
break;
case 'display_conditions':
case 'visitor_conditions':
$value = WordPress::sanitize_conditions( $value );
if (
'editpost' === Params::post( 'originalaction' ) &&
! isset( $post_data[ $meta_key ] )
) {
$value = [];
}
break;
}
$meta_values[ $meta_key ] = $value;
}
// Convert values to array.
$meta_values['weekdays'] = [
'enabled' => $meta_values['has_weekdays'],
'day_indexes' => $meta_values['weekdays'],
];
unset( $meta_values['has_weekdays'] );
update_post_meta( $ad->get_id(), self::OPTION_METAKEY, $meta_values );
}
/**
* Update ad groups.
*
* @param Ad $ad Ad object.
*
* @return void
*/
private function update_post_term( &$ad ): void {
( new Ad_Group_Relation() )->relate( $ad );
}
/**
* Make sure we store the ad version (to track data changes).
*
* @param Ad $ad Ad object.
*
* @return void
*/
private function update_version( &$ad ): void {
if ( ! metadata_exists( 'post', $ad->get_id(), '_ad_version' ) ) {
update_post_meta( $ad->get_id(), '_ad_version', ADVADS_VERSION );
}
}
/**
* Migrate values to new version
*
* @param array $values Values to migrate.
*
* @return array
*/
private function migrate_values( $values ): array {
$output = wp_parse_args(
$values['output'] ?? [],
[
'position' => 'none',
'clearfix' => false,
'add_wrapper_sizes' => false,
'margin' => [
'top' => 0,
'left' => 0,
'bottom' => 0,
'right' => 0,
],
]
);
foreach ( $output as $key => $value ) {
if ( isset( $values[ $key ] ) ) {
continue;
}
$values[ $key ] = $value;
}
$values['reserve_space'] = $values['reserve_space'] ?? $output['add_wrapper_sizes'];
// Typecast the margin values.
$values['margin'] = array_map( 'intval', $values['margin'] );
// Old values are left, center and right, if none of these we've already migrated.
if ( ! in_array( $values['position'], [ 'left', 'center', 'right' ], true ) ) {
// Ensure we get an array with min two elements.
$position = explode( '_', $values['position'] . '_' );
// Explicitly set clearfix option.
$values['clearfix'] = 'center' !== $position[0] && 'nofloat' === $position[1];
} elseif ( 'center' === $values['position'] ) {
$values['position'] = 'center_nofloat';
} else {
$values['position'] .= $values['clearfix'] ? '_nofloat' : '_float';
}
if ( isset( $values['visitor'] ) && ! isset( $values['visitors'] ) ) {
$values['visitors'] = $values['visitor'];
}
unset( $values['visitor'], $values['output'] );
return $values;
}
}