# learnpress/4.4.8/assets/src/js/admin/statistics/state.js

LearnPress – WordPress LMS Plugin for Create and Sell Online Courses, version 4.4.8. 91 lines.

- Page: https://pluginprobe.com/plugins/learnpress/4.4.8/code/assets/src/js/admin/statistics/state.js
- Raw: https://pluginprobe.com/plugins/learnpress/4.4.8/raw/assets/src/js/admin/statistics/state.js
- Modified: 2026-09-18T11:22:50+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/learnpress/4.4.8/code/assets/src/js/admin/statistics/state.js#L10-L20`.

```javascript
/**
 * Statistics dashboard shared filter state.
 *
 * The singleton is the ONLY mutation path: modules call lpStatsState.set()
 * and every tab module re-renders on the 'lp-stats:filter-changed' event.
 * Tab-specific deep-link params (e.g. order_status) are read by their own
 * tab module — only the four global filters live here.
 *
 * On every set() the five filters are written back to the URL (replaceState,
 * no history spam) so the current view is always copy/paste shareable; other
 * query params (page, tab, order_status, …) are preserved untouched.
 *
 * @since 4.4.2
 * @version 1.2.0
 */

export const LP_STATS_FILTER_CHANGED = 'lp-stats:filter-changed';
export const LP_STATS_EXPORT_CSV = 'lp-stats:export-csv';
// Server-resolved range echoed by a stats payload ( data.range ). Carries the
// authoritative toggle label so the filter bar can reconcile its optimistic one.
export const LP_STATS_RANGE_RESOLVED = 'lp-stats:range-resolved';

const COMPARE_DEFAULT = 'previous_period';

export class LpStatsState {
	constructor() {
		const params = new URL( window.location.href ).searchParams;

		this.filters = {
			filtertype: params.get( 'filtertype' ) || 'today',
			date: params.get( 'date' ) || '',
			compare:
				'previous_year' === params.get( 'compare' )
					? 'previous_year'
					: COMPARE_DEFAULT,
			instructor_id: parseInt( params.get( 'instructor_id' ), 10 ) || 0,
			category_id: parseInt( params.get( 'category_id' ), 10 ) || 0,
		};
	}

	get() {
		return { ...this.filters };
	}

	set( partial = {} ) {
		this.filters = { ...this.filters, ...partial };

		this.syncUrl();

		document.dispatchEvent(
			new CustomEvent( LP_STATS_FILTER_CHANGED, { detail: this.get() } )
		);
	}

	/**
	 * Reflect the current filters in the URL without pushing a history entry.
	 * Defaults (today / empty date / id 0) are dropped to keep URLs clean;
	 * unrelated params (page, tab, order_status, …) are left as-is.
	 */
	syncUrl() {
		if ( ! window.history || typeof window.history.replaceState !== 'function' ) {
			return;
		}

		const url = new URL( window.location.href );
		const params = url.searchParams;
		const { filtertype, date, compare, instructor_id: instructorId, category_id: categoryId } = this.filters;

		this.writeParam( params, 'filtertype', filtertype && filtertype !== 'today' ? filtertype : '' );
		this.writeParam( params, 'date', date );
		this.writeParam( params, 'compare', compare && compare !== COMPARE_DEFAULT ? compare : '' );
		this.writeParam( params, 'instructor_id', instructorId > 0 ? String( instructorId ) : '' );
		this.writeParam( params, 'category_id', categoryId > 0 ? String( categoryId ) : '' );

		window.history.replaceState( null, '', url.toString() );
	}

	/**
	 * Set the param when a truthy value is given, otherwise remove it.
	 */
	writeParam( params, key, value ) {
		if ( value ) {
			params.set( key, value );
		} else {
			params.delete( key );
		}
	}
}

export const lpStatsState = new LpStatsState();

```
