318 lines
7.8 KiB
PHP
318 lines
7.8 KiB
PHP
<?php
|
|
|
|
namespace ElementorPro\Modules\Notes;
|
|
|
|
use Elementor\Core\Base\Document;
|
|
use ElementorPro\Core\Database\Join_Clause;
|
|
use ElementorPro\Core\Database\Query_Builder;
|
|
use ElementorPro\Core\Utils\Collection;
|
|
use ElementorPro\Modules\Notes\Database\Models\Note;
|
|
|
|
if ( ! defined( 'ABSPATH' ) ) {
|
|
exit; // Exit if accessed directly
|
|
}
|
|
|
|
class Usage {
|
|
|
|
const THREADS = 'threads';
|
|
const REPLIES = 'replies';
|
|
|
|
/**
|
|
* Register hooks.
|
|
*
|
|
* @return void
|
|
*/
|
|
public function register() {
|
|
add_filter( 'elementor/tracker/send_tracking_data_params', function ( array $params ) {
|
|
$params['usages']['notes_feature'] = $this->get_usage_data();
|
|
|
|
return $params;
|
|
} );
|
|
}
|
|
|
|
/**
|
|
* Get the Notes feature usage data.
|
|
*
|
|
* @return array
|
|
*/
|
|
private function get_usage_data() {
|
|
return [
|
|
'threads' => $this->get_threads_usage(),
|
|
'replies' => $this->get_replies_usage(),
|
|
'mentions' => $this->get_mentions_usage(),
|
|
'first_interaction' => $this->get_first_interaction(),
|
|
'last_interaction' => $this->get_last_interaction(),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Get the Threads' usage data.
|
|
*
|
|
* @return array
|
|
*/
|
|
private function get_threads_usage() {
|
|
return [
|
|
'total' => Note::query()
|
|
->only_threads()
|
|
->count(),
|
|
|
|
'resolved' => Note::query()
|
|
->only_threads()
|
|
->where( 'is_resolved', '=', true )
|
|
->count(),
|
|
|
|
'trashed' => Note::query()
|
|
->only_threads()
|
|
->only_trashed()
|
|
->count(),
|
|
|
|
'users_used' => $this->get_notes_users_used( static::THREADS ),
|
|
|
|
'document_type' => $this->get_notes_document_types( static::THREADS ),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Get the replies' usage data.
|
|
*
|
|
* @return array
|
|
*/
|
|
private function get_replies_usage() {
|
|
return [
|
|
'total' => Note::query()
|
|
->only_replies()
|
|
->count(),
|
|
|
|
'trashed' => Note::query()
|
|
->only_replies()
|
|
->only_trashed()
|
|
->count(),
|
|
|
|
'replied_threads' => (int) Note::query()
|
|
->disable_model_initiation()
|
|
->only_replies()
|
|
->select_raw( [ 'COUNT(DISTINCT `parent_id`) AS `count`' ] )
|
|
->first()['count'],
|
|
|
|
'users_used' => $this->get_notes_users_used( static::REPLIES ),
|
|
|
|
'document_type' => $this->get_notes_document_types( static::REPLIES ),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Get the mentions' usage data.
|
|
*
|
|
* @return array
|
|
*/
|
|
private function get_mentions_usage() {
|
|
return [
|
|
'total' => ( new Query_Builder() )
|
|
->table( Module::TABLE_NOTES_USERS_RELATIONS, 'e_notes_relations' )
|
|
->join( function ( Join_Clause $j ) {
|
|
$j->table( Module::TABLE_NOTES, 'e_notes' )
|
|
->on_column( 'e_notes.id', '=', 'e_notes_relations.note_id' );
|
|
} )
|
|
->where( 'type', '=', Note::USER_RELATION_MENTION )
|
|
->where( 'e_notes.status', '!=', Note::STATUS_TRASH )
|
|
->count(),
|
|
|
|
'users_used' => $this->get_mentions_users_used(),
|
|
|
|
'document_type' => ( new Query_Builder() )
|
|
->select( [ 'type' => 'postmeta.meta_value' ] )
|
|
->add_count_select( '*', 'count' )
|
|
->from( Module::TABLE_NOTES_USERS_RELATIONS, 'e_notes_relations' )
|
|
->join( function ( Join_Clause $j ) {
|
|
$j->table( Module::TABLE_NOTES, 'e_notes' )
|
|
->on_column( 'e_notes.id', '=', 'e_notes_relations.note_id' );
|
|
} )
|
|
->join( function ( Join_Clause $j ) {
|
|
$j->table( 'posts' )
|
|
->on_column( 'posts.ID', '=', 'e_notes.post_id' );
|
|
} )
|
|
->join( function ( Join_Clause $j ) {
|
|
$j->table( 'postmeta' )
|
|
->on_column( 'posts.ID', '=', 'postmeta.post_id' )
|
|
->on( 'postmeta.meta_key', '=', Document::TYPE_META_KEY );
|
|
} )
|
|
->where( 'e_notes.status', '!=', Note::STATUS_TRASH )
|
|
->group_by( 'postmeta.meta_value' )
|
|
->get()
|
|
->map_with_keys( function ( $row ) {
|
|
return [ $row['type'] => (int) $row['count'] ];
|
|
} )
|
|
->all(),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Get the first user interaction with the Notes feature.
|
|
*
|
|
* @return string|null
|
|
*/
|
|
private function get_first_interaction() {
|
|
$note = Note::query()
|
|
->with_trashed()
|
|
->select( [ 'created_at' ] )
|
|
->order_by( 'created_at' )
|
|
->first();
|
|
|
|
return $note && $note->created_at
|
|
? $note->created_at->format( 'Y-m-d\TH:i:sO' )
|
|
: null;
|
|
}
|
|
|
|
/**
|
|
* Get the last user interaction with the Notes feature.
|
|
*
|
|
* @return string|null
|
|
*/
|
|
private function get_last_interaction() {
|
|
$note = Note::query()
|
|
->with_trashed()
|
|
->select( [ 'last_activity_at' ] )
|
|
->order_by( 'last_activity_at', 'desc' )
|
|
->first();
|
|
|
|
return $note && $note->last_activity_at
|
|
? $note->last_activity_at->format( 'Y-m-d\TH:i:sO' )
|
|
: null;
|
|
}
|
|
|
|
/**
|
|
* Get the count of `$type` usages grouped by user role.
|
|
*
|
|
* e.g. for 10 replies it can be something like: `{ admin: 7, subscriber: 3 }`
|
|
*
|
|
* @param string $type - Threads or replies.
|
|
*
|
|
* @return array
|
|
*/
|
|
private function get_notes_users_used( $type ) {
|
|
$query = Note::query()
|
|
->disable_model_initiation()
|
|
->select( [ 'user_used_id' => Module::TABLE_NOTES . '.author_id' ] )
|
|
->add_count_select( Module::TABLE_NOTES . '.id', 'count' )
|
|
->group_by( 'user_used_id' );
|
|
|
|
switch ( $type ) {
|
|
case static::THREADS:
|
|
$query->only_threads();
|
|
break;
|
|
|
|
case static::REPLIES:
|
|
$query->only_replies();
|
|
break;
|
|
}
|
|
|
|
return $this->normalize_users_used( $query->get() );
|
|
}
|
|
|
|
/**
|
|
* Get the count of mentions usages grouped by user role.
|
|
*
|
|
* e.g. for 10 mentions it can be something like: `{ admin: 7, subscriber: 3 }`
|
|
*
|
|
* @return array
|
|
*/
|
|
private function get_mentions_users_used() {
|
|
$query = ( new Query_Builder() )
|
|
->from( Module::TABLE_NOTES_USERS_RELATIONS, 'e_notes_relations' )
|
|
->select( [ 'user_used_id' => 'e_notes.author_id' ] )
|
|
->add_count_select( 'e_notes_relations.id', 'count' )
|
|
->join( function ( Join_Clause $j ) {
|
|
$j->table( Module::TABLE_NOTES, 'e_notes' )
|
|
->on_column( 'e_notes_relations.note_id', '=', 'e_notes.id' );
|
|
} )
|
|
->where( 'e_notes_relations.type', '=', Note::USER_RELATION_MENTION )
|
|
->where( 'e_notes.status', '!=', Note::STATUS_TRASH )
|
|
->group_by( 'e_notes.author_id' );
|
|
|
|
return $this->normalize_users_used( $query->get() );
|
|
}
|
|
|
|
/**
|
|
* Normalize `users_used` query results into counts array grouped by user role.
|
|
*
|
|
* @param Collection $query_results
|
|
*
|
|
* @return array
|
|
*/
|
|
private function normalize_users_used( Collection $query_results ) {
|
|
if ( $query_results->is_empty() ) {
|
|
return [];
|
|
}
|
|
|
|
$results = $query_results->map_with_keys( function ( $row ) {
|
|
return [ $row['user_used_id'] => (int) $row['count'] ];
|
|
} );
|
|
|
|
/**
|
|
* @type \WP_User[] $users
|
|
*/
|
|
$users = get_users( [
|
|
'include' => $results->keys(),
|
|
] );
|
|
|
|
$counts = [];
|
|
|
|
foreach ( $users as $user ) {
|
|
/**
|
|
* WordPress also uses the first role.
|
|
*
|
|
* @see https://github.com/WordPress/WordPress/blob/57039311720709d55e96e1a074414ebadba64e00/wp-admin/user-edit.php#L419-L435
|
|
*/
|
|
$role = reset( $user->roles );
|
|
|
|
if ( ! isset( $counts[ $role ] ) ) {
|
|
$counts[ $role ] = 0;
|
|
}
|
|
|
|
$counts[ $role ] += $results->get( $user->ID );
|
|
}
|
|
|
|
return $counts;
|
|
}
|
|
|
|
/**
|
|
* Get the count of `$type` usages grouped by document type.
|
|
*
|
|
* @param string $type - Threads or replies.
|
|
*
|
|
* @return array
|
|
*/
|
|
private function get_notes_document_types( $type ) {
|
|
$query = Note::query()
|
|
->disable_model_initiation()
|
|
->select( [ 'type' => 'postmeta.meta_value' ] )
|
|
->add_count_select( '*', 'count' )
|
|
->join( function ( Join_Clause $j ) {
|
|
$j->table( 'posts' )
|
|
->on_column( 'posts.ID', '=', Module::TABLE_NOTES . '.post_id' );
|
|
} )
|
|
->join( function ( Join_Clause $j ) {
|
|
$j->table( 'postmeta' )
|
|
->on_column( 'posts.ID', '=', 'postmeta.post_id' )
|
|
->on( 'postmeta.meta_key', '=', Document::TYPE_META_KEY );
|
|
} )
|
|
->group_by( 'postmeta.meta_value' );
|
|
|
|
switch ( $type ) {
|
|
case static::THREADS:
|
|
$query->only_threads();
|
|
break;
|
|
|
|
case static::REPLIES:
|
|
$query->only_replies();
|
|
break;
|
|
}
|
|
|
|
return $query->get()
|
|
->map_with_keys( function ( $row ) {
|
|
return [ $row['type'] => (int) $row['count'] ];
|
|
} )
|
|
->all();
|
|
}
|
|
}
|