AlkantarClanX12
Your IP : 216.73.217.24
<?php
/**
* Analytics class
*
* @package PopupMaker
* @copyright Copyright (c) 2024, Code Atlantic LLC
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Controls the basic analytics methods for Popup Maker
*/
class PUM_Analytics {
/**
* Initializes analytics endpoints and data
*/
public static function init() {
if ( ! self::analytics_enabled() ) {
return;
}
add_action( 'rest_api_init', [ __CLASS__, 'register_endpoints' ] );
add_action( 'wp_ajax_pum_analytics', [ __CLASS__, 'ajax_request' ] );
add_action( 'wp_ajax_nopriv_pum_analytics', [ __CLASS__, 'ajax_request' ] );
add_filter( 'pum_vars', [ __CLASS__, 'pum_vars' ] );
}
/**
* Checks whether analytics is enabled.
*
* @return bool
*/
public static function analytics_enabled() {
$disabled = pum_get_option( 'disable_analytics' ) || popmake_get_option( 'disable_popup_open_tracking' );
return (bool) apply_filters( 'pum_analytics_enabled', ! $disabled );
}
/**
* Get a list of key pairs for each event type.
* Internally used only for meta keys.
*
* Example returns [[open,opened],[conversion,conversion]].
*
* Usage examples:
* - popup_open_count, popup_last_opened
* - popup_conversion_count, popup_last_conversion
*
* @param string $event Event key.
*
* @return mixed
*/
public static function event_keys( $event ) {
$keys = [ $event, rtrim( $event, 'e' ) . 'ed' ];
if ( 'conversion' === $event ) {
$keys[1] = 'conversion';
}
return apply_filters( 'pum_analytics_event_keys', $keys, $event );
}
/**
* Returns an array of valid event types.
*
* @return string[]
*/
public static function valid_events() {
return apply_filters( 'pum_analytics_valid_events', [ 'open', 'conversion' ] );
}
/**
* Track an event.
*
* This is called by various methods including the ajax & rest api requests.
*
* Can be used externally such as after purchase tracking.
*
* @param array $args
*/
public static function track( $args = [] ) {
// TODO: Remove this to support beacon for CTA conversions.
if ( empty( $args['pid'] ) || $args['pid'] <= 0 ) {
return;
}
$event = sanitize_text_field( $args['event'] );
$popup = pum_get_popup( $args['pid'] );
if ( ! pum_is_popup( $popup ) || ! in_array( $event, self::valid_events(), true ) ) {
return;
}
// The analytics endpoints are intentionally public (tracking pixels fire for
// logged-out visitors), so they cannot use a nonce. Apply a lightweight
// per-visitor rate limit to blunt automated counter inflation while leaving
// legitimate tracking untouched.
if ( self::is_rate_limited( (int) $args['pid'], $event ) ) {
return;
}
$popup->increase_event_count( $event );
if ( has_action( 'pum_analytics_' . $event ) ) {
do_action( 'pum_analytics_' . $event, $popup->ID, $args );
}
do_action( 'pum_analytics_event', $args );
}
/**
* Determine whether the current visitor has exceeded the analytics rate limit
* for a given popup + event.
*
* The analytics endpoints are unauthenticated by design, so this provides a
* coarse per-visitor throttle to limit automated counter inflation. The cap is
* deliberately high so it never drops a real visitor's events; only abusive
* volumes are blocked.
*
* @param int $pid Popup ID.
* @param string $event Event key.
* @return bool True when the request should be dropped.
*/
protected static function is_rate_limited( $pid, $event ) {
/**
* Filters the analytics rate limit window (seconds) and max events per window.
*
* @param array $limits [ 'window' => int seconds, 'max' => int events ].
*/
$limits = apply_filters(
'popup_maker/analytics/rate_limit',
[
'window' => 5 * MINUTE_IN_SECONDS,
'max' => 30,
]
);
// A non-positive max disables rate limiting entirely.
if ( empty( $limits['max'] ) || $limits['max'] < 1 ) {
return false;
}
$visitor = self::get_visitor_hash();
$key = 'pum_alrl_' . md5( $visitor . '|' . $pid . '|' . $event );
$count = (int) get_transient( $key );
if ( $count >= (int) $limits['max'] ) {
return true;
}
set_transient( $key, $count + 1, (int) $limits['window'] );
return false;
}
/**
* Build a privacy-preserving identifier for the current visitor.
*
* Hashes the client IP together with the auth salt so no raw IP is ever stored
* in a transient key. Logged-in users are keyed by user ID.
*
* @return string
*/
protected static function get_visitor_hash() {
if ( is_user_logged_in() ) {
return 'u' . get_current_user_id();
}
$ip = isset( $_SERVER['REMOTE_ADDR'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) ) : '';
return wp_hash( $ip );
}
/**
* Process ajax requests.
*
* Only used when WP-JSON Restful API is not available.
*/
public static function ajax_request() {
$args = wp_parse_args(
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
$_REQUEST,
[
'event' => null,
'pid' => null,
'method' => null,
]
);
self::track( $args );
switch ( $args['method'] ) {
case 'image':
self::serve_pixel();
break;
case 'json':
self::serve_json();
break;
default:
self::serve_no_content();
break;
}
}
/**
* @param WP_REST_Request $request
*
* @return WP_Error|mixed
*/
public static function analytics_endpoint( WP_REST_Request $request ) {
$args = $request->get_params();
// Batch beacon: the client may send multiple events in one request as
// an `events` array (debounced/flush-on-exit batching). Each entry is a
// full event payload; process them through the same single-event path.
// Back-compatible — a single-event POST (top-level pid/event) still works.
$batch = self::parse_batch_events( $request, $args );
if ( null !== $batch ) {
foreach ( $batch as $event_args ) {
if ( is_array( $event_args ) && ! empty( $event_args['pid'] ) ) {
self::track( $event_args );
}
}
self::serve_no_content();
return true;
}
if ( ! $args || empty( $args['pid'] ) ) {
return new WP_Error( 'missing_params', __( 'Missing Parameters.', 'default' ), [ 'status' => 404 ] );
}
self::track( $args );
self::serve_no_content();
return true;
}
/**
* Extract a batch of event payloads from the request, if present.
*
* Accepts an `events` parameter that is either a JSON-encoded array
* (sendBeacon FormData can only carry strings) or an already-decoded array.
*
* @param WP_REST_Request $request Request.
* @param array $args Parsed params.
* @return array<int,array>|null Array of event payloads, or null when not a batch.
*/
protected static function parse_batch_events( WP_REST_Request $request, $args ) {
$events = isset( $args['events'] ) ? $args['events'] : $request->get_param( 'events' );
if ( empty( $events ) ) {
return null;
}
if ( is_string( $events ) ) {
$decoded = json_decode( $events, true );
$events = is_array( $decoded ) ? $decoded : null;
}
if ( ! is_array( $events ) || empty( $events ) ) {
return null;
}
// Must be a list of event objects, not an associative single event.
$first = reset( $events );
if ( ! is_array( $first ) ) {
return null;
}
return array_values( $events );
}
/**
* @param $param
*
* @return bool
*/
public static function endpoint_absint( $param ) {
return is_numeric( $param );
}
/**
* Sanitize eventData parameter (matches Pro's approach).
*
* Decodes JSON string to array if needed.
*
* @param mixed $value EventData value (JSON string or array).
*
* @return array Decoded eventData as array.
*/
public static function sanitize_event_data( $value ) {
// If already an array, return as-is.
if ( is_array( $value ) ) {
return $value;
}
// Decode JSON string to array (matches Pro's Request::parse_tracking_data).
if ( is_string( $value ) ) {
$decoded = json_decode( $value, true );
return is_array( $decoded ) ? $decoded : [];
}
return [];
}
/**
* Registers the analytics endpoints
*/
public static function register_endpoints() {
register_rest_route(
self::get_analytics_namespace(),
self::get_analytics_route(),
apply_filters(
'pum_analytics_rest_route_args',
[
'methods' => [ 'GET', 'POST' ],
'callback' => [ __CLASS__, 'analytics_endpoint' ],
'permission_callback' => '__return_true',
'args' => [
'event' => [
'required' => true,
'description' => __( 'Event Type', 'popup-maker' ),
'type' => 'string',
],
'pid' => [
'required' => true,
'description' => __( 'Popup ID', 'popup-maker' ),
'type' => 'integer',
'validation_callback' => [ __CLASS__, 'endpoint_absint' ],
'sanitize_callback' => 'absint',
],
'eventData' => [
'required' => false,
'description' => __( 'Event metadata (JSON or array)', 'popup-maker' ),
'sanitize_callback' => [ __CLASS__, 'sanitize_event_data' ],
],
],
]
)
);
}
/**
* Adds our analytics endpoint to pum_vars
*
* @param array $vars The current pum_vars.
* @return array The updates pum_vars
*/
public static function pum_vars( $vars = [] ) {
$vars['analytics_enabled'] = self::analytics_enabled();
$vars['analytics_route'] = self::get_analytics_route();
if ( function_exists( 'rest_url' ) ) {
$vars['analytics_api'] = esc_url_raw( rest_url( self::get_analytics_namespace() ) );
} else {
$vars['analytics_api'] = false;
}
return $vars;
}
/**
* Gets the analytics namespace
*
* If bypass adblockers is enabled, will return random or custom string. If not, returns 'pum/v1'.
*
* @return string The analytics namespce
* @since 1.13.0
*/
public static function get_analytics_namespace() {
$version = 1;
$namespace = self::customize_endpoint_value( 'pum' );
return "$namespace/v$version";
}
/**
* Gets the analytics route
*
* If bypass adblockers is enabled, will return random or custom string. If not, returns 'analytics'.
*
* @return string The analytics route
* @since 1.13.0
*/
public static function get_analytics_route() {
$route = 'analytics';
return self::customize_endpoint_value( $route );
}
/**
* Customizes the endpoint value given to it
*
* If bypass adblockers is enabled, will return random or custom string. If not, returns the value given to it.
*
* @param string $value The value to, potentially, customize.
* @return string
* @since 1.13.0
*/
public static function customize_endpoint_value( $value = '' ) {
$bypass_adblockers = pum_get_option( 'bypass_adblockers', false );
if ( true === $bypass_adblockers || 1 === intval( $bypass_adblockers ) ) {
switch ( pum_get_option( 'adblock_bypass_url_method', 'custom' ) ) {
case 'custom':
$value = preg_replace( '/[^a-z0-9]+/', '-', pum_get_option( 'adblock_bypass_custom_filename', $value ) );
break;
case 'random':
default:
$site_url = get_site_url();
$value = md5( $site_url . $value );
break;
}
}
return $value;
}
/**
* Creates and returns a 1x1 tracking gif to the browser.
*/
public static function serve_pixel() {
$gif = self::get_file( Popup_Maker::$DIR . 'assets/images/beacon.gif' );
header( 'Content-Type: image/gif' );
header( 'Content-Length: ' . strlen( $gif ) );
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo $gif;
exit;
}
/**
* @param $path
*
* @return bool|string
*/
public static function get_file( $path ) {
if ( function_exists( 'realpath' ) ) {
$path = realpath( $path );
}
// phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
if ( ! $path || ! @is_file( $path ) ) {
return '';
}
// phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
return @file_get_contents( $path );
}
/**
* Returns a 204 no content header.
*/
public static function serve_no_content() {
header( 'HTTP/1.0 204 No Content' );
header( 'Content-Type: image/gif' );
header( 'Content-Length: 0' );
exit;
}
/**
* Serves a proper json response.
*
* @param mixed $data
*/
public static function serve_json( $data = 0 ) {
header( 'Content-Type: application/json' );
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo PUM_Utils_Array::safe_json_encode( $data );
exit;
}
}
Home - Capital GMC Buick Regina
Skip to content
{{ $t(category) }}
Error
{{vehicle.modelData.year}} {{vehicle.modelData.make}} {{vehicle.modelData.model}}
Starting from {{vehicle.modelData.startingPrice | moneyFormat(lang)}}
Welcome to Capital GMC BUICK – REGINA
Thank you for choosing Capital GMC Buick | Regina, your premier certified Buick and GMC dealership proudly serving drivers in Regina and the surrounding communities. Whether you’re searching for a brand-new Buick or GMC vehicle or a meticulously inspected pre-owned model, we have a diverse selection to match your needs and lifestyle.
Beyond our impressive inventory, we offer a seamless and stress-free financing experience through our well-connected finance centre, where our team of experts is dedicated to securing the best loan or lease options for you, quickly, transparently, and hassle-free.
But our commitment to you doesn’t stop at the sale. Our state-of-the-art service centre is staffed with skilled Buick and GMC technicians who use the latest equipment and genuine OEM parts to keep your vehicle running at its best. From routine maintenance to complex repairs, we’ve got you covered.
Experience top-tier customer service, quality vehicles, and expert care, all in one place. Visit Capital GMC Buick | Regina today or call us at 306-205-8072 with any questions. We’re here to help!
Ask a Question
Capital GMC Buick – Regina
Contact Us
Have a question or need assistance? Fill out the form and we will reach out to you as soon as possible.
Notice: JavaScript is required for this content.
CLOSE
Schedule a Visit
Let us know when you are coming and how we can assist you. We can ensure someone will be on hand to help you out at the desired date and time.
Notice: JavaScript is required for this content.
CLOSE
Find a Career
Have a look at our list of available positions and apply online today to join our team!
×
Opportunities to Grow
The auto industry is constantly changing and we want to continue to grow. We offer growth, leadership & mentorship programs to allow our staff to grow with us.
×
Competitive Salary
We have a significant earning potential with incentive-based pay in most roles. We also offer an employee referral bonus with paid bonuses.
×
Health & Dental
We offer a comprehensive benefits package including extended health, dental, and vision care. We also include paramedical, life insurance, paid sick leave, short & long-term disability coverages.
×
Vacation
We value our employees and want everyone to take their vacation time. We offer a minimum of 2 weeks vacation each year.
×
Training & Development
We have many opportunities for paid education and training in-house as well as training from the Manufacturer.
×
$10,000 Cash Giveaway – Terms & Conditions
All October long, stop by Capital GMC Buick Cadillac, to enter for your chance to win $10,000 cash. No purchase is required, but entries must be made in-store.
The contest is open to residents of Saskatchewan who are 18+. Dealership employees and their households are not eligible. Entries will be accepted from October 1 to October 31, 2025. A random draw will take place on November 1, 2025.
The prize is one $10,000 award, paid by cheque, and must be accepted as awarded. Winner will be contacted by phone or email and must respond within 7 days or another entry may be drawn. Odds of winning depend on the number of entries received.By entering, you agree that Capital Automotive Group may use your name and photo for winner announcements. The contest is governed by the laws of Saskatchewan.
Notice: JavaScript is required for this content.
CLOSE