first commit
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
|
||||
namespace Elementor\Modules\GlobalClasses\Usage;
|
||||
|
||||
use Elementor\Modules\GlobalClasses\Global_Classes_Repository;
|
||||
use Elementor\Plugin;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects and exposes usage data for all global CSS classes across Elementor documents.
|
||||
*/
|
||||
class Applied_Global_Classes_Usage {
|
||||
|
||||
/**
|
||||
* Document types that should be excluded from usage reporting.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
private array $excluded_types = [ 'e-flexbox', 'template' ];
|
||||
|
||||
/**
|
||||
* Tracks usage for each global class.
|
||||
*
|
||||
* @var array<string, Css_Class_Usage>
|
||||
*/
|
||||
private array $class_usages = [];
|
||||
|
||||
/**
|
||||
* Returns the total usage count per class ID (excluding template-only classes).
|
||||
*
|
||||
* @return array<string, int>
|
||||
*/
|
||||
public function get(): array {
|
||||
$this->build_class_usages();
|
||||
|
||||
$result = [];
|
||||
foreach ( $this->class_usages as $class_id => $usage ) {
|
||||
if ( $usage->get_total_usage() > 0 ) {
|
||||
$result[ $class_id ] = $usage->get_total_usage();
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns detailed usage information per class ID.
|
||||
* Each class ID maps to a list of document usages (excluding excluded types).
|
||||
*
|
||||
* @return array<string, array{
|
||||
* pageId: int,
|
||||
* title: string,
|
||||
* type: string,
|
||||
* total: int,
|
||||
* elements: string[]
|
||||
* }>
|
||||
*/
|
||||
public function get_detailed_usage(): array {
|
||||
$this->build_class_usages();
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ( $this->class_usages as $class_id => $usage ) {
|
||||
$pages = $usage->get_pages();
|
||||
|
||||
$filtered_pages = array_filter(
|
||||
$pages,
|
||||
fn( $page_data ) => ! in_array( $page_data['type'], $this->excluded_types, true )
|
||||
);
|
||||
|
||||
if ( empty( $filtered_pages ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ( $filtered_pages as $page_id => $page_data ) {
|
||||
$result[ $class_id ][] = [
|
||||
'pageId' => $page_id,
|
||||
'title' => $page_data['title'],
|
||||
'type' => $page_data['type'],
|
||||
'total' => $page_data['total'],
|
||||
'elements' => $page_data['elements'],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the internal usage map from all Elementor documents.
|
||||
*
|
||||
* This method initializes and aggregates class usage from all relevant documents,
|
||||
* merging duplicate class IDs found in multiple pages.
|
||||
*/
|
||||
private function build_class_usages(): void {
|
||||
$this->class_usages = [];
|
||||
|
||||
$class_ids = Global_Classes_Repository::make()
|
||||
->all()
|
||||
->get_items()
|
||||
->keys()
|
||||
->all();
|
||||
|
||||
Plugin::$instance->db->iterate_elementor_documents(
|
||||
function ( $document ) use ( $class_ids ) {
|
||||
$usage = new Document_Usage( $document );
|
||||
$usage->analyze();
|
||||
|
||||
foreach ( $usage->get_usages() as $class_id => $class_usage ) {
|
||||
if ( ! in_array( $class_id, $class_ids, true ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ! isset( $this->class_usages[ $class_id ] ) ) {
|
||||
$this->class_usages[ $class_id ] = $class_usage;
|
||||
} else {
|
||||
$this->class_usages[ $class_id ]->merge( $class_usage );
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
|
||||
namespace Elementor\Modules\GlobalClasses\Usage;
|
||||
|
||||
/**
|
||||
* Tracks usage of a specific global CSS class across multiple Elementor documents.
|
||||
*/
|
||||
class Css_Class_Usage {
|
||||
|
||||
/** @var string */
|
||||
private string $class_id;
|
||||
|
||||
/** @var int */
|
||||
private int $total = 0;
|
||||
|
||||
/**
|
||||
* @var array<int, array{
|
||||
* title: string,
|
||||
* total: int,
|
||||
* elements: string[],
|
||||
* type?: string
|
||||
* }>
|
||||
*/
|
||||
private array $pages = [];
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $class_id Global CSS class ID.
|
||||
*/
|
||||
public function __construct( string $class_id ) {
|
||||
$this->class_id = $class_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Track usage of this class on a specific document and element.
|
||||
*
|
||||
* @param int $page_id Document ID.
|
||||
* @param string $page_title Document title.
|
||||
* @param string $element_id Element ID using this class.
|
||||
* @param string|null $document_type Optional document type (e.g. header, footer, etc).
|
||||
*/
|
||||
public function track_usage( int $page_id, string $page_title, string $element_id, ?string $document_type = null ): void {
|
||||
++$this->total;
|
||||
|
||||
if ( ! isset( $this->pages[ $page_id ] ) ) {
|
||||
$this->pages[ $page_id ] = [
|
||||
'title' => $page_title,
|
||||
'total' => 0,
|
||||
'elements' => [],
|
||||
];
|
||||
|
||||
if ( $document_type ) {
|
||||
$this->pages[ $page_id ]['type'] = $document_type;
|
||||
}
|
||||
}
|
||||
|
||||
++$this->pages[ $page_id ]['total'];
|
||||
$this->pages[ $page_id ]['elements'][] = $element_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge usage data from another instance with the same class ID.
|
||||
*
|
||||
* @param Css_Class_Usage $other The other usage object to merge in.
|
||||
*
|
||||
* @throws \InvalidArgumentException If the class IDs do not match.
|
||||
*/
|
||||
public function merge( Css_Class_Usage $other ): void {
|
||||
if ( $other->get_class_id() !== $this->class_id ) {
|
||||
throw new \InvalidArgumentException( 'Mismatched class ID' );
|
||||
}
|
||||
|
||||
$this->total += $other->get_total_usage();
|
||||
|
||||
foreach ( $other->get_pages() as $page_id => $data ) {
|
||||
if ( ! isset( $this->pages[ $page_id ] ) ) {
|
||||
$this->pages[ $page_id ] = $data;
|
||||
} else {
|
||||
$this->pages[ $page_id ]['total'] += $data['total'];
|
||||
$this->pages[ $page_id ]['elements'] = array_merge(
|
||||
$this->pages[ $page_id ]['elements'],
|
||||
$data['elements']
|
||||
);
|
||||
|
||||
if ( empty( $this->pages[ $page_id ]['type'] ) && ! empty( $data['type'] ) ) {
|
||||
$this->pages[ $page_id ]['type'] = $data['type'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the global class ID this instance tracks.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_class_id(): string {
|
||||
return $this->class_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the total number of elements using this class.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_total_usage(): int {
|
||||
return $this->total;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a map of document usages.
|
||||
*
|
||||
* @return array<int, array{title: string, total: int, elements: string[], type?: string}>
|
||||
*/
|
||||
public function get_pages(): array {
|
||||
return $this->pages;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
namespace Elementor\Modules\GlobalClasses\Usage;
|
||||
|
||||
use Elementor\Plugin;
|
||||
use Elementor\Core\Base\Document as ElementorDocument;
|
||||
use Elementor\Modules\GlobalClasses\Global_Classes_Repository;
|
||||
|
||||
/**
|
||||
* Tracks usage of global CSS classes within a specific Elementor document.
|
||||
*/
|
||||
class Document_Usage {
|
||||
|
||||
|
||||
/** @var ElementorDocument */
|
||||
private ElementorDocument $document;
|
||||
|
||||
/** @var array<string, Css_Class_Usage> */
|
||||
private array $usages = [];
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param ElementorDocument $document The Elementor document object.
|
||||
*/
|
||||
public function __construct( ElementorDocument $document ) {
|
||||
$this->document = $document;
|
||||
}
|
||||
|
||||
/**
|
||||
* Analyze the document to find and record usage of global CSS classes.
|
||||
*/
|
||||
public function analyze(): void {
|
||||
$page_id = $this->document->get_main_id();
|
||||
$page_title = $this->document->get_post()->post_title;
|
||||
$class_ids = $this->get_all_global_class_ids();
|
||||
$elements_data = $this->document->get_elements_raw_data() ?? [];
|
||||
|
||||
$document_type = $this->document->get_type();
|
||||
if ( empty( $document_type ) ) {
|
||||
$document_type = get_post_type( $page_id ) ?? 'unknown';
|
||||
}
|
||||
|
||||
if ( empty( $elements_data ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
Plugin::$instance->db->iterate_data(
|
||||
$elements_data,
|
||||
function ( $element_data ) use ( $class_ids, $page_id, $page_title, $document_type ) {
|
||||
$class_values = $element_data['settings']['classes']['value'] ?? [];
|
||||
|
||||
if ( empty( $class_values ) || ! is_array( $class_values ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ( $class_values as $class_id ) {
|
||||
if ( ! in_array( $class_id, $class_ids, true ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ! isset( $this->usages[ $class_id ] ) ) {
|
||||
$this->usages[ $class_id ] = new Css_Class_Usage( $class_id );
|
||||
}
|
||||
|
||||
$this->usages[ $class_id ]->track_usage(
|
||||
$page_id,
|
||||
$page_title,
|
||||
$element_data['id'] ?? 'unknown',
|
||||
$document_type
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all recorded usages of global CSS classes in this document.
|
||||
*
|
||||
* @return array<string, Css_Class_Usage>
|
||||
*/
|
||||
public function get_usages(): array {
|
||||
return $this->usages;
|
||||
}
|
||||
|
||||
/**֜
|
||||
* Retrieve all registered global CSS class IDs.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
protected function get_all_global_class_ids(): array {
|
||||
return Global_Classes_Repository::make()
|
||||
->all()
|
||||
->get_items()
|
||||
->filter( fn( $item ) => ! empty( $item['id'] ?? null ) )
|
||||
->keys()
|
||||
->all();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace Elementor\Modules\GlobalClasses\Usage;
|
||||
|
||||
use Elementor\Core\Utils\Collection;
|
||||
use Elementor\Modules\GlobalClasses\Usage\Applied_Global_Classes_Usage;
|
||||
use Elementor\Modules\GlobalClasses\Global_Classes_Repository;
|
||||
|
||||
class Global_Classes_Usage {
|
||||
const MIN_CLASSES_COUNT = 1;
|
||||
public function register_hooks() {
|
||||
add_filter( 'elementor/tracker/send_tracking_data_params', fn( $params ) => $this->add_tracking_data( $params ) );
|
||||
}
|
||||
|
||||
private function add_tracking_data( $params ) {
|
||||
$params['usages']['global_classes']['total_count'] = Global_Classes_Repository::make()->all()->get_items()->count();
|
||||
|
||||
if ( 0 === $params['usages']['global_classes']['total_count'] ) {
|
||||
return $params;
|
||||
}
|
||||
|
||||
$applied_global_classes_usage = ( new Applied_Global_Classes_Usage() )->get();
|
||||
|
||||
$applied_global_classes_usage = Collection::make( $applied_global_classes_usage )
|
||||
->filter( fn( $count ) => $count <= self::MIN_CLASSES_COUNT )
|
||||
->keys()
|
||||
->count();
|
||||
|
||||
if ( ! empty( $applied_global_classes_usage ) ) {
|
||||
$params['usages']['global_classes']['low_usage_global_classes_count'] = $applied_global_classes_usage;
|
||||
}
|
||||
|
||||
return $params;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user