From 78808c6ab016df54decb0282669cde3307c237dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacek=20Fefli=C5=84ski?= Date: Tue, 27 Jan 2026 13:09:30 +0100 Subject: [PATCH] Map --- moje-statystyki.php | 358 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 358 insertions(+) diff --git a/moje-statystyki.php b/moje-statystyki.php index e9e00fd..e291fd7 100644 --- a/moje-statystyki.php +++ b/moje-statystyki.php @@ -109,6 +109,44 @@ function mystat_activate() { // --- 2. MENU ADMINA I DASHBOARD --- add_action( 'admin_menu', 'mystat_add_admin_menu' ); +/** + * Set up admin-specific hooks. + */ +function mystat_admin_init_setup() { + add_filter( 'upload_mimes', 'mystat_add_gpx_mime_type' ); + add_filter( 'wp_check_filetype_and_ext', 'mystat_fix_gpx_upload_permission', 10, 4 ); +} +add_action( 'admin_init', 'mystat_admin_init_setup' ); + +/** + * Add GPX support to WordPress Media Library. + * + * @param array $mimes Allowed mime types. + * @return array Modified mime types. + */ +function mystat_add_gpx_mime_type( $mimes ) { + $mimes['gpx'] = 'application/gpx+xml'; + return $mimes; +} + +/** + * Bypasses WordPress's strict file type check for GPX files. + * This is needed because WordPress can be overly cautious with XML-based files. + * + * @param array $data File data. + * @param string $file Full path to the file. + * @param string $filename The filename. + * @param array $mimes Mime types. + * @return array Modified file data. + */ +function mystat_fix_gpx_upload_permission( $data, $file, $filename, $mimes ) { + if ( strtolower( pathinfo( $filename, PATHINFO_EXTENSION ) ) === 'gpx' ) { + $data['ext'] = 'gpx'; + $data['type'] = 'application/gpx+xml'; + } + return $data; +} + function mystat_add_admin_menu() { add_menu_page( 'Moje Statystyki', // Tytuł strony @@ -164,6 +202,15 @@ function mystat_add_admin_menu() { 'mystat-edit-activity', // Slug podmenu 'mystat_edit_activity_page' // Funkcja renderująca ); + + add_submenu_page( + 'moje-statystyki', // Slug rodzica + 'Podsumowanie Roczne', // Tytuł strony + 'Podsumowanie Roczne', // Tytuł w podmenu + 'manage_options', // Wymagane uprawnienia + 'mystat-yearly-summary', // Slug podmenu + 'mystat_yearly_summary_page'// Funkcja renderująca + ); } function mystat_dashboard_page() { @@ -349,6 +396,201 @@ function mystat_equipment_page() { prefix . 'mystat_activities'; + + $current_year = isset( $_GET['year'] ) ? intval( $_GET['year'] ) : current_time( 'Y' ); + + // Pobierz dostępne lata z bazy danych + $available_years = $wpdb->get_col( "SELECT DISTINCT YEAR(date) FROM $table_activities ORDER BY YEAR(date) DESC" ); + if ( empty( $available_years ) ) { + $available_years = [current_time('Y')]; // Domyślny rok, jeśli brak danych + } + + // Zapytanie SQL do grupowania danych miesięcznie + $sql = $wpdb->prepare(" + SELECT + MONTH(date) as month_num, + SUM(distance) as total_distance, + SUM(calories) as total_calories, + SEC_TO_TIME(SUM(TIME_TO_SEC(duration))) as total_duration + FROM $table_activities + WHERE YEAR(date) = %d + GROUP BY month_num + ORDER BY month_num ASC + ", $current_year); + + $monthly_summary = $wpdb->get_results( $sql, OBJECT_K ); // OBJECT_K zwróci tablicę z kluczami będącymi numerami miesięcy + + // Przygotowanie danych dla wszystkich 12 miesięcy + $full_year_summary = []; + $total_year_distance = 0; + $total_year_calories = 0; + $total_year_seconds = 0; + + for ( $i = 1; $i <= 12; $i++ ) { + $month_name = date_i18n( 'F', mktime( 0, 0, 0, $i, 10 ) ); // Nazwa miesiąca + $data = isset( $monthly_summary[$i] ) ? $monthly_summary[$i] : null; + + $full_year_summary[$i] = (object) [ + 'month_name' => $month_name, + 'total_distance' => $data ? $data->total_distance : 0, + 'total_calories' => $data ? $data->total_calories : 0, + 'total_duration' => $data ? $data->total_duration : '00:00:00', + ]; + + $total_year_distance += $full_year_summary[$i]->total_distance; + $total_year_calories += $full_year_summary[$i]->total_calories; + if ( $data && ! empty( $data->total_duration ) ) { + list($h, $m, $s) = explode(':', $data->total_duration); + $total_year_seconds += $h * 3600 + $m * 60 + $s; + } + } + + $total_year_hours = floor($total_year_seconds / 3600); + $total_year_minutes = floor(($total_year_seconds % 3600) / 60); + $total_year_duration_formatted = sprintf('%d godz. %d min.', $total_year_hours, $total_year_minutes); + + // Przygotowanie danych dla wykresu + $chart_labels = []; + $chart_data_distance = []; + foreach ($full_year_summary as $month_data) { + $chart_labels[] = $month_data->month_name; + $chart_data_distance[] = round((float)$month_data->total_distance, 2); + } + + // Włączenie skryptów dla Chart.js + wp_enqueue_script('chart-js', 'https://cdn.jsdelivr.net/npm/chart.js', [], null, true); + wp_register_script('mystat-chart-loader', false); + wp_enqueue_script('mystat-chart-loader'); + wp_add_inline_script('mystat-chart-loader', ' + document.addEventListener("DOMContentLoaded", function() { + const ctx = document.getElementById("mystatYearlyChart"); + if (!ctx) return; + new Chart(ctx, { + type: "bar", + data: { + labels: ' . json_encode($chart_labels) . ', + datasets: [{ + label: "Dystans (km)", + data: ' . json_encode($chart_data_distance) . ', + backgroundColor: "rgba(52, 152, 219, 0.5)", + borderColor: "rgba(52, 152, 219, 1)", + borderWidth: 1 + }] + }, + options: { + responsive: true, + maintainAspectRatio: false, + scales: { + y: { + beginAtZero: true, + title: { display: true, text: "Kilometry" } + } + } + } + }); + }); + '); + + ?> +
+

Podsumowanie Roczne

+ +
+
+ +
+ + + +
+
+
+ +
+

Wykres Dystansu w

+
+
+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + +
MiesiącDystans (km)Kalorie (kcal)Czas
month_name ); ?>total_distance, 2, ',', ' ' ); ?>total_calories, 0, ',', ' ' ); ?>total_duration ); ?>
SUMA ROCZNA
+
+ 20 ] ); + + if ( is_wp_error( $response ) || wp_remote_retrieve_response_code( $response ) !== 200 ) { + return []; + } + + $gpx_content = wp_remote_retrieve_body( $response ); + if ( empty( $gpx_content ) ) { + return []; + } + + libxml_use_internal_errors( true ); + $gpx = simplexml_load_string( $gpx_content ); + libxml_clear_errors(); + + if ( $gpx === false ) { + return []; + } + + $points = []; + if ( isset( $gpx->trk ) ) { + foreach ( $gpx->trk->trkseg as $trkseg ) { + foreach ( $trkseg->trkpt as $trkpt ) { + if ( isset( $trkpt['lat'] ) && isset( $trkpt['lon'] ) ) { + $points[] = [ (float) $trkpt['lat'], (float) $trkpt['lon'] ]; + } + } + } + } + + return $points; +} + function mystat_edit_activity_page() { global $wpdb; $activity_id = isset( $_GET['id'] ) ? intval( $_GET['id'] ) : 0; @@ -414,6 +656,39 @@ function mystat_view_activity_page() { echo ''; } }; + + // Prepare map data if GPX exists + $track_points = []; + if ( ! empty( $activity->gpx_url ) ) { + // Note: For performance, you might want to cache the parsed points in post meta + // rather than parsing the file on every page load. + $track_points = mystat_get_track_from_gpx_url( $activity->gpx_url ); + + if ( ! empty( $track_points ) ) { + // Enqueue Leaflet assets. For simplicity, this is done here. + // A better approach is to use the 'admin_enqueue_scripts' hook. + wp_enqueue_style('leaflet-css', 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.css'); + wp_enqueue_script('leaflet-js', 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.js', [], '1.9.4', true); + + // Pass track data to a script + wp_register_script('mystat-map-loader', false); + wp_enqueue_script('mystat-map-loader'); + wp_add_inline_script('mystat-map-loader', + 'const mystat_track_points = ' . json_encode($track_points) . ';' . + 'document.addEventListener("DOMContentLoaded", function() { + if (typeof L === "undefined" || typeof mystat_track_points === "undefined" || mystat_track_points.length === 0) return; + const map = L.map("mystat-activity-map"); + L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", { + attribution: \'© OpenStreetMap contributors\' + }).addTo(map); + const polyline = L.polyline(mystat_track_points, {color: "#' . esc_js( ltrim($activity->color, '#') ) . '"}).addTo(map); + map.fitBounds(polyline.getBounds().pad(0.1)); + L.marker(mystat_track_points[0]).addTo(map).bindPopup("Start"); + L.marker(mystat_track_points[mystat_track_points.length - 1]).addTo(map).bindPopup("Koniec"); + });' + ); + } + } ?>
@@ -469,6 +744,19 @@ function mystat_view_activity_page() { Plik GPXPobierz plik GPX + + +
+

Mapa Trasy

+
+ gpx_url ) ) : ?> +
+

Mapa Trasy

+
+

Nie udało się wczytać danych z pliku GPX lub plik jest uszkodzony/pusty.

+
+ +
@@ -562,6 +850,9 @@ function mystat_handle_activity_form_submission() { * Renderowanie formularza HTML */ function mystat_render_add_form( $activity = null ) { + // Enqueue media scripts for the uploader + wp_enqueue_media(); + global $wpdb; $table_categories = $wpdb->prefix . 'mystat_categories'; $table_event_types = $wpdb->prefix . 'mystat_event_types'; @@ -689,11 +980,35 @@ function mystat_render_add_form( $activity = null ) { + + + + + + +

+ gpx_url ) ) { + $track_points = mystat_get_track_from_gpx_url( $activity->gpx_url ); + + if ( ! empty( $track_points ) ) { + // Enqueue scripts for the frontend + wp_enqueue_style('leaflet-css', 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.css'); + wp_enqueue_script('leaflet-js', 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.js', [], '1.9.4', true); + + $map_id = 'mystat-map-' . esc_attr( $activity->id ); + + // Pass track data to a script + wp_register_script('mystat-shortcode-map-loader-' . $activity->id, false); + wp_enqueue_script('mystat-shortcode-map-loader-' . $activity->id); + wp_add_inline_script('mystat-shortcode-map-loader-' . $activity->id, + '(function() { + document.addEventListener("DOMContentLoaded", function() { + if (typeof L === "undefined") return; + const trackPoints = ' . json_encode( $track_points ) . '; + const mapId = "' . esc_js($map_id) . '"; + + var container = L.DomUtil.get(mapId); + if(container != null) { container._leaflet_id = null; } + + const map = L.map(mapId); + L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", { + attribution: \'© OpenStreetMap\' + }).addTo(map); + + const polyline = L.polyline(trackPoints, {color: "#3498db"}).addTo(map); + map.fitBounds(polyline.getBounds().pad(0.1)); + }); + })();' + ); + } + } + ?>

title ); ?>

@@ -1009,6 +1363,10 @@ function mystat_single_activity_shortcode_handler( $atts ) { + + +
+