Deploy b92dc4b from main

This commit is contained in:
github-actions[bot]
2026-04-12 21:22:34 +00:00
parent 5d4e73b947
commit 102104f4dc
26 changed files with 1503 additions and 163 deletions

47
includes/class-peptide-news-analytics.php Normal file → Executable file
View File

@@ -1,4 +1,5 @@
<?php
declare( strict_types=1 );
/**
* Click analytics tracking and reporting.
*
@@ -16,7 +17,7 @@ class Peptide_News_Analytics {
* @param array $meta Additional context (IP, UA, referrer, etc.).
* @return bool
*/
public static function record_click( $article_id, $meta = array() ) {
public static function record_click( int $article_id, array $meta = array() ): bool {
global $wpdb;
$table = $wpdb->prefix . 'peptide_news_clicks';
@@ -61,7 +62,7 @@ class Peptide_News_Analytics {
* @param int $article_id
* @param string $ip Anonymized IP for unique visitor counting.
*/
private static function update_daily_stats( $article_id, $ip ) {
private static function update_daily_stats( int $article_id, string $ip ): void {
global $wpdb;
$table = $wpdb->prefix . 'peptide_news_daily_stats';
@@ -114,7 +115,7 @@ class Peptide_News_Analytics {
* @param int $limit
* @return array
*/
public static function get_top_articles( $start_date, $end_date, $limit = 20 ) {
public static function get_top_articles( string $start_date, string $end_date, int $limit = 20 ): array {
global $wpdb;
$stats_table = $wpdb->prefix . 'peptide_news_daily_stats';
@@ -143,7 +144,7 @@ class Peptide_News_Analytics {
* @param string $end_date
* @return array
*/
public static function get_click_trends( $start_date, $end_date ) {
public static function get_click_trends( string $start_date, string $end_date ): array {
global $wpdb;
$table = $wpdb->prefix . 'peptide_news_daily_stats';
@@ -167,7 +168,7 @@ class Peptide_News_Analytics {
* @param int $limit
* @return array
*/
public static function get_popular_topics( $start_date, $end_date, $limit = 20 ) {
public static function get_popular_topics( string $start_date, string $end_date, int $limit = 20 ): array {
global $wpdb;
$stats_table = $wpdb->prefix . 'peptide_news_daily_stats';
@@ -221,7 +222,7 @@ class Peptide_News_Analytics {
* @param string $end_date
* @return array
*/
public static function get_device_breakdown( $start_date, $end_date ) {
public static function get_device_breakdown( string $start_date, string $end_date ): array {
global $wpdb;
$table = $wpdb->prefix . 'peptide_news_clicks';
@@ -244,7 +245,7 @@ class Peptide_News_Analytics {
* @param string $end_date
* @return array
*/
public static function get_source_performance( $start_date, $end_date ) {
public static function get_source_performance( string $start_date, string $end_date ): array {
global $wpdb;
$stats_table = $wpdb->prefix . 'peptide_news_daily_stats';
@@ -265,27 +266,41 @@ class Peptide_News_Analytics {
) );
}
/**
* Hard cap on CSV export rows to prevent memory exhaustion on large datasets.
*
* @var int
*/
const CSV_EXPORT_MAX_ROWS = 50000;
/**
* Export click data as CSV-ready array.
*
* @param string $start_date
* @param string $end_date
* @return array
* Capped at CSV_EXPORT_MAX_ROWS to prevent memory exhaustion on sites
* with large click volumes. The cap is applied at the SQL level so
* only the limited result set is ever loaded into PHP memory.
*
* @param string $start_date Y-m-d format.
* @param string $end_date Y-m-d format.
* @return array Array of associative arrays (one per click row).
*/
public static function export_clicks_csv( $start_date, $end_date ) {
public static function export_clicks_csv( string $start_date, string $end_date ): array {
global $wpdb;
$clicks_table = $wpdb->prefix . 'peptide_news_clicks';
$articles_table = $wpdb->prefix . 'peptide_news_articles';
return $wpdb->get_results( $wpdb->prepare(
"SELECT c.clicked_at, a.title, a.source, a.source_url, a.categories,
c.referrer_url, c.page_url, c.device_type, c.session_id
FROM {$clicks_table} c
INNER JOIN {$articles_table} a ON a.id = c.article_id
WHERE DATE(c.clicked_at) BETWEEN %s AND %s
ORDER BY c.clicked_at DESC",
ORDER BY c.clicked_at DESC
LIMIT %d",
$start_date,
$end_date
$end_date,
self::CSV_EXPORT_MAX_ROWS
), ARRAY_A );
}
@@ -294,7 +309,7 @@ class Peptide_News_Analytics {
*
* @return string|null
*/
private static function get_client_ip() {
private static function get_client_ip(): ?string {
$ip_keys = array( 'HTTP_CF_CONNECTING_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_REAL_IP', 'REMOTE_ADDR' );
foreach ( $ip_keys as $key ) {
@@ -316,7 +331,7 @@ class Peptide_News_Analytics {
* @param string $ip
* @return string
*/
private static function anonymize_ip( $ip ) {
private static function anonymize_ip( string $ip ): string {
if ( filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 ) ) {
return preg_replace( '/\.\d+$/', '.0', $ip );
}
@@ -332,7 +347,7 @@ class Peptide_News_Analytics {
* @param string $ua
* @return string
*/
private static function detect_device( $ua ) {
private static function detect_device( string $ua ): string {
$ua = strtolower( $ua );
if ( preg_match( '/(tablet|ipad|playbook|silk)/', $ua ) ) {