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,536 @@
(() => {
window.wp.domReady(() => {
init(window.wp);
});
function init(wp) {
/**
* Shortcut variables
*/
const el = wp.element.createElement,
registerBlockType = wp.blocks.registerBlockType,
RawHTML = wp.element.RawHTML,
aaGut = window.advadsGutenberg,
i18n = aaGut.i18n,
textFlow = aaGut.textFlow,
safeHTML = wp.dom.safeHTML,
editor = wp.blockEditor,
comp = wp.components;
/**
* Custom SVG icon
* could move to a separated file if we need it in other places, too
*
* <source> https://gist.github.com/zgordon/e837e29f77c343d29ebb7290a1a75eea
*/
const advadsIconEl = el(
'svg',
{
width: '24px',
height: '24px',
viewBox: '1.396 3276 24 24',
xmlns: 'http://www.w3.org/2000/svg',
x: '0px',
y: '0px',
},
el(
'g',
{},
el('path', {
fill: '#1C1B3A',
d: 'M18.602,3286.2v8.53H6.677v-11.925h8.53c-0.355-0.804-0.545-1.684-0.545-2.625s0.205-1.82,0.545-2.625 h-2.57H1.406v18.266l0.6,0.6l-0.6-0.6c0,2.304,1.875,4.179,4.18,4.179l0,0h7.05h11.216v-13.821 c-0.805,0.355-1.705,0.566-2.645,0.566C20.286,3286.745,19.406,3286.541,18.602,3286.2z',
}),
el('circle', {
fill: '#0E75A4',
cx: '21.206',
cy: '3280.179',
r: '4.18',
})
)
);
/**
* Register the single ad block type
*/
registerBlockType('advads/gblock', {
apiVersion: 2,
title: i18n.advads,
icon: advadsIconEl,
category: 'common',
attributes: {
className: {
type: 'string',
default: '',
},
itemID: {
type: 'string',
default: '',
},
width: {
type: 'string',
default: '',
},
height: {
type: 'string',
default: '',
},
align: {
type: 'string',
default: 'default',
},
},
// todo: make the keywords translatable
keywords: ['advert', 'adsense', 'banner'],
edit: (props) => {
const itemID = props.attributes.itemID;
/**
* Update itemID
*
* @param {Event} event change event on the select input.
*/
function setID(event) {
props.setAttributes({
itemID: event.target.querySelector('option:checked')
.value,
});
}
/**
* Update width
*
* @param {Event} event change event on the number input.
*/
function setWidth(event) {
props.setAttributes({ width: event.target.value });
}
/**
* Update height
*
* @param {Event} event change event on the number input.
*/
function setHeight(event) {
props.setAttributes({ height: event.target.value });
}
/**
* Request hints related to the item.
*
* @param {string} ID Item ID.
*/
function requestHints(ID) {
if (!ID || 0 !== ID.indexOf('group_')) {
setHints([]);
return;
}
const data = new FormData();
data.append('action', 'advads-get-block-hints');
data.append('nonce', window.advadsglobal.ajax_nonce);
data.append('itemID', itemID);
fetch(window.ajaxurl, {
method: 'POST',
credentials: 'same-origin',
body: data,
})
.then((response) => response.json())
.then((json) => {
if (json.success) {
setHints(json.data);
}
})
.catch((error) => {
// eslint-disable-next-line no-console -- Might help experienced users
console.info(error);
});
}
function createSizeInputs(label, name, onchange) {
const randomID =
'advanced-ads-size' +
(Math.random() + 1).toString(36).substring(1);
return el(
'div',
{ className: 'size-group' },
el(
'label',
{ htmlFor: randomID },
el('span', { className: 'head' }, label)
),
el(
'div',
{ className: 'size-input' },
el('input', {
type: 'number',
inputMode: 'numeric',
id: randomID,
value: props.attributes[name],
name,
min: 0,
max: Infinity,
step: 1,
onChange: onchange,
}),
el('span', { className: 'suffix' }, 'px')
)
);
}
const [hints, setHints] = window.wp.element.useState([]);
window.wp.element.useEffect(() => {
requestHints(itemID);
}, [itemID]);
// the form children elements
const children = [];
// argument list (in array form) for the children creation
const args = [],
ads = [],
groups = [],
placements = [];
args.push('select');
args.push({
value: props.attributes.itemID,
onChange: setID,
key: 'advads-select-item',
});
args.push(el('option', { key: 'empty' }, i18n['--empty--']));
for (const adID in aaGut.ads) {
if (typeof aaGut.ads[adID].id === 'undefined') {
continue;
}
ads.push(
el(
'option',
{
value: 'ad_' + aaGut.ads[adID].id,
key: adID,
},
aaGut.ads[adID].title
)
);
}
for (const GID in aaGut.groups) {
if ('undefined' === typeof aaGut.groups[GID].id) {
continue;
}
groups.push(
el(
'option',
{
value: 'group_' + aaGut.groups[GID].id,
key: GID,
},
aaGut.groups[GID].name
)
);
}
if (aaGut.placements) {
for (const pid in aaGut.placements) {
if ('undefined' === typeof aaGut.placements[pid].id) {
continue;
}
placements.push(
el(
'option',
{
value: 'place_' + aaGut.placements[pid].id,
key: pid,
},
aaGut.placements[pid].name
)
);
}
}
if (aaGut.placements) {
args.push(
el(
'optgroup',
{
label: i18n.placements,
key: 'placements',
},
placements
)
);
}
args.push(
el(
'optgroup',
{
label: i18n.adGroups,
key: 'adGroups',
},
groups
)
);
args.push(el('optgroup', { label: i18n.ads, key: 'ads' }, ads));
// add a <label /> first and style it.
children.push(
el(
'div',
{
className: 'components-placeholder__label',
key: 'advads-block-title',
},
advadsIconEl,
el(
'label',
{ style: { display: 'block' } },
i18n.advads
)
)
);
if (itemID && i18n['--empty--'] !== itemID) {
let url = '#';
if (0 === itemID.indexOf('place_')) {
url = aaGut.editLinks.placement;
} else if (0 === itemID.indexOf('group_')) {
url = aaGut.editLinks.group;
} else if (0 === itemID.indexOf('ad_')) {
url = aaGut.editLinks.ad.replace(
'%ID%',
itemID.substr(3)
);
}
children.push(
el(
'div',
{
className: 'components-placeholder__fieldset',
key: 'advads-select-wrap',
},
// then add the <select /> input with its own children
el.apply(null, args),
el('a', {
className: 'dashicons dashicons-external',
style: {
margin: 5,
},
href: url,
target: '_blank',
key: 'advads-item-link',
})
)
);
hints.forEach(function (item, index) {
children.push(
el(
RawHTML,
{
key: index,
className:
'advads-block-hint advads-notice-inline advads-error',
},
safeHTML(item)
)
);
});
} else {
children.push(el.apply(null, args));
}
if (!aaGut.ads.length) {
children.push(
el(
'div',
{
className: 'components-placeholder__label',
key: 'advads-first-ad',
},
'',
el(
'a',
{
href: window.advadsglobal.create_ad_url,
className: 'button',
target: '_blank',
style: {
display: 'block',
marginTop: '10px',
},
},
window.advadsglobal.create_your_first_ad
)
)
);
}
const sizePanel = el(
'div',
{ id: 'advanced-ads-size-wrap' },
el(
'div',
null,
createSizeInputs(i18n.width, 'width', setWidth),
createSizeInputs(i18n.height, 'height', setHeight)
)
);
const sidebar = el(
editor.InspectorControls,
{ key: 'advads-sidebar' },
el(
comp.PanelBody,
{
title: i18n.size,
initialOpen: true,
},
sizePanel
)
);
children.push(sidebar);
const alignmentItems = [];
for (const slug in textFlow) {
const isSelected = props.attributes.align === slug;
alignmentItems.push(
el(
comp.MenuItem,
{
key: slug,
label: textFlow[slug].label,
onClick: () =>
props.setAttributes({ align: slug }),
isSelected,
},
el(
'div',
{
className:
'text-flow-wrap' +
(isSelected ? ' current' : ''),
},
el(
'div',
{
className: 'text-flow-icon',
},
el('img', {
src: `${aaGut.imagesUrl}${slug}.png`,
alt: slug,
title: textFlow[slug].label,
className: 'standard',
}),
el('img', {
src: `${aaGut.imagesUrl}${slug}-alt.png`,
alt: slug,
title: textFlow[slug].label,
className: 'alternate',
})
),
el(
'div',
{
className: 'text-flow-label',
title: textFlow[slug].description,
},
el('span', {}, textFlow[slug].label)
)
)
)
);
}
const toolBar = el(
editor.BlockControls,
{
key: 'advads-toolbar',
group: 'block',
},
el(
comp.ToolbarGroup,
{
title: 'Alignment',
},
el(comp.ToolbarDropdownMenu, {
icon: 'editor-alignleft',
label: 'Choose an alignment',
children: () =>
el(
'div',
{ className: 'advads-align-dropdown' },
alignmentItems
),
})
)
);
// return the complete form
return el(
'div',
editor.useBlockProps(),
el(
'form',
{
className: 'components-placeholder is-large',
},
children
),
toolBar
);
},
save: () => {
// server side rendering
return null;
},
// Transforms legacy widget to Advanced Ads block.
transforms: {
from: [
{
type: 'block',
blocks: ['core/legacy-widget'],
isMatch: (attributes) => {
if (
!attributes.instance ||
!attributes.instance.raw
) {
// Can't transform if raw instance is not shown in REST API.
return false;
}
return attributes.idBase === 'advads_ad_widget';
},
transform: (attributes) => {
const instance = attributes.instance.raw;
const transformedBlock = wp.blocks.createBlock(
'advads/gblock',
{
name: instance.name,
itemID: instance.item_id,
}
);
if (!instance.title) {
return transformedBlock;
}
return [
wp.blocks.createBlock('core/heading', {
content: instance.title,
}),
transformedBlock,
];
},
},
],
},
});
}
})();

View File

@@ -0,0 +1,101 @@
#advanced-ads-size-wrap > div {
display: grid;
grid-template-columns: 50% 50%;
gap: 0.6em;
}
#advanced-ads-size-wrap input[type="number"] {
max-width: calc(100% - 1px);
padding: 0.2em 0.6em;
border: none;
outline: none;
-webkit-appearance: textfield;
-moz-appearance: textfield;
appearance: textfield;
}
#advanced-ads-size-wrap input[type="number"]::-webkit-inner-spin-button,
#advanced-ads-size-wrap input[type="number"]::-webkit-outer-spin-button {
-webkit-appearance: none;
}
#advanced-ads-size-wrap .size-input {
position: relative;
border: 1px solid #949494;
font-size: 14px;
line-height: 14px;
}
#advanced-ads-size-wrap .suffix {
position: absolute;
z-index: 9;
top: 0;
padding: 9px;
right: 2px;
}
.rtl #advanced-ads-size-wrap .suffix {
right: auto;
left: 2px;
}
#advanced-ads-size-wrap .head {
text-transform: uppercase;
font-weight: 500;
font-size: 11px;
}
.text-flow-wrap {
width: 100%;
display: grid;
grid-template-columns: 30% 60%;
gap: 0.5em;
}
.text-flow-wrap::after {
content: "";
display: block;
}
.text-flow-wrap img {
width: 36px;
height: 36px;
float: left;
}
.text-flow-wrap.current img {
width: 48px;
height: 48px;
}
.text-flow-wrap img.standard {
display: inline-block;
}
.text-flow-wrap img.alternate {
display: none;
}
.text-flow-wrap.current img.standard,
.text-flow-wrap:hover img.standard {
display: none;
}
.text-flow-wrap.current img.alternate,
.text-flow-wrap:hover img.alternate {
display: inline-block;
}
.advads-align-dropdown .components-button:focus:not(:disabled) {
box-shadow: none;
}
.advads-align-dropdown .text-flow-label {
display: flex;
align-content: center;
flex-wrap: wrap;
}
.text-flow-wrap.current .text-flow-label {
font-weight: 600;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

@@ -0,0 +1,12 @@
<?php
// module configuration
$path = dirname( __FILE__ );
return [
'classmap' => [
'Advanced_Ads_Gutenberg' => $path . '/includes/class-gutenberg.php',
],
'textdomain' => null,
];

View File

@@ -0,0 +1,280 @@
<?php
// phpcs:ignoreFile
/**
* Gutenberg block registration
*
* @package Advanced_Ads
*/
/**
* Class Advanced_Ads_Gutenberg
*/
class Advanced_Ads_Gutenberg {
/**
* The singleton
*
* @var Advanced_Ads_Gutenberg
*/
private static $instance;
/**
* CSS classes to use on the frontend
*
* @var string
*/
private static $css_class;
/**
* Constructor
*/
private function __construct() {
add_action( 'init', [ $this, 'init' ] );
add_action( 'enqueue_block_editor_assets', [ $this, 'register_scripts' ] );
}
/**
* Register blocks
*/
public function init() {
if ( ! function_exists( 'register_block_type' ) ) {
// no Gutenberg, Abort.
return;
}
register_block_type(
'advads/gblock',
[
'editor_script_handles' => [ ADVADS_PLUGIN_BASENAME . '/gutenberg-ad' ],
'editor_style_handles' => [ ADVADS_PLUGIN_BASENAME . '/gutenberg-ad' ],
'render_callback' => [ $this, 'render_ad_selector' ],
]
);
/**
* Removes legacy widget from legacy widget block.
*
* @param string[] $widget_types An array of excluded widget-type IDs.
*
* @return array
*/
add_filter(
'widget_types_to_hide_from_legacy_widget_block',
function( $widget_types ) {
$widget_types[] = 'advads_ad_widget';
return $widget_types;
}
);
}
/**
* Register back end scripts
*
* @return void
*/
public function register_scripts() {
if ( ! function_exists( 'register_block_type' ) ) {
// no Gutenberg, Abort.
return;
}
wp_register_script(
ADVADS_PLUGIN_BASENAME . '/gutenberg-ad',
ADVADS_BASE_URL . 'modules/gutenberg/assets/advanced-ads.block.js',
[ 'wp-dom-ready', 'wp-blocks', 'wp-element' ],
ADVADS_VERSION,
false
);
$all_ads = wp_advads_ad_query(
[
'post_status' => [ 'publish' ],
'orderby' => 'title',
'order' => 'ASC',
]
)->posts;
$all_groups = wp_advads_get_all_groups();
$ads = [];
$groups = [];
$placements = [];
foreach ( $all_ads as $ad ) {
$ads[] = [
'id' => $ad->ID,
'title' => $ad->post_title,
];
}
foreach ( $all_groups as $group ) {
$groups[] = [
'id' => $group->get_id(),
'name' => $group->get_name(),
];
}
foreach ( wp_advads_get_all_placements() as $placement ) {
if ( $placement->is_type( [ 'sidebar_widget', 'default' ] ) ) {
$placements[] = [
'id' => $placement->get_id(),
'name' => $placement->get_title(),
];
}
}
ksort( $placements );
if ( empty( $placements ) ) {
$placements = false;
}
$i18n = [
'--empty--' => __( '--empty--', 'advanced-ads' ),
'advads' => __( 'Advanced Ads', 'advanced-ads' ),
'ads' => __( 'Ads', 'advanced-ads' ),
'adGroups' => __( 'Ad Groups', 'advanced-ads' ),
'placements' => __( 'Placements', 'advanced-ads' ),
'width' => __( 'Width', 'advanced-ads' ),
'height' => __( 'Height', 'advanced-ads' ),
'size' => __( 'Size', 'advanced-ads' ),
'alignment' => __( 'Alignment', 'advanced-ads' ),
];
$inline_script = wp_json_encode(
[
'ads' => $ads,
'groups' => $groups,
'placements' => $placements,
'editLinks' => [
'group' => admin_url( 'admin.php?page=advanced-ads-groups' ),
'placement' => admin_url( 'admin.php?page=advanced-ads-placements' ),
'ad' => admin_url( 'post.php?post=%ID%&action=edit' ),
],
'imagesUrl' => ADVADS_BASE_URL . 'modules/gutenberg/assets/img/',
'i18n' => $i18n,
'textFlow' => [
'default' => [
'label' => __( "Theme's default", 'advanced-ads' ),
'description' => __( 'The ad will behave as predefined by the theme.', 'advanced-ads' ),
],
'float-left' => [
'label' => __( "Float left", 'advanced-ads' ),
'description' => __( 'Text will wrap around the ad and its margin.', 'advanced-ads' ),
],
'float-right' => [
'label' => __( "Float right", 'advanced-ads' ),
'description' => __( 'Text will wrap around the ad and its margin.', 'advanced-ads' ),
],
'block-left' => [
'label' => __( "Block left", 'advanced-ads' ),
'description' => __( 'Text will continue after the ad and its margin.', 'advanced-ads' ),
],
'block-right' => [
'label' => __( "Block right", 'advanced-ads' ),
'description' => __( 'Text will continue after the ad and its margin.', 'advanced-ads' ),
],
'center' => [
'label' => __( "Centered", 'advanced-ads' ),
'description' => __( 'Text will continue after the ad and its margin.', 'advanced-ads' ),
],
],
]
);
// put the inline code with the global variable right before the block's JS file.
wp_add_inline_script( ADVADS_PLUGIN_BASENAME . '/gutenberg-ad', 'var advadsGutenberg = ' . $inline_script, 'before' );
wp_enqueue_script( ADVADS_PLUGIN_BASENAME . '/gutenberg-ad' );
wp_enqueue_style(
ADVADS_PLUGIN_BASENAME . '/gutenberg-ad',
ADVADS_BASE_URL . 'modules/gutenberg/assets/block.css',
[],
ADVADS_VERSION
);
}
/**
* Server side rendering for single ad block
*
* @param array $attr Block's attributes.
*/
public static function render_ad_selector( $attr ) {
ob_start();
if ( ! isset( $attr['itemID'] ) ) {
ob_end_clean();
return '';
}
$output = [
'output' => [
'class' => ! empty( $attr['className'] ) ? array_filter( explode( ' ', $attr['className'] ) ) : [],
],
];
if ( isset( $attr['fixed_widget'] ) ) {
$output['wrapper_attrs']['data-fixed_widget'] = esc_attr( $attr['fixed_widget'] );
}
if ( ! empty( $attr['width'] ) ) {
$output['output']['wrapper_attrs']['style']['width'] = absint( $attr['width'] ) . 'px';
}
if ( ! empty( $attr['height'] ) ) {
$output['output']['wrapper_attrs']['style']['height'] = absint( $attr['height'] ) . 'px';
}
$align = esc_attr( $attr['align'] ?? 'default' );
$after_ad_filter = function( $output ) {
return $output . '<br style="clear: both; display: block; float: none;">';
};
if ( 0 === strpos( $align, 'block' ) ) {
add_filter( 'advanced-ads-ad-output', $after_ad_filter );
}
switch ( $align ) {
case 'float-left':
case 'block-left':
$output['output']['wrapper_attrs']['style']['float'] = 'left';
break;
case 'float-right':
case 'block-right':
$output['output']['wrapper_attrs']['style']['float'] = 'right';
break;
case 'center':
$output['output']['wrapper_attrs']['style']['margin-left'] = 'auto';
$output['output']['wrapper_attrs']['style']['margin-right'] = 'auto';
$output['output']['wrapper_attrs']['style']['text-align'] = 'center';
break;
default:
}
// phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped -- we can't escape ad output without potentially breaking ads
if ( 0 === strpos( $attr['itemID'], 'ad_' ) ) {
echo get_the_ad( absint( substr( $attr['itemID'], 3 ) ), '', $output );
} elseif ( 0 === strpos( $attr['itemID'], 'group_' ) ) {
echo get_the_group( substr( $attr['itemID'], 6 ), '', $output );
} elseif ( 0 === strpos( $attr['itemID'], 'place_' ) ) {
$id = substr( $attr['itemID'], 6 );
echo get_the_placement( is_numeric( $id ) ? (int) $id : $id, '', $output );
}
// phpcs:enable
return ob_get_clean();
}
/**
* Return the unique instance
*/
public static function get_instance() {
if ( null === self::$instance ) {
self::$instance = new self();
}
return self::$instance;
}
}

View File

@@ -0,0 +1,5 @@
<?php
if ( class_exists( 'Advanced_Ads', false ) ) {
Advanced_Ads_Gutenberg::get_instance();
}