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,46 @@
<?php /** @noinspection HttpUrlsUsage */
namespace WPDRMS\ASP\Misc;
use WPDRMS\ASP\Patterns\SingletonTrait;
class OutputBuffer {
use SingletonTrait;
private $found = false;
function obStart() {
ob_start(array($this, 'obCallback'));
}
function obCallback($buffer, $phase) {
if ($phase & PHP_OUTPUT_HANDLER_FINAL || $phase & PHP_OUTPUT_HANDLER_END) {
// Hook into this to change the buffer
return apply_filters('asp_ob_end', $buffer);
}
return $buffer;
}
function obClose(): bool {
$handlers = ob_list_handlers();
$callback = self::class . '::obCallback';
$found = in_array($callback, $handlers);
if ( $found ) {
for ($i = count($handlers) - 1; $i >= 0; $i--) {
ob_end_flush();
if ($handlers[$i] === $callback) {
break;
}
}
}
// $this->found = found is not good. If this function is triggered multiple times, then may override "true" to "false"
$this->found = $found == true ? true : $this->found;
return $found;
}
function obFound(): bool {
return $this->found;
}
}

View File

@@ -0,0 +1,100 @@
<?php
namespace WPDRMS\ASP\Misc;
defined('ABSPATH') or die("You can't access this file directly.");
class Performance {
/**
* @var array of performance values
*/
private $records;
/**
* @var array default values for the records array
*/
private $default = array(
'run_count' => 0,
'average_runtime' => 0,
'average_memory' => 0,
'last_runtime' => 0,
'last_memory' => 0
);
/**
* @var int current runtime
*/
private $runtime;
/**
* @var int actual memory usage
*/
private $memory;
/**
* @var string the name of the storage
*/
private $key;
/**
* Setup Class
*
* @param string $key
*/
function __construct(string $key = "plugin_performance") {
$this->key = $key;
$this->records = get_option($key, $this->default);
}
/**
* Deletes the storage
*/
function reset() {
delete_option($this->key);
}
/**
* Gets the storage
*
* @return array
*/
function get_data(): array {
return $this->records;
}
/**
* Starts the measurement
*/
function start_measuring() {
$this->runtime = microtime(true);
$this->memory = memory_get_usage(true);
}
/**
* Stops the measurement
*/
function stop_measuring() {
$this->runtime = microtime(true) - $this->runtime;
$this->memory = memory_get_peak_usage(true) - $this->memory;
$this->save();
}
/**
* Saves the values
*/
private function save() {
$this->count_averages();
$this->records['last_runtime'] = $this->runtime > 15 ? 15 : $this->runtime;
$this->records['last_memory'] = $this->memory;
++$this->records['run_count'];
update_option($this->key, $this->records);
}
/**
* Calculates the final averages before writing to database
*/
private function count_averages() {
$this->records['average_runtime'] =
($this->records['average_runtime'] * $this->records['run_count'] + $this->runtime) / ($this->records['run_count'] + 1);
$this->records['average_memory'] =
($this->records['average_memory'] * $this->records['run_count'] + $this->memory) / ($this->records['run_count'] + 1);
}
}

View File

@@ -0,0 +1,95 @@
<?php /** @noinspection HttpUrlsUsage */
namespace WPDRMS\ASP\Misc;
use WP_Error;
if ( !defined('ABSPATH') ) {
die('-1');
}
class PluginLicense {
static $url = 'https://update.wp-dreams.com/';
private const OPTION_NAME = 'asp_license_data';
public static function activate( $license_key ) {
$url = isset($_SERVER['HTTP_HOST']) ? rawurlencode($_SERVER['HTTP_HOST']) : 'https://unkwown.domain';
$key = rawurlencode( $license_key );
$url = self::$url . "license/activate/$key/?url=" . $url;
$response = wp_remote_post( $url );
if ( $response instanceof WP_Error ) {
return false;
}
$data = json_decode( $response['body'], true );
// something went wrong
if ( empty($data) ) {
return false;
}
if ( isset($data['status']) && $data['status'] == 1 ) {
update_site_option(
self::OPTION_NAME,
array(
'key' => $license_key,
'host' => $_SERVER['HTTP_HOST'] ?? 'unkwown.domain',
)
);
}
return $data;
}
public static function deactivate( $remote_check = true ) {
$data = false;
if ( $remote_check ) {
$key = self::isActivated();
if ( false !== $key ) {
$url = isset($_SERVER['HTTP_HOST']) ? rawurlencode($_SERVER['HTTP_HOST']) : 'unkwown.domain';
$key = rawurlencode($key);
$url = self::$url . "license/deactivate/$key?url=" . $url;
$response = wp_remote_request($url, array( 'method' =>'PATCH' ));
if ( $response instanceof WP_Error ) {
return false;
}
$data = json_decode($response['body'], true);
}
}
delete_site_option(self::OPTION_NAME);
return $data;
}
public static function isActivated( bool $remote_check = false ) {
self::convertToSiteOption();
$data = get_site_option(self::OPTION_NAME);
if ( $data === false || !isset($data['host']) || !isset($data['key']) ) {
return false;
}
if ( $remote_check ) {
$url = isset($_SERVER['HTTP_HOST']) ? rawurlencode($_SERVER['HTTP_HOST']) : 'unknown.domain';
$key = rawurlencode( $data['key'] );
$url = self::$url . "license/is_active/$key/?url=" . $url;
$response = wp_remote_get( $url );
if ( $response instanceof WP_Error ) {
return false;
}
$rdata = json_decode( $response['body'], true );
return $rdata['status'] ? $data['key'] : false;
}
return $data['key'];
}
private static function convertToSiteOption() {
// Old option with the old key
$data = get_option('asp_update_data');
if ( $data !== false ) {
update_site_option(self::OPTION_NAME, $data);
delete_option('asp_update_data');
}
}
}

View File

@@ -0,0 +1,129 @@
<?php
namespace WPDRMS\ASP\Misc;
use WPDRMS\ASP\Utils\Str;
if (!defined('ABSPATH')) die('-1');
class Priorities {
public static function count() {
$count = get_site_option('_asp_priority_count');
if ( $count === false ) {
global $wpdb;
$wpdb->get_var( "SELECT 1 FROM " . wd_asp()->db->table('priorities') . " LIMIT 1" );
$count = $wpdb->num_rows;
update_site_option('_asp_priority_count', $count);
}
return $count;
}
static function ajax_get_posts() {
global $wpdb;
parse_str($_POST['options'], $o);
$w_post_type = '';
$w_filter = '';
$w_limit = (int)$o['p_asp_limit'] + 0;
$w_limit = $w_limit < 1 ? 20 : $w_limit;
$w_limit = $w_limit > 200 ? 200 : $w_limit;
$pt = wd_asp()->db->table("priorities");
if (isset($o['blog_id']) && $o['blog_id'] != 0 && is_multisite())
switch_to_blog($o['p_asp_blog']);
if (isset($o['p_asp_filter']) && $o['p_asp_filter'] != '') {
$w_filter = "AND $wpdb->posts.post_title LIKE '%" . Str::escape($o['p_asp_filter']) . "%'";
}
if (isset($o['p_asp_post_type']) && $o['p_asp_post_type'] != 'all') {
$w_post_type = "AND $wpdb->posts.post_type = '" . Str::escape($o['p_asp_post_type']) . "'";
}
if ( $o['p_asp_post_type'] == 'attachment' ) {
$post_status = "$wpdb->posts.post_status IN ('inherit')";
} else {
$post_status = "$wpdb->posts.post_status IN ('publish', 'pending')";
}
$allowed_orderings = array(
'id DESC', 'id ASC', 'title DESC', 'title ASC', 'priority DESC', 'priority ASC'
);
if ( !isset($o['p_asp_ordering']) || !in_array($o['p_asp_ordering'], $allowed_orderings) ) {
$o['p_asp_ordering'] = 'id DESC';
}
$querystr = "
SELECT
$wpdb->posts.post_title as `title`,
$wpdb->posts.ID as id,
$wpdb->posts.post_date as `date`,
$wpdb->users.user_nicename as `author`,
$wpdb->posts.post_type as `post_type`,
CASE WHEN $pt.priority IS NULL
THEN 100
ELSE $pt.priority
END as `priority`
FROM $wpdb->posts
LEFT JOIN $wpdb->users ON $wpdb->users.ID = $wpdb->posts.post_author
LEFT JOIN $pt ON ($pt.post_id = $wpdb->posts.ID AND $pt.blog_id = " . get_current_blog_id() . ")
WHERE
$wpdb->posts.ID>0 AND
$post_status AND
$wpdb->posts.post_type NOT IN ('revision')
$w_post_type
$w_filter
GROUP BY
$wpdb->posts.ID
ORDER BY " . $o['p_asp_ordering'] . "
LIMIT $w_limit";
echo "!!PASPSTART!!" . json_encode($wpdb->get_results($querystr, OBJECT)) . '!!PASPEND!!';
if (is_multisite())
restore_current_blog();
die();
}
/**
*
*/
static function ajax_set_priorities() {
global $wpdb;
$i = 0;
parse_str($_POST['options'], $o);
if ($o['p_blogid'] == 0)
$o['p_blogid'] = get_current_blog_id();
foreach ($o['priority'] as $k => $v) {
// See if the value changed, count them
if ($v != $o['old_priority'][$k]) {
$i++;
$query = "INSERT INTO ".wd_asp()->db->table("priorities")."
(post_id, blog_id, priority)
VALUES($k, " . $o['p_blogid'] . ", $v)
ON DUPLICATE KEY UPDATE priority=" . $v;
$wpdb->query($query);
}
}
echo "!!PSASPSTART!!" . $i . "!!PSASPEND!!";
if (is_multisite())
restore_current_blog();
// Cleanup
$wpdb->query("DELETE FROM " . wd_asp()->db->table("priorities") . " WHERE priority=100");
$wpdb->get_var( "SELECT 1 FROM ".wd_asp()->db->table("priorities")." LIMIT 1" );
$count = $wpdb->num_rows;
update_site_option('_asp_priority_count', $count);
die();
}
}

View File

@@ -0,0 +1,373 @@
<?php
namespace WPDRMS\ASP\Misc;
use WPDRMS\ASP\Patterns\SingletonTrait;
if ( !defined('ABSPATH') ) die('-1');
class PriorityGroups {
use SingletonTrait;
/**
* @var string
*/
private $key = '_asp_priority_groups';
/**
* Array of instances (arrays)
*
* @var array
*/
private $instances;
/**
* Ordering in which the instances can be requested: priority, name
*
* @var string
*/
private $order = 'priority';
/**
* Order by: asc or desc
*
* @var string
*/
private $orderBy = 'desc';
/**
* Default data structure for one priority ruleset
*
* @var array
*/
private $default = array(
'priority' => 100,
'name' => 'Priority group',
'phrase' => '', // phrase that affects the logic
'phrase_logic' => 'disabled', // disabled, exact, any, start, end
'instance' => 0, // search instance ID to affect, default 0 (all)
'logic' => 'and', // logic to connect the rules with
'rules' => array(/*
array(
'name' => 'Rule name',
'field' => 'tax', // 'tax', 'cf', 'title' (disabled for now)
'operator' => 'in', // in, not in, like, not like, elike, =, <>, >, <, >=, <=, BETWEEN
'values' => array(),
'_values' => array() // additional data for the values
)
*/
)
);
/**
* A sample default rule, used in the rule array in a ruleset
*
* @var array
*/
private $default_rule = array(
'name' => 'Rule name',
'field' => 'tax', // 'tax', 'cf', 'title'
'operator' => 'in', // in, not in, like, not like, elike, =, <>, >, <, >=, <=, BETWEEN
'values' => array(),
'_values' => array() // additional data for the values
);
/**
* Get a rule by ID, or all rules
*
* @param bool|int $id
* @param bool|int $force_refresh
* @return array
*/
public function get($id = false, $force_refresh = false): array {
if ( !isset($this->instances) || !is_array($this->instances) || $force_refresh )
$this->load();
if ( $id === false ) {
return $this->instances;
} else {
return $this->instances[$id] ?? array();
}
}
/**
* Get all rules sorted
*
* @param string $order
* @param string $orderby
* @return array
*/
public function getSorted(string $order = 'priority', string $orderby = 'desc'): array {
$inst = $this->get();
if ( !empty($inst) ) {
$this->order = $order;
$this->orderBy = $orderby;
usort($inst, array($this, 'sortInstances'));
}
return $inst;
}
/**
* Get a rule by ID, or all rules
* Includes the taxonomy term labels.
*
* @param bool|int $id
* @param bool|int $force_refresh
* @return array
*/
public function getForDisplay($id = false, $force_refresh = false): array {
$inst = $this->get($id, $force_refresh);
if ( empty($inst) )
return $inst;
if ( $id !== false ) {
// For easier use, put a single instance into an array
$inst = array($inst);
}
/**
* Expected structure:
* $inst = array(
* ...,
* 'values' => array(
* array(
* 'field' => 'tax',
* 'values' => array(
* 'taxonomy_name' => array(1, 2, 3),
* ...
* ),
* array(
* 'field' => 'cf',
* 'values' => array( 'field_name' => array('val1', 'val2') )
* ),
* array(
* 'field' => 'title'
* 'values' => 'value'
* )
* ...
* ),
* ....
* );
*/
foreach ($inst as $ik => $instance) {
foreach ($instance['rules'] as $rk => $rule) {
if ( $rule['field'] == 'tax' ) {
foreach ($rule['values'] as $rfk => $rfv) {
$terms = wpd_get_terms(array(
'taxonomy' => $rfk,
'include' => $rule['values'][$rfk],
'fields' => 'id=>name',
'hide_empty' => false
));
if ( !isset($inst[$ik]['rules'][$rk]['_values']) )
$inst[$ik]['rules'][$rk]['_values'] = array();
if ( !is_wp_error($terms) ) {
$inst[$ik]['rules'][$rk]['_values'][$rfk] = $terms;
} else {
// Something went wrong (taxonomy deleted?)
unset($inst[$ik]['rules'][$rk]['values'][$rfk]);
}
}
}
}
}
return $inst;
}
/**
* JSON and Base64 encoded version of get()
*
* @param bool|int $id
* @param bool|int $force_refresh
* @return string
*/
public function getEncoded($id = false, $force_refresh = false): string {
return base64_encode(json_encode($this->get($id, $force_refresh)));
}
/**
* JSON and Base64 encoded version of getForDisplay()
*
* @param bool|int $id
* @param bool|int $force_refresh
* @return string
*/
public function getForDisplayEncoded($id = false, $force_refresh = false): string {
return base64_encode(json_encode($this->getForDisplay($id, $force_refresh)));
}
/**
* Get the rules count
*
* @param bool $force_refresh
* @return int
*/
public function getCount(bool $force_refresh = false): int {
if ( !isset($this->instances) || !is_array($this->instances) || $force_refresh )
$this->load();
return count($this->instances);
}
/**
* Set all instances by data
*
* @param $data
* @param bool|int $save
*/
public function set($data, $save = true) {
$this->instances = $data;
if ( $save )
$this->save();
}
/**
* JSON and Base64 encoded version of set()
*
* @param $data
* @param bool|int $save
*/
public function setEncoded($data, $save = true) {
$this->set(json_decode(base64_decode($data), true), $save);
}
/**
* Add a group to the instances
*
* @param $data
* @param bool|int $save
*/
public function add($data, $save = true) {
$this->instances[] = $data;
if ( $save )
$this->save();
}
/**
* Load up the instances from the database
*
* @return mixed
*/
public function load() {
$this->instances = get_option($this->key, array());
if ( $this->cleanInstances() ) {
// Something changed, save the new, consistent data
$this->save(false);
}
return $this->instances;
}
/**
* Saves instances to the database
*
* @param bool|int $clean
*/
public function save($clean = true) {
if ( $clean )
$this->cleanInstances();
update_option($this->key, $this->instances);
}
/**
* Used for usort() to sort by key
*
* @param $a
* @param $b
* @return int
*/
public function sortInstances($a, $b): int {
if ( isset($a[$this->order], $b[$this->order]) ) {
if ( $a[$this->order] == $b[$this->order] ) {
return 0;
}
if ( $this->orderBy == 'asc' ) {
return ($a[$this->order] < $b[$this->order]) ? -1 : 1;
} else {
return ($a[$this->order] < $b[$this->order]) ? 1 : -1;
}
} else {
return 0;
}
}
/**
*
*/
public function debug() {}
// ------------------------------------------------------------
// ---------------- PRIVATE --------------------
// ------------------------------------------------------------
/**
* Just calls init
*/
private function __construct() {
$this->init();
}
private function init() {
$this->load();
}
/**
* Performs a cleaning process on group instances
*
* @return bool
*/
private function cleanInstances(): bool {
$changed = false;
foreach ($this->instances as $k => &$v) {
// Merge with the default first
$v = wp_parse_args($v, $this->default);
// Clean up the unwanted keys, if any
$instance_keys = array_keys($this->default);
foreach ($v as $kk => $vv) {
if ( !in_array($kk, $instance_keys) )
unset($this->instances[$k][$kk]);
}
// ..also, the unwanted rule keys, if any
$rule_keys = array_keys($this->default_rule);
foreach ($v['rules'] as $rk => $rule) {
foreach ($rule as $kk => $vv) {
if ( !in_array($kk, $rule_keys) )
unset($this->instances[$k]['rules'][$rk][$kk]);
}
}
// Skip these tests on the front-end and on any ajax request
if ( !wp_doing_ajax() && is_admin() ) {
// Clean up non-existent taxonomies and taxonomy terms
foreach ($v['rules'] as $rk => $rule) {
if ( $rule['field'] == 'tax' ) {
foreach ($rule['values'] as $rtax => $rterms) {
$terms = wpd_get_terms(array(
'taxonomy' => $rtax,
'include' => $rterms,
'fields' => 'ids',
'hide_empty' => false
));
if ( !is_wp_error($terms) ) {
// Some category might got deleted?
if ( count($terms) == 0 ) {
unset($this->instances[$k]['rules'][$rk]['values'][$rtax]);
$changed = true;
} else if ( count($terms) < count($rule['values'][$rtax]) ) {
$v['rules'][$rk]['values'][$rtax] = $terms;
$changed = true;
}
} else {
// Something went wrong (taxonomy deleted?)
unset($this->instances[$k]['rules'][$rk]['values'][$rtax]);
$changed = true;
}
}
}
}
}
}
return $changed;
}
}

View File

@@ -0,0 +1,104 @@
<?php
namespace WPDRMS\ASP\Misc;
defined('ABSPATH') or die("You can't access this file directly.");
class Statistics {
static function addKeyword($id, $s) {
global $wpdb;
if ( trim($s) == '' ) {
$s = '[no keyword]';
}
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
$in = $wpdb->query(
$wpdb->prepare(
"UPDATE " . wd_asp()->db->table('stats') . " SET num=num+1, last_date=%d WHERE (keyword='%s' AND search_id=%d)",
time(),
strip_tags($s),
$id
)
);
if ($in == false) {
return $wpdb->query(
$wpdb->prepare(
"INSERT INTO " . wd_asp()->db->table('stats') . " (search_id, keyword, num, last_date) VALUES (%d, '%s', 1, %d)",
$id,
strip_tags($s),
time()
)
);
}
return $in;
}
static function getTop($count, $id=0, $exclude_empty = false) {
global $wpdb;
$fields = "id, search_id, keyword, num, last_date";
$where = "";
$group_by = "";
$id = $id + 0;
if ( $id > 0 ) {
$where = " WHERE search_id=" . $id;
if ( $exclude_empty )
$where .= " AND keyword NOT LIKE '[no keyword]' ";
} else {
$fields = "id, search_id, keyword, SUM(num) as num, last_date";
$group_by = " GROUP BY keyword ";
if ( $exclude_empty )
$where = " WHERE keyword NOT LIKE '[no keyword]' ";
}
return $wpdb->get_results($wpdb->prepare(
"SELECT $fields FROM " . wd_asp()->db->table('stats') . " " . $where . " $group_by ORDER BY num DESC LIMIT %d",
$count
)
,ARRAY_A
);
}
static function getLast($count, $id=0, $exclude_empty = false) {
global $wpdb;
$fields = "id, search_id, keyword, num, last_date";
$where = "";
$group_by = "";
$id = $id + 0;
if ( $id > 0 ) {
$where = " WHERE search_id=" . $id;
if ( $exclude_empty )
$where .= " AND keyword NOT LIKE '[no keyword]' ";
} else {
$fields = "id, search_id, keyword, SUM(num) as num, last_date";
$group_by = " GROUP BY keyword ";
if ( $exclude_empty )
$where = " WHERE keyword NOT LIKE '[no keyword]' ";
}
return $wpdb->get_results($wpdb->prepare(
"SELECT $fields FROM " . wd_asp()->db->table('stats') . " " . $where . " $group_by ORDER BY last_date DESC LIMIT %d",
$count
)
,ARRAY_A
);
}
static function clearAll() {
global $wpdb;
return $wpdb->query("DELETE FROM " . wd_asp()->db->table('stats'));
}
static function deleteKw($id) {
global $wpdb;
return $wpdb->query(
$wpdb->prepare(
"DELETE FROM " . wd_asp()->db->table('stats') . " WHERE id=%d"
, ($id+0)
)
) ;
}
}

View File

@@ -0,0 +1,84 @@
<?php
namespace WPDRMS\ASP\Misc;
if ( !defined('ABSPATH') ) die('-1');
class Themes {
/**
* List of theme files
*
* @var array
*/
private static $files = array(
'search' => 'themes.json',
'search_buttons' => 'sb_themes.json'
);
/**
* List of themes (key=>theme)
*
* @var array
*/
private static $themes = array();
/**
* Path to the theme files
*
* @var
*/
private static $path;
/**
* Gets the theme, or sub theme
*
* @param $theme
* @param string $sub
* @return mixed
*/
public static function get($theme, string $sub = 'all' ) {
if ( count(self::$themes) < 1 ) {
self::init();
}
if ( isset(self::$themes[$theme]) ) {
if ( $sub != 'all' && !empty($sub) ) {
if ( isset(self::$themes[$theme][$sub]) ) {
if ( isset(self::$themes[$theme][$sub]['_ref']) ) {
$ref = self::$themes[$theme][$sub]['_ref'];
return array_merge(
self::$themes[$theme][$ref],
self::$themes[$theme][$sub]
);
} else {
return self::$themes[$theme][$sub];
}
} else {
/**
* Some themes may not have any keys just a boolean (false) value, avoid those
* and return the next usable theme.
*/
foreach ( self::$themes[$theme] as $keys ) {
if ( is_array($keys) )
return $keys;
}
}
} else {
return self::$themes[$theme];
}
}
return false;
}
/**
* Init, gets the files to the variables
*/
private static function init() {
$ds = DIRECTORY_SEPARATOR;
self::$path = ASP_PATH . $ds . 'backend' . $ds . 'settings' . $ds;
foreach ( self::$files as $k => $file ) {
if ( !isset(self::$themes[$k]) ) {
self::$themes[$k] = file_get_contents(self::$path . $file);
self::$themes[$k] = json_decode(self::$themes[$k], true);
}
}
}
}