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,221 @@
<?php
namespace WPDRMS\ASP\Synonyms;
defined('ABSPATH') or die("You can't access this file directly.");
if ( !class_exists(__NAMESPACE__ . '\Database') ) {
class Database {
function add($keyword, $synonyms_arr, $language = '') {
global $wpdb;
$table = wd_asp()->db->table('synonyms');
// Use INSERT IGNORE to prevent any errors (only warnings)
$query = $wpdb->prepare(
"INSERT IGNORE INTO `$table` (keyword, synonyms, lang) VALUES( '%s', '%s', '%s')",
stripslashes_deep($keyword),
implode(',', stripslashes_deep($synonyms_arr)),
$language
);
return $wpdb->query($query);
}
function update($keyword, $synonyms_arr, $language = '') {
global $wpdb;
$table = wd_asp()->db->table('synonyms');
$query = $wpdb->prepare(
"UPDATE `$table` SET synonyms='%s' WHERE keyword='%s' AND lang='%s'",
implode(',', $synonyms_arr),
$keyword,
$language
);
return $wpdb->query($query);
}
function delete($keyword, $language = '') {
global $wpdb;
$table = wd_asp()->db->table('synonyms');
$query = $wpdb->prepare(
"DELETE FROM `$table` WHERE keyword='%s' AND lang='%s'",
$keyword,
$language
);
return $wpdb->query($query);
}
function select() {
global $wpdb;
$table = wd_asp()->db->table('synonyms');
return $wpdb->get_results(
"SELECT keyword, synonyms, lang FROM `$table` ORDER BY id DESC LIMIT 15000",
ARRAY_A
);
}
function deleteByID($id) {
global $wpdb;
$table = wd_asp()->db->table('synonyms');
$query = $wpdb->prepare(
"DELETE FROM `$table` WHERE id=%d",
$id
);
return $wpdb->query($query);
}
public function wipe() {
global $wpdb;
$table = wd_asp()->db->table('synonyms');
if ( $table != '' )
$wpdb->query( "TRUNCATE TABLE `$table`" );
}
public function find($keyword = '', $language = '', $limit = 30, $exact = false) {
global $wpdb;
$table = wd_asp()->db->table('synonyms');
if ( $keyword == '' ) {
if ( $language != 'any' )
$lang_query = "WHERE lang LIKE '".esc_sql($language)."' ";
else
$lang_query = '';
$res = $wpdb->get_results(
$wpdb->prepare(
"SELECT keyword, synonyms, lang, id
FROM `$table`
$lang_query
ORDER BY id DESC LIMIT %d",
($limit + 0)
),
ARRAY_A
);
} else {
if ( $language != 'any' )
$lang_query = "AND lang LIKE '".esc_sql($language)."' ";
else
$lang_query = '';
$kw = $exact == true ? $keyword : '%' . $wpdb->esc_like($keyword) . '%';
$res = $wpdb->get_results(
$wpdb->prepare(
"SELECT keyword, synonyms, lang, id,
(
(case when
(keyword LIKE '%s')
then 1 else 0 end
) +
(case when
(keyword LIKE '%s')
then 1 else 0 end
)
) as `relevance`
FROM `$table`
WHERE
keyword LIKE '%s'
$lang_query
ORDER BY relevance DESC, id DESC LIMIT %d",
$keyword,
$wpdb->esc_like($keyword) . '%',
$kw,
($limit + 0)
),
ARRAY_A
);
}
return $res;
}
public function export() {
global $wpdb;
$table = wd_asp()->db->table('synonyms');
return $wpdb->get_results(
"SELECT keyword, synonyms, lang
FROM `$table`
ORDER BY id ASC LIMIT 100000",
ARRAY_A
);
}
public function import( $synonyms ) {
global $wpdb;
$inserted = 0;
$values = array();
$table = wd_asp()->db->table('synonyms');
foreach ( $synonyms as $syn ) {
$value = $wpdb->prepare(
"(%s, %s, %s)",
$syn['keyword'],
$syn['synonyms'], // this is a single string now
$syn['lang']
);
$values[] = $value;
// Split INSERT at every 200 records
if ( count( $values ) > 199 ) {
$values = implode( ', ', $values );
$query = "INSERT IGNORE INTO `$table`
(`keyword`, `synonyms`, `lang`)
VALUES $values";
$inserted += $wpdb->query( $query );
$values = array();
}
}
// Remaining synonyms
if ( count( $values ) > 0 ) {
$values = implode( ', ', $values );
$query = "INSERT IGNORE INTO `$table`
(`keyword`, `synonyms`, `lang`)
VALUES $values";
$inserted += $wpdb->query( $query );
}
return $inserted;
}
public function createTable($table_name = ''): array {
global $wpdb;
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
$return = array();
if ($table_name == '')
$table_name = wd_asp()->db->table('synonyms');
$charset_collate = "";
if ( ! empty( $wpdb->charset ) ) {
$charset_collate_bin_column = "CHARACTER SET $wpdb->charset";
$charset_collate = "DEFAULT $charset_collate_bin_column";
}
if ( strpos( $wpdb->collate, "_" ) > 0 ) {
$charset_collate .= " COLLATE $wpdb->collate";
}
$query = "
CREATE TABLE IF NOT EXISTS `$table_name` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`keyword` varchar(50) NOT NULL,
`synonyms` text CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
`lang` varchar(20) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE (`keyword`, `lang`)
) $charset_collate AUTO_INCREMENT=1 ;";
dbDelta($query);
$wpdb->query($query);
$return[] = $query;
$query = "SHOW INDEX FROM $table_name";
$indices = $wpdb->get_results( $query );
$existing_indices = array();
foreach ( $indices as $index ) {
if ( isset( $index->Key_name ) ) {
$existing_indices[] = $index->Key_name;
}
}
// Worst case scenario optimal indexes
if ( ! in_array( 'keyword_lang', $existing_indices ) ) {
$sql = "CREATE INDEX keyword_lang ON $table_name (keyword(50), lang(20))";
$wpdb->query( $sql );
$return[] = $sql;
}
return $return;
}
}
}

View File

@@ -0,0 +1,361 @@
<?php
namespace WPDRMS\ASP\Synonyms;
use WPDRMS\ASP\Patterns\SingletonTrait;
use WPDRMS\ASP\Utils\FileManager;
use WPDRMS\ASP\Utils\MB;
defined('ABSPATH') or die("You can't access this file directly.");
if ( !class_exists(__NAMESPACE__ . '\Manager') ) {
class Manager {
use SingletonTrait;
private $db;
/**
* Array of synonyms, set during the init process
* @var array
*/
private $synonyms = array();
/**
* False until initialized
* @var bool
*/
private $initialized = false;
/**
* False, until the synonyms as keywords conversion is called
* @var bool
*/
private $converted = false;
function __construct() {
$this->db = new Database();
}
/**
* Gets keyword synonyms, based on keyword+language. Returns all synonyms when $keyword is empty.
*
* @param string $keyword
* @param string $language
* @param bool $refresh
* @return array|bool Array of synonyms, all synonyms array or False on failure.
*/
public function get(string $keyword = '', string $language = '', bool $refresh = false) {
if ( $keyword == '' ) {
if ( $refresh || $this->initialized === false ) {
$this->init();
}
return $this->synonyms; // return all
} else {
$keyword = $this->processKeyword($keyword);
if ( $keyword != '' ) {
if ( $refresh || $this->initialized === false ) {
$this->init();
}
$lang = $language == '' ? 'default' : $language;
if ( isset($this->synonyms[$lang], $this->synonyms[$lang][$keyword]) )
return $this->synonyms[$lang][$keyword];
else
return false;
}
}
return false;
}
/**
* Checks if a keyword+language pair has synonyms.
* If $keyword is empty, checks if there are any synonyms are available
*
* @param string $keyword
* @param string $language
* @return bool
*/
public function exists(string $keyword = '', string $language = ''): bool {
$keyword = $this->processKeyword($keyword);
if ( $this->initialized === false ) {
$this->init();
}
$lang = $language == '' ? 'default' : $language;
if ( $keyword == '' ) {
return count($this->synonyms) > 0;
} else {
return isset($this->synonyms[$lang], $this->synonyms[$lang][$keyword]);
}
}
/**
* Adds a keyword and synonyms to the database
*
* @param string $keyword
* @param string|array $synonyms
* @param string $language
* @return int number of rows inserted
*/
public function add(string $keyword, $synonyms, string $language = ''): int {
$synonyms_arr = $this->processSynonyms($synonyms);
$keyword = $this->processKeyword($keyword);
$language = $this->processKeyword($language);
if ( count($synonyms_arr) < 1 || $keyword == '' ) {
return 0;
} else {
return $this->db->add($keyword, $synonyms_arr, $language);
}
}
/**
* Updates are row, based on $keyword+$lang unique key. If the row does not exist, it is created.
*
* @param string $keyword
* @param string|array $synonyms
* @param string $language
* @param bool $overwrite_existing
* @return int number of affected rows
*/
public function update(string $keyword, $synonyms, string $language = '', bool $overwrite_existing = true): int {
$synonyms_arr = $this->processSynonyms($synonyms);
$keyword = $this->processKeyword($keyword);
$language = $this->processKeyword($language);
if ( count($synonyms_arr) < 1 || $keyword == '' )
return 0;
if ( !$this->exists($keyword, $language) ) {
return $this->add($keyword, $synonyms_arr, $language);
} else {
if ( $overwrite_existing ) {
return $this->db->update($keyword, $synonyms_arr, $language);
} else {
return 0;
}
}
}
/**
* Converts synonyms into keyword => synonym pairs
* @noinspection PhpUnused
*/
public function synonymsAsKeywords() {
if ( $this->initialized === false ) {
$this->init();
}
if ( count($this->synonyms) > 0 && $this->converted == false ) {
foreach ( $this->synonyms as $lang => $synonyms ) {
$additional_syns = array();
foreach ( $synonyms as $kw => $syns ) {
foreach ( $syns as $syn ) {
if ( !isset($additional_syns[$syn]) ) {
$additional_syns[$syn] = array_merge(
array($kw),
array_diff($syns, array($syn))
);
}
}
}
if ( count($additional_syns) > 0 ) {
$this->synonyms[$lang] = array_merge(
$this->synonyms[$lang],
$additional_syns
);
}
}
$this->converted = true;
}
}
/**
* Deletes a row based on keyword+language keys
*
* @param string $keyword
* @param string $language
* @return int number of affected rows
*/
public function delete(string $keyword, string $language = ''): int {
$keyword = $this->processKeyword($keyword);
if ( $keyword != '' ) {
return $this->db->delete($keyword, $language);
} else {
return 0;
}
}
/**
* Deletes a row by ID
*
* @param $id
* @return int number of affected rows
* @noinspection PhpUnused
*/
public function deleteByID($id): int {
$id = (int)$id;
if ( $id != 0 ) {
return $this->db->deleteByID($id);
} else {
return 0;
}
}
/**
* Deletes all rows from the database table
*/
public function wipe() {
$this->db->wipe();
}
/**
* Looks for a synonym based on keyword and language. If keyword is empty, lists all results from the language.
*
* @param string $keyword
* @param string $language When set to 'any', looks in all languages. Empty '' value is the default language.
* @param int $limit
* @param bool $exact
* @return array Results
*/
public function find(string $keyword = '', string $language = '', int $limit = 30, bool $exact = false): array {
return $this->db->find($this->processKeyword($keyword), $language, $limit, $exact);
}
/**
* Generates an export file to the upload directory.
*
* @return int|string -1 on error, 0 when no rows to export, URL of file on success
*/
public function export() {
if ( $this->exists() === false )
return 0;
$res = $this->db->export();
if ( count($res) == 0 )
return 0; // Nothing to export
/** @noinspection PhpComposerExtensionStubsInspection */
$contents = json_encode($res);
$filename = 'asp_synonyms_export.json';
if ( FileManager::instance()->write( wd_asp()->upload_path . $filename , $contents) !== false )
return wd_asp()->upload_url . $filename;
else
return -1;
}
/**
* Imports synonyms from an export file.
*
* @param $path
* @return int Number of affected rows. -2 on file IO errors, -1 on file content errors
*/
public function import($path): int {
$att = attachment_url_to_postid($path);
if ( $att != 0 ) {
$att = get_attached_file($att);
$contents = FileManager::instance()->read($att);
} else {
$contents = FileManager::instance()->read($path);
}
if ( !empty($contents) ) {
$type = wp_check_filetype($path);
if ( $type['ext'] == 'csv' ) {
if ( is_string($att) && $att != '' ) {
$fp = fopen($att, "r");
$csv = array();
$contents = array();
while (($data = fgetcsv($fp)) !== FALSE) {
$csv[] = $data;
}
fclose($fp);
foreach ($csv as $row) {
$new = array();
$new['keyword'] = $row[0];
$new['synonyms'] = array_slice($row, 1);
$new['synonyms'] = array_filter($new['synonyms'], 'strlen');
$new['lang'] = '';
if ( !empty($new['synonyms']) ) {
$new['synonyms'] = implode(',', $new['synonyms']);
$contents[] = $new;
}
}
}
} else {
$contents = str_replace(array("\r", "\n"), '', trim($contents));
/** @noinspection PhpComposerExtensionStubsInspection */
$contents = json_decode($contents, true);
}
if ( is_array($contents) ) {
$contents = array_map(function($synonym){
$synonym['keyword'] = $this->processKeyword($synonym['keyword']);
$synonym['synonyms'] = $this->processKeyword($synonym['synonyms']);
$synonym['lang'] = $this->processKeyword($synonym['lang']);
return $synonym;
}, $contents);
return $this->db->import($contents);
} else {
return -1; // Invalid content?
}
} else {
return -2; // Something went wrong
}
}
/**
* Creates the synonyms table and the constraints.
*
* @param string $table_name
* @return array queries
*/
public function createTable(string $table_name = ''): array {
return $this->db->createTable($table_name);
}
/**
* Initializes the synonyms variable
*/
private function init() {
$res = $this->db->select();
if ( !is_wp_error($res) && count($res) > 0 ) {
$this->synonyms = array();
foreach( $res as $row ) {
$lang = $row['lang'] == '' ? 'default' : $row['lang'];
if ( !isset($this->synonyms[$lang]) )
$this->synonyms[$lang] = array();
$this->synonyms[$lang][$row['keyword']] = wpd_comma_separated_to_array($row['synonyms']);
}
} // else $this->synonyms stays false
$this->initialized = true;
}
/**
* Clears the synonyms array before the DB processing
*
* @param $synonyms
* @return array
*/
private function processSynonyms($synonyms): array {
$synonyms_arr = is_array($synonyms) ?
wpd_comma_separated_to_array(implode(',',$synonyms)) : wpd_comma_separated_to_array($synonyms);
foreach ( $synonyms_arr as &$w ) {
$w = MB::strtolower($w);
$w = trim(preg_replace('/\s+/', ' ', $w));
}
return $synonyms_arr;
}
/**
* Clears the keyword before the DB processing
*
* @param $keyword
* @return string
*/
private function processKeyword($keyword): string {
return preg_replace('/\s+/', ' ', MB::strtolower(trim($keyword)));
}
}
}