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" } + } + } + } + }); + }); + '); + + ?> +
| Miesiąc | Dystans (km) | Kalorie (kcal) | Czas |
|---|---|---|---|
| month_name ); ?> | +total_distance, 2, ',', ' ' ); ?> | +total_calories, 0, ',', ' ' ); ?> | +total_duration ); ?> | +
| SUMA ROCZNA | ++ | + | + |
Nie udało się wczytać danych z pliku GPX lub plik jest uszkodzony/pusty.
++ 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)); + }); + })();' + ); + } + } + ?>