Compare commits

...

10 Commits

Author SHA1 Message Date
3b729f075b automatisation du déploiement du thème
Some checks reported errors
continuous-integration/drone/push Build encountered an error
2024-09-19 14:36:59 +02:00
222f847198 styling new stats 2024-09-16 16:41:29 +02:00
2e236f4653 modifying permissions to allow simple user to see stats 2024-09-16 16:41:08 +02:00
b710fcd5fd handling rating properly 2024-09-13 14:56:13 +02:00
f218280d0b removing unecessary write log 2024-09-13 14:27:55 +02:00
5891a3e418 tweaking api to handle stats from deployed pro frontEnd 2024-09-13 14:27:34 +02:00
03697e497c refining statistics handlin 2024-07-15 16:01:52 +02:00
c8dbc31ea3 refining statistics handlin 2024-07-15 16:01:42 +02:00
10337a71c7 fixing languages problems 2024-07-15 10:19:34 +02:00
7921e48b2d hadnling new statistic dashboard cover 2024-07-09 10:54:30 +02:00
10 changed files with 294 additions and 183 deletions

39
.drone.yml Normal file
View File

@ -0,0 +1,39 @@
---
kind: pipeline
type: ssh
name: Stay Safe | Back-End | Pipeline de déploiement
clone:
disable: true
# DATAS DU SERVEUR DE BUILD
server:
host:
from_secret: build_server_host
user:
from_secret: build_server_user
password:
from_secret: build_server_password
steps:
- name: Clonage du Repo
commands:
- git clone https://git.deligraph.be/Antoine/lhoist-stay-safe__backend-theme.git
- name: Installation du package
commands:
- cd lhoist-stay-safe__backend-theme
- npm install
- name: Build du package
commands:
- cd lhoist-stay-safe__backend-theme
- npm run production
- name: Déploiement sur le serveur de prod
environment:
PROD_SERVER_PATH:
from_secret: prod_server_path
PROD_SERVER_PASSWORD:
from_secret: prod_server_password
PROD_SERVER_THEME_PATH:
from_secret: prod_server_theme_path
commands:
- cd lhoist-stay-safe__backend-theme
- rsync -avhpn -e 'ssh -p 22' ./ $PROD_SERVER_PATH:~/back/wp-content/themes/Deligraph_lhoist --delete

View File

@ -1,6 +1,7 @@
<?php
require_once(__DIR__ . '/includes/errorlog.php');
require_once(__DIR__ . '/includes/utilities.php');
require_once(__DIR__ . '/includes/init.php');
require_once(__DIR__ . '/includes/blocks.php');
require_once(__DIR__ . '/includes/post_types.php');
@ -9,6 +10,7 @@ require_once(__DIR__ . '/includes/logos.php');
require_once(__DIR__ . '/includes/api.php');
require_once(__DIR__ . '/includes/statistics-page.php');
require_once(__DIR__ . '/includes/search-find.php');
require_once(__DIR__ . '/includes/permissions.php');
// require_once(__DIR__ . '/includes/widget.php');
// require_once( __DIR__ . '/includes/taxonomy.php');

View File

@ -49,10 +49,12 @@ function lhoist_datas_permission_callback(
$origin = $request->get_header('origin');
$referer = $request->get_header('referer');
$isLocalHost = $origin === 'http://localhost:3000' && $referer === 'http://localhost:3000/';
$isVercelApp = $origin === 'https://lhoist-stay-safe.vercel.app' && $referer === 'https://lhoist-stay-safe.vercel.app/';
// $isLocalHost = $origin === 'http://localhost:3000' && $referer === 'http://localhost:3000/';
// $isVercelApp = $origin === 'https://lhoist-stay-safe.vercel.app' && $referer === 'https://lhoist-stay-safe.vercel.app/';
$isFrontEndApp = $origin === 'https://stay-safe-lhoist.com' && $referer === 'https://stay-safe-lhoist.com/';
if ($isVercelApp || $isLocalHost) {
if ($isFrontEndApp) {
return true;
}
return false;
@ -65,6 +67,12 @@ function get_latest_game_datas($request)
{
// $language = sanitize_text_field($request['language']);
$currentLanguage = strtolower($request->get_param('current-language')) ?? 'fr';
if ($currentLanguage === "my") {
$currentLanguage = "ms";
}
if ($currentLanguage === "pt") {
$currentLanguage = "pt-pt";
}
// SWITCH TO CURRENT REQUEST LANGUAGE
do_action('wpml_switch_language', $currentLanguage);
@ -115,6 +123,12 @@ function get_game_datas($request)
{
$id = $request->get_param('id');
$currentLanguage = strtolower($request->get_param('current-language')) ?? 'fr';
if ($currentLanguage === "my") {
$currentLanguage = "ms";
}
if ($currentLanguage === "pt") {
$currentLanguage = "pt-pt";
}
// SWITCH TO CURRENT REQUEST LANGUAGE
do_action('wpml_switch_language', $currentLanguage);
@ -156,7 +170,12 @@ function get_all_games_datas($request)
$currentLanguage = strtolower($request->get_param('current-language')) ?? 'fr';
if ($currentLanguage === "my") {
$currentLanguage = "ms";
}
if ($currentLanguage === "pt") {
$currentLanguage = "pt-pt";
}
// SWITCH TO CURRENT REQUEST LANGUAGE
do_action('wpml_switch_language', $currentLanguage);
add_filter('acf/settings/current_language', 'acf_set_language');
@ -171,7 +190,6 @@ function get_all_games_datas($request)
if (!$searchAndFindsQuery->post) {
do_action('wpml_switch_language', "fr");
$searchAndFindsQuery = new WP_Query($args);
write_log("passed");
}
$gamesDatas = array();
@ -216,7 +234,12 @@ function get_interface_page_screen($request)
$id = $request->get_param('id');
$currentLanguage = strtolower($request->get_param('current-language')) ?? 'fr';
if ($currentLanguage === "my") {
$currentLanguage = "ms";
}
if ($currentLanguage === "pt") {
$currentLanguage = "pt-pt";
}
// SWITCH TO CURRENT REQUEST LANGUAGE
do_action('wpml_switch_language', $currentLanguage);
@ -234,6 +257,7 @@ function get_interface_page_screen($request)
// ################ POST GAME STATISTICS ################
function lhoist_sanitize_statistic_datas($datas)
{
$cleanDatas = array();
@ -241,6 +265,7 @@ function lhoist_sanitize_statistic_datas($datas)
$cleanDatas['user_locale'] = isset($datas['user_locale']) ? sanitize_text_field($datas['user_locale']) : null;
$cleanDatas['user_country'] = isset($datas['user_country']) ? sanitize_text_field($datas['user_country']) : null;
$cleanDatas['level_post_id'] = isset($datas['level_post_id']) ? (int) $datas['level_post_id'] : null;
$cleanDatas['level_name'] = isset($datas['level_name']) ? sanitize_text_field($datas['level_name']) : null;
$cleanDatas['level_score'] = isset($datas['level_score']) ? (int) $datas['level_score'] : null;
$cleanDatas['level_completion_time'] = isset($datas['level_completion_time']) ? (int) $datas['level_completion_time'] : null;
@ -270,28 +295,25 @@ function lhoist_check_statistics_datas_formats($datas)
exit;
}
}
function lhoist_convert_post_id($id)
{
$convertedId = apply_filters('wpml_object_id', $id, 'search-and-find', true);
return $convertedId;
}
function lhoist_post_game_datas_statistics(WP_REST_Request $request)
{
$datas = $request->get_json_params();
$datas['level_post_id'] = lhoist_convert_post_id($datas['level_post_id']);
$datas['level_name'] = html_entity_decode(get_the_title($datas['level_post_id']), ENT_QUOTES, 'UTF-8');
$cleanDatas = lhoist_sanitize_statistic_datas($datas);
lhoist_check_statistics_datas_formats($cleanDatas);
global $wpdb;
$datetime = new DateTime("now", new DateTimeZone('Europe/Brussels'));
$gameStats = array(
'session_ID' => "qsdqsdqsdqsd",
'user_locale' => "FR",
'user_country' => "France",
'level_post_id' => 43,
'level_is_completed' => $level_is_completed ?? "0",
'level_completion_time' => 200,
'level_score' => 3,
'date' => $datetime->format('Y-m-d H:i:s'),
);
$table_name = 'wp_app_users_statistics';
$result_check = $wpdb->insert(
$table_name,
@ -338,12 +360,13 @@ function lhoist_post_rating(WP_REST_Request $request)
$cleanDatas = lhoist_sanitize_ratings_datas($datas);
lhoist_check_ratings_datas_formats($cleanDatas);
global $wpdb;
$datetime = new DateTime("now", new DateTimeZone('Europe/Brussels'));
$ratingsDatas = array(
'comment' => "super",
'rating' => 3,
'rating' => $cleanDatas['note'],
'comment' => $cleanDatas['comment'] ?? '',
'date' => $datetime->format('Y-m-d H:i:s'),
);
$table_name = 'wp_app_ratings';

8
includes/permissions.php Normal file
View File

@ -0,0 +1,8 @@
<?php
// function add_custom_capability_to_subscriber()
// {
// $role = get_role('subscriber');
// $role->add_cap('access_custom_options_page');
// }
// add_action('init', 'add_custom_capability_to_subscriber');

View File

@ -20,7 +20,7 @@ function register_statistics_option_page()
add_menu_page(
'Statistiques des jeux',
'Statistiques des jeux',
'manage_options',
'read',
'session-datas-options',
'render_statistics_option_page',
'dashicons-chart-area'
@ -46,7 +46,7 @@ add_action('admin_post_nopriv_download_pdf', 'handle_download_pdf_request');
function handle_download_pdf_request()
{
// Vérifier les autorisations ou les conditions nécessaires
if (!current_user_can('manage_options')) {
if (!current_user_can('read')) {
wp_die('Access Denied');
}
@ -75,7 +75,7 @@ function generate_pdf_from_html($html_content, $filename = 'export.pdf')
$pdf->SetKeywords('Keywords');
// Définir l'en-tête et le pied de page
$pdf->setHeaderData('', PDF_HEADER_LOGO_WIDTH, 'Title', 'Header text');
$pdf->setHeaderData('', PDF_HEADER_LOGO_WIDTH, 'Statistiques de jeu ', 'Lhoist Stay safe');
$pdf->setFooterData(array(0, 64, 0), array(0, 64, 128));
// Définir la police
@ -100,7 +100,7 @@ add_action('admin_post_nopriv_export_csv', 'handle_export_csv_request');
function handle_export_csv_request()
{
// Vérifier les autorisations ou les conditions nécessaires
if (!current_user_can('manage_options')) {
if (!current_user_can('read')) {
wp_die('Access Denied');
}
@ -133,7 +133,8 @@ function export_data_to_csv()
// Écrire les données dans le fichier CSV
foreach ($data as $row) {
$row["level_completion_time"] = $row["level_completion_time"] / 100;
// $row["level_completion_time"] = $row["level_completion_time"] / 100;
fputcsv($file, $row);
}

23
includes/utilities.php Normal file
View File

@ -0,0 +1,23 @@
<?php
function format_milliseconds_to_readable_time($timeInSeconds)
{
// Convert milliseconds to seconds with PHP_ROUND_HALF_UP.
$seconds = (int) $timeInSeconds;
// Calculate hours, minutes, and seconds
$minutes = floor($seconds / 60);
$seconds %= 60;
// Format the result in "H:i:s" format.(int) $string;
$timeFormat = sprintf('%02d:%02d', $minutes, $seconds);
return $timeFormat;
// Output: 00:20:35
}

View File

@ -1,15 +1,15 @@
.dashboard-widget {
@apply pb-12;
&__title {
@apply !text-2xl text-center !font-semibold !text-blue-600;
@apply !text-2xl text-center !font-semibold !text-lhoist;
}
&__preview-picture {
@apply !w-full mx-auto;
max-width: 300px;
@apply !w-full mx-auto my-8;
max-width: 240px;
display: block;
}
&__cta {
@apply bg-blue-500 text-lg !text-white py-4 px-6 rounded-full block w-fit mx-auto;
@apply bg-lhoist text-lg !text-white py-4 px-6 rounded-full block w-fit mx-auto;
text-decoration: none;
transition: all 0.3s;
cusror: pointer;
@ -24,9 +24,18 @@
}
.page-sessions-datas {
.game_stats {
.game_stats,
.rating_stats {
@apply bg-white my-12 !px-16 !py-6;
h2 {
@apply text-3xl font-semibold text-neutral-800 mt-0;
}
h3 {
@apply text-blue-600 uppercase font-bold text-base my-0 tracking-widest mb-4;
}
h4 {
@apply font-normal text-lg font-medium text-slate-400 my-0;
}
box-sizing: border-box;
.page-title {
@ -35,20 +44,12 @@
&__stats-container {
@apply grid md:grid-cols-2 gap-16 overflow-hidden;
}
&__game-title {
@apply text-3xl font-semibold text-neutral-800 mt-0;
}
&__statistics-section {
p,
li {
@apply text-lg text-slate-600;
}
h3 {
@apply text-blue-600 uppercase font-bold text-base my-0 tracking-widest mb-4;
}
h4 {
@apply font-normal text-lg font-medium text-slate-400 my-0;
}
}
&__scores-distribution {
@ -124,6 +125,15 @@
@apply capitalize;
}
}
.rating_stats {
@apply grid grid-cols-2;
h2 {
@apply col-span-2;
}
.average-score {
height: fit-content;
}
}
.download-btns {
@apply flex flex-col md:flex-row gap-x-12 gap-y-4 justify-center my-12;
.dowload-stats {
@ -139,6 +149,12 @@
}
}
.page-rating-datas {
section {
@apply bg-white my-12 !px-16 !py-6;
}
}
#graphic-rating-repartition,
#graphic-score-repartition {
max-height: 400px;
@apply w-fit mt-8;

View File

@ -1,107 +1,7 @@
import Chart from 'chart.js/auto';
import ChartDataLabels from 'chartjs-plugin-datalabels';
function buildDataChart(level) {
const scoreDistribution = level.querySelectorAll(
'.game_stats__scores-distribution .score-data'
);
const scoreDistributionDataset = [];
for (const score of scoreDistribution) {
scoreDistributionDataset.push({
label: '# of Votes',
score: score.getAttribute('score') + 'points',
count: score.getAttribute('count'),
});
}
// console.log('score', scoreDistribution);
// console.log(scoreDistributionDataset);
const colorPalettes = [
['#1d4ed8', '#3b82f6', '#60a5fa', '#93c5fd', '#c3dafe'],
['#1d4ed8', '#3c67dc', '#5b81e0', '#7a9be3', '#99b5e7'],
['#1223C2', '#030E8E', '#3D49C7', '#6D77D0'],
['#1d4ed8', '#3b82f6', '#60a5fa', '#93c5fd', '#c3dafe'],
['#1240a1', '#2e6ee0', '#548bf7', '#81aefd', '#a9d2ff'],
['#0a37a8', '#2d65d4', '#5794ff', '#7dbdff', '#a3dcff'],
['#1a3d9c', '#4271d9', '#75a7ff', '#9fc5ff', '#c6e2ff'],
['#084ba6', '#3a79d6', '#6ba5ff', '#96c3ff', '#badbff'],
['#1137a3', '#3267d6', '#5fa3ff', '#8fc1ff', '#b5e0ff'],
];
const dataTruc = {
labels: ['Red', 'Blue', 'Yellow'],
datasets: [
{
label: 'My First Dataset',
data: [300, 50, 100],
backgroundColor: [
'rgb(255, 99, 132)',
'rgb(54, 162, 235)',
'rgb(255, 205, 86)',
],
hoverOffset: 4,
},
],
};
const data = {
labels: ['Red', 'Blue', 'Yellow'],
datasets: [
{
label: 'My First Dataset',
data: [300, 50, 100],
backgroundColor: [
'rgb(255, 99, 132)',
'rgb(54, 162, 235)',
'rgb(255, 205, 86)',
],
hoverOffset: 4,
},
],
};
new Chart(
document.getElementById('graphic-score-repartition'),
{
type: 'doughnut',
options: {
animation: true,
layout: {
padding: {
right: 50,
},
},
plugins: {
legend: {
position: 'bottom',
},
tooltip: {
enabled: false,
},
},
},
data: {
labels: scoreDistributionDataset.map(
(scoreData) => scoreData.score
),
datasets: [
{
label: scoreDistributionDataset.map(
(scoreData) => scoreData.count
),
backgroundColor: colorPalettes[4],
data: scoreDistributionDataset.map(
(scoreData) => scoreData.score
),
hoverOffset: 14,
},
],
},
}
);
}
function buildDataChart2(level) {
function buildLevelDataCharts(level) {
const scoreDistribution = level.querySelectorAll(
'.game_stats__scores-distribution .score-data'
);
@ -113,15 +13,6 @@ function buildDataChart2(level) {
count: score.getAttribute('count'),
});
}
// const data = [
// { team: 'Red Jaguars', score: 8 },
// { team: 'Blue Barracudas', score: 23 },
// { team: 'Green Monkeys', score: 3 },
// { team: 'Orange Iguanas', score: 15 },
// { team: 'Purple Parrots', score: 7 },
// { team: 'Silver Snakes', score: 1 },
// ];
// console.log('dta', data);
const colorPalettes = [
['#1d4ed8', '#3b82f6', '#60a5fa', '#93c5fd', '#c3dafe'],
['#1d4ed8', '#3c67dc', '#5b81e0', '#7a9be3', '#99b5e7'],
@ -189,25 +80,90 @@ function buildDataChart2(level) {
}
);
}
function buildRatingsDataChart() {
const ratingDistribution = document.querySelectorAll(
'.rating_stats .rating-data'
);
const ratingDistributionDataset = [];
for (const rating of ratingDistribution) {
ratingDistributionDataset.push({
rating: rating.getAttribute('rating'),
count: rating.getAttribute('count'),
});
}
const colorPalettes = [
['#1d4ed8', '#3b82f6', '#60a5fa', '#93c5fd', '#c3dafe'],
['#1d4ed8', '#3c67dc', '#5b81e0', '#7a9be3', '#99b5e7'],
['#1223C2', '#030E8E', '#3D49C7', '#6D77D0'],
['#1d4ed8', '#3b82f6', '#60a5fa', '#93c5fd', '#c3dafe'],
['#1240a1', '#2e6ee0', '#548bf7', '#81aefd', '#a9d2ff'],
['#0a37a8', '#2d65d4', '#5794ff', '#7dbdff', '#a3dcff'],
['#1a3d9c', '#4271d9', '#75a7ff', '#9fc5ff', '#c6e2ff'],
['#084ba6', '#3a79d6', '#6ba5ff', '#96c3ff', '#badbff'],
['#1137a3', '#3267d6', '#5fa3ff', '#8fc1ff', '#b5e0ff'],
];
// console.log('score', scoreDistributionDataset);
new Chart(
document.getElementById('graphic-rating-repartition'),
{
type: 'pie',
data: {
labels: ratingDistributionDataset.map(
(row) => row.rating
),
datasets: [
{
backgroundColor: colorPalettes[4],
label: 'Nombres de joueurs',
data: ratingDistributionDataset.map(
(row) => row.count
),
hoverOffset: 50,
},
],
},
plugins: [ChartDataLabels],
options: {
plugins: {
legend: {
display: false,
position: 'bottom',
},
title: {
display: false,
text: 'Custom Chart Title',
},
datalabels: {
color: '#fff',
anchor: 'center',
font: {
size: 20,
},
formatter: (value, context) => {
return context.chart.data.labels[
context.dataIndex
];
},
// align: 'center',
// offset: 10,
// borderWidth: 2,
// borderColor: '#fff',
// borderRadius: 25,
},
},
},
}
);
}
window.addEventListener('DOMContentLoaded', (event) => {
const levels = document.querySelectorAll('.game_stats');
levels.forEach((level) => {
buildDataChart2(level);
// function updatePercentage(percentage) {
// const overlay = document.querySelector(
// '.donut-chart__overlay'
// );
// const text = document.querySelector(
// '.donut-chart__percentage'
// );
// overlay.style.transform = `rotate(${
// (percentage / 100) * 360
// }deg)`;
// text.textContent = `${percentage}%`;
// }
// // Exemple : mettre à jour le pourcentage à 75%
// updatePercentage(75);
buildLevelDataCharts(level);
});
buildRatingsDataChart();
});

View File

@ -1,6 +1,6 @@
<?php
if (!current_user_can('manage_options')) return;
// if (!current_user_can('manage_options')) return;
global $wpdb;
$table_name = "wp_app_users_statistics";
@ -11,8 +11,13 @@ $level_post_ids = $wpdb->get_col("
");
?>
<h1 class="page-title"><?php echo esc_html(get_admin_page_title()); ?></h1>
<div class="page-sessions-datas">
<h1 class="page-title"><?php echo esc_html(get_admin_page_title()); ?></h1>
<?php foreach ($level_post_ids as $level_post_id) : ?>
<?php $levelPost = get_post($level_post_id); ?>
@ -64,7 +69,6 @@ $level_post_ids = $wpdb->get_col("
<path class="circle" stroke-dasharray="70, 800" d="M18 2.0845 a 15.9155 15.9155 0 0 1 0 31.831 a 15.9155 15.9155 0 0 1 0 -31.831" />
</svg>
<p class="text"><?php echo round($average_level_score, 1) ?></p>
<!-- <div class="donut-average"></div> -->
</div>
<?php endif; ?>
@ -113,23 +117,50 @@ $level_post_ids = $wpdb->get_col("
</section>
<?php endforeach; ?>
<?php
$ratings_table_name = "wp_app_ratings";
$ratings = $wpdb->get_results("
<section class="rating_stats">
<?php
$ratings_table_name = "wp_app_ratings";
$ratings = $wpdb->get_results("
SELECT rating, COUNT(rating) as count
FROM $ratings_table_name
GROUP BY rating
");
$average_app_rating = $wpdb->get_var("
SELECT AVG(rating)
FROM $ratings_table_name
");
?>
<h2>Répartition des notes de l'app</h2>
<!-- <div class="rating_stats__average-score block-data-score"> -->
<?php if ($average_app_rating) : ?>
<div class="average-score">
<h3>Note moyenne</h3>
<svg viewBox="0 -1 40 40" class="circular-chart">
<path class="circle" stroke-dasharray="70, 800" d="M18 2.0845 a 15.9155 15.9155 0 0 1 0 31.831 a 15.9155 15.9155 0 0 1 0 -31.831" />
</svg>
<p class="text"><?php echo round($average_app_rating, 1) ?></p>
<!-- <div class="donut-average"></div> -->
</div>
<?php endif; ?>
<div class="repartition_score">
<h3>Répartition des notes</h3>
<canvas id="graphic-rating-repartition"></canvas>
<ul>
<li class="rating-data" rating="<?php echo "1" ?>" count="2"><span class="data-label"><?php echo "1" ?></span> : <span class="data-value"><?php echo "2" ?></span> <span class="joueurs">joueurs</span></li>
<?php foreach ($ratings as $rating): ?>
<li class="rating-data" rating="<?php echo $rating->rating ?>" count="<?php echo $rating->count ?>"><span class="data-label"><?php echo $rating->rating ?></span> : <span class="data-value"><?php echo $rating->count ?></span> <span class="joueurs">joueurs</span></li>
<?php endforeach; ?>
<li class="rating-data" rating="<?php echo "2" ?>" count="2"><span class="data-label"><?php echo "2" ?></span> : <span class="data-value"><?php echo "2" ?></span> <span class="joueurs">joueurs</span></li>
</ul>
</div>
// echo '<pre>';
// print_r($ratings);
// echo '</pre>';
?>
<section class="ratings">
</section>
</div>

View File

@ -45,6 +45,11 @@ $level_post_ids = $wpdb->get_col("
FROM $table_name
WHERE level_post_id = $level_post_id
");
$average_level_time = $wpdb->get_var("
SELECT AVG(level_completion_time) as average
FROM $table_name
WHERE level_post_id = $level_post_id
");
$completeLevelsScores = $wpdb->get_results("
SELECT level_score
FROM $table_name
@ -62,13 +67,20 @@ $level_post_ids = $wpdb->get_col("
<div class="average-score">
<svg viewBox="0 -1 40 40" class="circular-chart">
<path class="circle" stroke-dasharray="70, 800" d="M18 2.0845
a 15.9155 15.9155 0 0 1 0 31.831
a 15.9155 15.9155 0 0 1 0 -31.831" />
a 15.9155 15.9155 0 0 1 0 31.831
a 15.9155 15.9155 0 0 1 0 -31.831" />
</svg>
<p class="text"><?php echo round($average_level_score, 1) ?></p>
<!-- <div class="donut-average"></div> -->
</div>
<?php endif; ?>
<h3>Temps moyen</h3>
<?php if ($average_level_time) : ?>
<div class="average-time">
<p class="text"><?php echo round($average_level_time, 1) ?> secondes</p>
<!-- <div class="donut-average"></div> -->
</div>
<?php endif; ?>
</div>
<div class="game_stats__scores-distribution ">
@ -92,7 +104,7 @@ $level_post_ids = $wpdb->get_col("
<h4>Répartition des langues</h4>
<ul>
<?php foreach ($users_locales as $users_locale) : ?>
<li><span class="data-label"><?php echo $users_locale->user_locale ?></span> : <?php echo $users_locale->count ?></li>
<li><span class="data-label"><?php echo $users_locale->user_locale ?></span> : <?php echo $users_locale->count ?><span class="joueurs">joueurs</span></li>
<?php endforeach; ?>
</ul>
</div>