425 lines
9.4 KiB
PHP
425 lines
9.4 KiB
PHP
<?php
|
|
|
|
namespace DgoraWcas\Analytics;
|
|
|
|
use DgoraWcas\Multilingual;
|
|
|
|
if ( ! defined( 'ABSPATH' ) ) {
|
|
exit;
|
|
}
|
|
|
|
class Data {
|
|
|
|
/**
|
|
* @var string
|
|
*/
|
|
private $format = 'Y-m-d H:i:s';
|
|
|
|
/**
|
|
* Date start in format Y-m-d H:i:s
|
|
* @var string
|
|
*/
|
|
private $dateFrom;
|
|
|
|
/**
|
|
* Date end in format Y-m-d H:i:s
|
|
* @var string
|
|
*/
|
|
private $dateTo;
|
|
|
|
/**
|
|
* Available values: 'autocomplete', 'search-results-page'
|
|
* @var string
|
|
*/
|
|
private $context;
|
|
|
|
/**
|
|
* Language
|
|
* @var string
|
|
*/
|
|
private $lang = '';
|
|
|
|
/**
|
|
* Minimum number of phrase repetitions which must occur to be recognized as critical
|
|
* @var int
|
|
*/
|
|
private $minCriticalRep = 3;
|
|
|
|
/**
|
|
* Percentage limit of searches returning results.
|
|
* Above this limit searches will be marked as satisfying
|
|
* Below this limit searches will be marked as not satisfying
|
|
* @var int
|
|
*/
|
|
private $searchesReturningResutlsGoodPercent = 70;
|
|
|
|
/**
|
|
* Constructor
|
|
*
|
|
*/
|
|
public function __construct() {
|
|
$this->setDefaultDateRange();
|
|
}
|
|
|
|
/**
|
|
* Set data range
|
|
*
|
|
* @param string $from | timestamp or Y-m-d H:i:s
|
|
* @param string $to | timestamp or Y-m-d H:i:s
|
|
*
|
|
* @return void
|
|
*/
|
|
public function setDateRange( $from = '', $to = '' ) {
|
|
$from = ! empty( $from ) && is_numeric( $from ) ? date( $this->format, $from ) : $from;
|
|
$to = ! empty( $to ) && is_numeric( $to ) ? date( $this->format, $to ) : $to;
|
|
|
|
if ( ! empty( $from ) && $this->validateDate( $from ) ) {
|
|
$this->dateFrom = $from;
|
|
}
|
|
|
|
if ( ! empty( $to ) && $this->validateDate( $to ) ) {
|
|
$this->dateTo = $to;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set minimum number of phrase repetitions which must occur to be recognized as critical
|
|
*
|
|
* @param int $rep
|
|
*
|
|
* @return void
|
|
*/
|
|
public function minCriticalRep( $rep ) {
|
|
if ( is_numeric( $rep ) && $rep > 0 ) {
|
|
$this->minCriticalRep = $rep;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set default data range - last 30 days
|
|
*
|
|
* @return void
|
|
*/
|
|
public function setDefaultDateRange() {
|
|
$this->dateFrom = date( $this->format, strtotime( 'today - 30 days' ) );
|
|
$this->dateTo = date( $this->format );
|
|
}
|
|
|
|
/**
|
|
* Set language
|
|
*
|
|
* @param string $lang
|
|
*
|
|
* @return void
|
|
*/
|
|
public function setLang( $lang ) {
|
|
if ( Multilingual::isMultilingual() && ! empty( $lang ) ) {
|
|
$this->lang = Multilingual::getDefaultLanguage();
|
|
}
|
|
|
|
if ( Multilingual::isLangCode( $lang ) ) {
|
|
$this->lang = $lang;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set context
|
|
*
|
|
* @param string $context | Available values: 'autocomplete', 'search-results-page'
|
|
*
|
|
* @return void
|
|
*/
|
|
public function setContext( $context ) {
|
|
if ( ! in_array( $context, array( 'autocomplete', 'search-results-page' ) ) ) {
|
|
$context = 'autocomplete';
|
|
}
|
|
|
|
$this->context = $context;
|
|
}
|
|
|
|
/**
|
|
* Get phrases without search results
|
|
*
|
|
* @return array
|
|
*/
|
|
public function getPhrasesWithNoResults() {
|
|
return $this->getPhrases( $this->dateFrom, $this->dateTo, $this->context, false );
|
|
}
|
|
|
|
/**
|
|
* Get phrases with search results
|
|
*
|
|
* @param int $limit
|
|
* @param int $offset
|
|
*
|
|
* @return array
|
|
*/
|
|
public function getPhrasesWithResults( $limit = 10, $offset = 0 ) {
|
|
return $this->getPhrases( $this->dateFrom, $this->dateTo, $this->context, true, null, $limit, $offset );
|
|
}
|
|
|
|
/**
|
|
* Get total searches
|
|
*
|
|
* @param bool $hasResults
|
|
* @param bool $unique - count only unique values
|
|
*
|
|
* @return int
|
|
*/
|
|
public function getTotalSearches( $hasResults, $unique = false ) {
|
|
global $wpdb;
|
|
$total = 0;
|
|
$select = 'COUNT(id)';
|
|
$where = '';
|
|
|
|
if ( $unique ) {
|
|
$select = 'COUNT(DISTINCT phrase)';
|
|
}
|
|
|
|
// Context
|
|
if ( $this->context === 'autocomplete' ) {
|
|
$where .= " AND autocomplete = 1";
|
|
} else {
|
|
$where .= " AND autocomplete = 0";
|
|
}
|
|
|
|
//With results or with no results
|
|
if ( $hasResults ) {
|
|
$where .= " AND hits > 0";
|
|
} else {
|
|
$where .= " AND hits = 0";
|
|
}
|
|
|
|
// Language
|
|
$where .= $this->getLanguageSql();
|
|
|
|
$sql = $wpdb->prepare( "SELECT $select
|
|
FROM $wpdb->dgwt_wcas_stats
|
|
WHERE 1=1
|
|
$where
|
|
AND created_at > %s AND created_at < %s", $this->dateFrom, $this->dateTo );
|
|
|
|
$res = $wpdb->get_var( $sql );
|
|
if ( ! empty( $res ) && is_numeric( $res ) ) {
|
|
$total = absint( $res );
|
|
}
|
|
|
|
return $total;
|
|
}
|
|
|
|
/**
|
|
* Get SQL where clause related to language
|
|
*
|
|
* @param string $lang
|
|
*
|
|
* @return string
|
|
*/
|
|
public function getLanguageSql( $lang = '' ) {
|
|
global $wpdb;
|
|
|
|
$where = '';
|
|
|
|
if ( Multilingual::isMultilingual() ) {
|
|
if ( empty( $lang ) ) {
|
|
$lang = $this->lang;
|
|
}
|
|
|
|
if ( Multilingual::getDefaultLanguage() === $lang ) {
|
|
$where .= $wpdb->prepare( " AND (lang = %s OR lang IS NULL)", $lang );
|
|
} else {
|
|
$where .= $wpdb->prepare( " AND lang = %s", $lang );
|
|
}
|
|
}
|
|
|
|
return $where;
|
|
}
|
|
|
|
/**
|
|
* Get total critical searches
|
|
*
|
|
* @return int
|
|
*/
|
|
public function getTotalCriticalSearches() {
|
|
global $wpdb;
|
|
|
|
$total = 0;
|
|
$where = '';
|
|
|
|
// Language
|
|
$where .= $this->getLanguageSql();
|
|
|
|
$sql = $wpdb->prepare( "SELECT COUNT(*) AS total FROM (
|
|
SELECT phrase, COUNT(id) AS qty
|
|
FROM $wpdb->dgwt_wcas_stats
|
|
WHERE 1=1
|
|
AND created_at > %s AND created_at < %s
|
|
AND autocomplete = 1
|
|
AND solved = 0
|
|
AND hits = 0
|
|
$where
|
|
GROUP BY phrase
|
|
HAVING qty >= %d) AS total", $this->dateFrom, $this->dateTo, $this->minCriticalRep );
|
|
|
|
$res = $wpdb->get_var( $sql );
|
|
if ( ! empty( $res ) && is_numeric( $res ) ) {
|
|
$total = absint( $res );
|
|
}
|
|
|
|
return $total;
|
|
}
|
|
|
|
/**
|
|
* Get critical searches
|
|
*
|
|
* @param int $limit
|
|
* @param int $offset
|
|
*
|
|
* @return array
|
|
*/
|
|
public function getCriticalSearches( $limit = 10, $offset = 0 ) {
|
|
global $wpdb;
|
|
$phrases = array();
|
|
$where = '';
|
|
|
|
// Language
|
|
$where .= $this->getLanguageSql();
|
|
|
|
$sql = $wpdb->prepare( "SELECT phrase, COUNT(id) AS qty
|
|
FROM $wpdb->dgwt_wcas_stats
|
|
WHERE hits = 0
|
|
AND created_at > %s AND created_at < %s
|
|
AND autocomplete = 1
|
|
AND solved = 0
|
|
$where
|
|
GROUP BY phrase
|
|
HAVING qty >= %d
|
|
ORDER BY qty DESC, phrase ASC LIMIT %d,%d", $this->dateFrom, $this->dateTo, $this->minCriticalRep, $offset, $limit );
|
|
|
|
$res = $wpdb->get_results( $sql, ARRAY_A );
|
|
if ( ! empty( $res ) && is_array( $res ) ) {
|
|
$phrases = $res;
|
|
|
|
foreach ( $res as $key => $search ) {
|
|
$phrases[ $key ] = $search;
|
|
}
|
|
}
|
|
|
|
return $phrases;
|
|
}
|
|
|
|
|
|
/**
|
|
*
|
|
* Get search phrases with the frequency of occurrences
|
|
*
|
|
* @param string $dateFrom
|
|
* @param string $dateTo
|
|
* @param string $context
|
|
* @param bool $hasResults
|
|
* @param bool $solved
|
|
* @param int $limit
|
|
* @param int $offset
|
|
*
|
|
* @return array
|
|
*/
|
|
public function getPhrases( $dateFrom, $dateTo, $context, $hasResults, $solved = null, $limit = 10, $offset = 0 ) {
|
|
global $wpdb;
|
|
|
|
$output = array();
|
|
$where = '';
|
|
|
|
// Context
|
|
if ( $context === 'autocomplete' ) {
|
|
$where .= " AND autocomplete = 1";
|
|
} else {
|
|
$where .= " AND autocomplete = 0";
|
|
}
|
|
|
|
//With results or with no results
|
|
if ( $hasResults ) {
|
|
$where .= " AND hits > 0";
|
|
} else {
|
|
$where .= " AND hits = 0";
|
|
}
|
|
|
|
if ( is_bool( $solved ) ) {
|
|
if ( $solved ) {
|
|
$where .= " AND solved = 1";
|
|
} else {
|
|
$where .= " AND solved = 0";
|
|
}
|
|
}
|
|
|
|
// Language
|
|
$where .= $this->getLanguageSql();
|
|
|
|
$sql = $wpdb->prepare( "SELECT phrase, COUNT(id) AS qty
|
|
FROM $wpdb->dgwt_wcas_stats
|
|
WHERE 1=1
|
|
AND created_at > %s AND created_at < %s
|
|
$where
|
|
GROUP BY phrase
|
|
ORDER BY qty DESC, phrase ASC LIMIT %d,%d", $dateFrom, $dateTo, $offset, $limit );
|
|
|
|
$res = $wpdb->get_results( $sql, ARRAY_A );
|
|
if ( ! empty( $res ) && is_array( $res ) ) {
|
|
$output = $res;
|
|
}
|
|
|
|
return $output;
|
|
}
|
|
|
|
/**
|
|
* Mark as solved. Exclude the phrase from critical phrases module.
|
|
*
|
|
* @return bool
|
|
*/
|
|
function markAsSolved( $phrase ) {
|
|
global $wpdb;
|
|
$success = false;
|
|
|
|
$data = array(
|
|
'solved' => 1
|
|
);
|
|
|
|
$where = array(
|
|
'phrase' => $phrase
|
|
);
|
|
|
|
$format = array( '%s' );
|
|
|
|
if ( ! empty( $this->lang ) ) {
|
|
$where['lang'] = $this->lang;
|
|
$format[] = '%s';
|
|
}
|
|
|
|
if ( $wpdb->update( $wpdb->dgwt_wcas_stats, $data, $where, $format ) ) {
|
|
$success = true;
|
|
}
|
|
|
|
return $success;
|
|
}
|
|
|
|
/**
|
|
* Check if the date has properly format
|
|
*
|
|
* @return bool
|
|
*/
|
|
function validateDate( $date, $format = 'Y-m-d H:i:s' ) {
|
|
$d = \DateTime::createFromFormat( $format, $date );
|
|
|
|
return $d && $d->format( $format ) === $date;
|
|
}
|
|
|
|
/**
|
|
* Check if the date has properly format
|
|
*
|
|
* @param int $percentage
|
|
*
|
|
* @return bool
|
|
*/
|
|
function isSearchesReturningResutlsSatisfying( $percentage ) {
|
|
return $percentage >= $this->searchesReturningResutlsGoodPercent;
|
|
}
|
|
}
|