Download all files FTP

This commit is contained in:
2026-04-13 15:50:16 +02:00
parent d8382136b2
commit cb5b386424
6906 changed files with 1956223 additions and 40713 deletions

View File

@@ -16,13 +16,62 @@ if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Formatuje kwotÄ™ do postaci 1 000 000,00.
*
* @param mixed $price Surowa wartość ceny.
* @return string
*/
function elementor_addon_format_price( $price ) {
if ( '' === $price || null === $price ) {
return '';
}
$value = wp_strip_all_tags( (string) $price );
$value = str_replace( [ "\xc2\xa0", ' ', 'zł', 'zl' ], '', $value );
$value = preg_replace( '/[^\d,.\-]/u', '', $value );
if ( '' === $value || null === $value ) {
return '';
}
$last_comma = strrpos( $value, ',' );
$last_dot = strrpos( $value, '.' );
if ( false !== $last_comma && false !== $last_dot ) {
if ( $last_comma > $last_dot ) {
$value = str_replace( '.', '', $value );
$value = str_replace( ',', '.', $value );
} else {
$value = str_replace( ',', '', $value );
}
} elseif ( false !== $last_comma ) {
$value = str_replace( '.', '', $value );
$value = str_replace( ',', '.', $value );
} else {
$parts = explode( '.', $value );
if ( count( $parts ) > 2 ) {
$decimal = array_pop( $parts );
$value = implode( '', $parts ) . '.' . $decimal;
}
}
if ( ! is_numeric( $value ) ) {
return trim( (string) $price );
}
return number_format_i18n( (float) $value, 0 );
}
/**
* Register widget files
*/
function register_hello_world_widget( $widgets_manager ) {
require_once( __DIR__ . '/widgets/apartaments.php' );
require_once( __DIR__ . '/widgets/parking-spots.php' );
$widgets_manager->register( new \Elementor_Apartaments() );
$widgets_manager->register( new \Elementor_Parking_Spots() );
}
add_action( 'elementor/widgets/register', 'register_hello_world_widget' );
@@ -86,7 +135,7 @@ function elementor_addon_register_assets() {
add_action( 'wp_enqueue_scripts', 'elementor_addon_register_assets' );
/**
* Przekaż dane do JS (ajaxUrl + nonce) gdy skrypt jest enqueue'owany przez widget.
* PrzekaĹĽ dane do JS (ajaxUrl + nonce) gdy skrypt jest enqueue'owany przez widget.
*/
function elementor_addon_localize_scripts() {
wp_localize_script( 'elementor-addon-main-js', 'apartamentsData', [
@@ -96,12 +145,38 @@ function elementor_addon_localize_scripts() {
}
add_action( 'wp_enqueue_scripts', 'elementor_addon_localize_scripts', 20 );
/**
* Włącza wsparcie "Atrybuty wpisu" (menu_order) dla CPT apartamenty,
* aby można było ręcznie ustawiać kolejność.
*/
function elementor_addon_enable_apartamenty_menu_order( $args, $post_type ) {
if ( 'apartamenty' !== $post_type ) {
return $args;
}
$supports = $args['supports'] ?? [];
if ( true === $supports || false === $supports ) {
$supports = [ 'title', 'editor' ];
}
if ( ! is_array( $supports ) ) {
$supports = (array) $supports;
}
if ( ! in_array( 'page-attributes', $supports, true ) ) {
$supports[] = 'page-attributes';
}
$args['supports'] = $supports;
return $args;
}
add_filter( 'register_post_type_args', 'elementor_addon_enable_apartamenty_menu_order', 20, 2 );
// ===========================================================
// HISTORIA CEN TABELA DB
// HISTORIA CEN — TABELA DB
// ===========================================================
/**
* Tworzy tabelę wp_price_history jeśli nie istnieje lub wersja DB jest stara.
* Tworzy tabelę wp_price_history jeśli nie istnieje lub wersja DB jest stara.
*/
function elementor_addon_create_price_history_table() {
global $wpdb;
@@ -123,27 +198,58 @@ function elementor_addon_create_price_history_table() {
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
dbDelta( $sql );
update_option( 'elementor_addon_db_version', '1.0' );
}
register_activation_hook( __FILE__, 'elementor_addon_create_price_history_table' );
/**
* Sprawdza wersję DB przy każdym init i tworzy tabelę jeśli brakuje.
* Tworzy tabelÄ™ wp_parking_price_history dla miejsc postojowych.
*/
function elementor_addon_create_parking_price_history_table() {
global $wpdb;
$table_name = $wpdb->prefix . 'parking_price_history';
$charset_collate = $wpdb->get_charset_collate();
$sql = "CREATE TABLE {$table_name} (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
parking_type VARCHAR(50) NOT NULL,
price VARCHAR(50) NOT NULL DEFAULT '',
price_m2 VARCHAR(50) NOT NULL DEFAULT '',
recorded_at DATE NOT NULL,
PRIMARY KEY (id),
UNIQUE KEY unique_daily (parking_type, recorded_at),
KEY idx_type (parking_type)
) ENGINE=InnoDB {$charset_collate};";
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
dbDelta( $sql );
}
/**
* Tworzy obie tabele przy aktywacji pluginu.
*/
function elementor_addon_create_tables() {
elementor_addon_create_price_history_table();
elementor_addon_create_parking_price_history_table();
update_option( 'elementor_addon_db_version', '1.1' );
}
register_activation_hook( __FILE__, 'elementor_addon_create_tables' );
/**
* Sprawdza wersję DB przy każdym init i tworzy tabele jeśli brakuje.
*/
function elementor_addon_maybe_update_db() {
if ( get_option( 'elementor_addon_db_version' ) !== '1.0' ) {
elementor_addon_create_price_history_table();
if ( get_option( 'elementor_addon_db_version' ) !== '1.1' ) {
elementor_addon_create_tables();
}
}
add_action( 'init', 'elementor_addon_maybe_update_db' );
// ===========================================================
// HISTORIA CEN CRON DZIENNY
// HISTORIA CEN — CRON DZIENNY
// ===========================================================
/**
* Rejestruje WP Cron jeśli jeszcze nie zaplanowany.
* Rejestruje WP Cron jeśli jeszcze nie zaplanowany.
*/
function elementor_addon_schedule_cron() {
if ( ! wp_next_scheduled( 'apartamenty_record_prices' ) ) {
@@ -153,8 +259,8 @@ function elementor_addon_schedule_cron() {
add_action( 'wp', 'elementor_addon_schedule_cron' );
/**
* Zapisuje aktualne ceny wszystkich apartamentów do tabeli historii.
* Używa INSERT IGNORE jeden rekord na apartament na dzień.
* Zapisuje aktualne ceny wszystkich apartamentĂłw do tabeli historii.
* Używa INSERT IGNORE — jeden rekord na apartament na dzień.
*/
function elementor_addon_record_prices() {
global $wpdb;
@@ -192,11 +298,37 @@ function elementor_addon_record_prices() {
)
);
}
// Miejsca postojowe - zapis cen z ACF options (pola w grupach)
$parking_table = $wpdb->prefix . 'parking_price_history';
$parking_groups = [
'zwykle' => 'miejsce_postojowe_zwykle',
'rodzinne' => 'miejsce_postojowe_rodzinne',
];
foreach ( $parking_groups as $type => $group_name ) {
$group = get_field( $group_name, 'option' ) ?: [];
$price = $group[ $group_name . '_cena' ] ?? '';
$price_m2 = $group[ $group_name . '_cena_m2' ] ?? '';
if ( $price || $price_m2 ) {
$wpdb->query(
$wpdb->prepare(
"INSERT IGNORE INTO {$parking_table} (parking_type, price, price_m2, recorded_at)
VALUES (%s, %s, %s, %s)",
$type,
(string) $price,
(string) $price_m2,
$today
)
);
}
}
}
add_action( 'apartamenty_record_prices', 'elementor_addon_record_prices' );
// ===========================================================
// HISTORIA CEN AJAX ENDPOINT
// HISTORIA CEN - AJAX ENDPOINT
// ===========================================================
/**
@@ -241,12 +373,66 @@ function elementor_addon_get_price_history_ajax() {
add_action( 'wp_ajax_apartamenty_get_price_history', 'elementor_addon_get_price_history_ajax' );
add_action( 'wp_ajax_nopriv_apartamenty_get_price_history', 'elementor_addon_get_price_history_ajax' );
/**
* Zwraca historię cen dla miejsca postojowego jako JSON.
* Parametr: parking_type ('zwykle' lub 'rodzinne')
*/
function elementor_addon_get_parking_price_history_ajax() {
global $wpdb;
if ( ! check_ajax_referer( 'apartamenty_price_history_nonce', 'nonce', false ) ) {
wp_send_json_error( [ 'message' => 'Invalid nonce' ] );
die();
}
$parking_type = sanitize_text_field( $_POST['parking_type'] ?? '' );
if ( ! in_array( $parking_type, [ 'zwykle', 'rodzinne' ], true ) ) {
wp_send_json_error( [ 'message' => 'Invalid parking_type' ] );
die();
}
$labels = [
'zwykle' => 'Miejsce postojowe zwykłe',
'rodzinne' => 'Miejsce postojowe rodzinne',
];
$group_names = [
'zwykle' => 'miejsce_postojowe_zwykle',
'rodzinne' => 'miejsce_postojowe_rodzinne',
];
$table_name = $wpdb->prefix . 'parking_price_history';
$history = $wpdb->get_results(
$wpdb->prepare(
"SELECT recorded_at, price, price_m2
FROM {$table_name}
WHERE parking_type = %s
ORDER BY recorded_at DESC
LIMIT 50",
$parking_type
)
);
$group_name = $group_names[ $parking_type ];
$group = get_field( $group_name, 'option' ) ?: [];
wp_send_json_success( [
'title' => $labels[ $parking_type ],
'price' => $group[ $group_name . '_cena' ] ?? '',
'price_m2' => $group[ $group_name . '_cena_m2' ] ?? '',
'history' => $history,
] );
}
add_action( 'wp_ajax_parking_get_price_history', 'elementor_addon_get_parking_price_history_ajax' );
add_action( 'wp_ajax_nopriv_parking_get_price_history', 'elementor_addon_get_parking_price_history_ajax' );
// ===========================================================
// JAWNOŚĆ CEN — XML ENDPOINTS
// JAWNOŚĆ CEN — XML ENDPOINTS
// ===========================================================
/**
* Rejestruje reguły przepisywania dla endpointów XML.
* Rejestruje reguły przepisywania dla endpointów XML.
*/
function apartamenty_xml_rewrite_rules() {
add_rewrite_rule( '^ceny-mieszkan\.(xml|md5)$', 'index.php?apartamenty_xml=$matches[1]', 'top' );
@@ -255,7 +441,7 @@ function apartamenty_xml_rewrite_rules() {
add_action( 'init', 'apartamenty_xml_rewrite_rules', 10 );
/**
* Dodaje query vars dla endpointów XML.
* Dodaje query vars dla endpointĂłw XML.
*/
function apartamenty_xml_query_vars( $vars ) {
$vars[] = 'apartamenty_xml';
@@ -265,8 +451,8 @@ function apartamenty_xml_query_vars( $vars ) {
add_filter( 'query_vars', 'apartamenty_xml_query_vars' );
/**
* Generuje XML z cenami wszystkich apartamentów.
* Wynik cachowany w transiencie na 1 godzinę.
* Generuje XML z cenami wszystkich apartamentĂłw.
* Wynik cachowany w transiencie na 1 godzinÄ™.
*
* @return string XML jako string
*/
@@ -283,8 +469,10 @@ function apartamenty_generate_price_xml() {
'post_type' => 'apartamenty',
'post_status' => 'publish',
'posts_per_page' => -1,
'orderby' => 'title',
'order' => 'ASC',
'orderby' => [
'menu_order' => 'ASC',
'title' => 'ASC',
],
] );
$x = function( $val ) {
@@ -340,6 +528,58 @@ function apartamenty_generate_price_xml() {
}
}
// Miejsca postojowe
$parking_table = $wpdb->prefix . 'parking_price_history';
$parking_configs = [
'zwykle' => [
'label' => 'Miejsce postojowe zwykłe',
'group_name' => 'miejsce_postojowe_zwykle',
],
'rodzinne' => [
'label' => 'Miejsce postojowe rodzinne',
'group_name' => 'miejsce_postojowe_rodzinne',
],
];
$xml .= "\t<miejsca_postojowe>\n";
foreach ( $parking_configs as $type => $cfg ) {
$group = get_field( $cfg['group_name'], 'option' ) ?: [];
$price = $group[ $cfg['group_name'] . '_cena' ] ?? '';
$price_m2 = $group[ $cfg['group_name'] . '_cena_m2' ] ?? '';
$p_history = $wpdb->get_results(
$wpdb->prepare(
"SELECT recorded_at, price, price_m2
FROM {$parking_table}
WHERE parking_type = %s
ORDER BY recorded_at DESC",
$type
)
);
$last_update = ! empty( $p_history ) ? $p_history[0]->recorded_at : date( 'Y-m-d' );
$xml .= "\t\t" . '<miejsce_postojowe typ="' . $x( $type ) . '">' . "\n";
$xml .= "\t\t\t<nazwa>" . $x( $cfg['label'] ) . "</nazwa>\n";
$xml .= "\t\t\t<cena_brutto>" . $x( $price ) . "</cena_brutto>\n";
$xml .= "\t\t\t<cena_za_m2>" . $x( $price_m2 ) . "</cena_za_m2>\n";
$xml .= "\t\t\t<data_aktualizacji>" . $x( $last_update ) . "</data_aktualizacji>\n";
$xml .= "\t\t\t<historia_cen>\n";
foreach ( $p_history as $row ) {
$xml .= "\t\t\t\t" . '<zmiana data="' . $x( $row->recorded_at ) . '">' . "\n";
$xml .= "\t\t\t\t\t<cena_brutto>" . $x( $row->price ) . "</cena_brutto>\n";
$xml .= "\t\t\t\t\t<cena_za_m2>" . $x( $row->price_m2 ) . "</cena_za_m2>\n";
$xml .= "\t\t\t\t</zmiana>\n";
}
$xml .= "\t\t\t</historia_cen>\n";
$xml .= "\t\t</miejsce_postojowe>\n";
}
$xml .= "\t</miejsca_postojowe>\n";
$xml .= '</lokale>';
set_transient( 'apartamenty_price_xml_cache', $xml, HOUR_IN_SECONDS );
@@ -400,7 +640,7 @@ function apartamenty_generate_datagov_xml() {
}
/**
* Obsługuje żądania do endpointów XML — wysyła odpowiedź i kończy.
* Obsługuje żądania do endpointów XML — wysyła odpowiedź i kończy.
*/
function apartamenty_xml_template_redirect() {
$xml_type = get_query_var( 'apartamenty_xml' );
@@ -433,16 +673,16 @@ function apartamenty_xml_template_redirect() {
add_action( 'template_redirect', 'apartamenty_xml_template_redirect', 1 );
// ===========================================================
// JAWNOŚĆ CEN — STRONA ADMINISTRACYJNA
// JAWNOŚĆ CEN — STRONA ADMINISTRACYJNA
// ===========================================================
/**
* Rejestruje stronę Jawność Cen w menu Narzędzia wp-admin.
* Rejestruje stronę Jawność Cen w menu Narzędzia wp-admin.
*/
function apartamenty_jawnosc_cen_menu() {
add_management_page(
'Jawność Cen',
'Jawność Cen',
'Jawność Cen',
'Jawność Cen',
'manage_options',
'jawnosc-cen',
'apartamenty_jawnosc_cen_page'
@@ -451,17 +691,17 @@ function apartamenty_jawnosc_cen_menu() {
add_action( 'admin_menu', 'apartamenty_jawnosc_cen_menu' );
/**
* Renderuje stronę administracyjną z URL-ami do zgłoszenia.
* Renderuje stronę administracyjną z URL-ami do zgłoszenia.
*/
function apartamenty_jawnosc_cen_page() {
$url_ceny = esc_url( home_url( '/ceny-mieszkan.xml' ) );
$url_datagov = esc_url( home_url( '/dane-gov-pl.xml' ) );
?>
<div class="wrap">
<h1>Jawność Cen — Wyszyńskiego 12</h1>
<h1>Jawność Cen — Wyszyńskiego 12</h1>
<div class="notice notice-info">
<p>Dane aktualizowane codziennie przez WP Cron. Zgłoś URL katalogu dane.gov.pl do administratora portalu: <strong>kontakt@dane.gov.pl</strong></p>
<p>Dane aktualizowane codziennie przez WP Cron. Zgłoś URL katalogu dane.gov.pl do administratora portalu: <strong>kontakt@dane.gov.pl</strong></p>
</div>
<table class="widefat" style="max-width:800px; margin-top:20px;">
@@ -478,15 +718,15 @@ function apartamenty_jawnosc_cen_page() {
<td><code><?php echo $url_ceny; ?></code></td>
<td>
<button class="button" onclick="copyUrl('<?php echo esc_js( $url_ceny ); ?>')">Kopiuj URL</button>
<a href="<?php echo $url_ceny; ?>" target="_blank" class="button">Otwórz XML</a>
<a href="<?php echo $url_ceny; ?>" target="_blank" class="button">OtwĂłrz XML</a>
</td>
</tr>
<tr>
<td><strong>Katalog dane.gov.pl</strong><br><em>(zgłoś Ministerstwu)</em></td>
<td><strong>Katalog dane.gov.pl</strong><br><em>(zgłoś Ministerstwu)</em></td>
<td><code><?php echo $url_datagov; ?></code></td>
<td>
<button class="button button-primary" onclick="copyUrl('<?php echo esc_js( $url_datagov ); ?>')">Kopiuj URL</button>
<a href="<?php echo $url_datagov; ?>" target="_blank" class="button">Otwórz XML</a>
<a href="<?php echo $url_datagov; ?>" target="_blank" class="button">OtwĂłrz XML</a>
</td>
</tr>
</tbody>
@@ -502,4 +742,4 @@ function apartamenty_jawnosc_cen_page() {
}
</script>
<?php
}
}