id, $hide_screen) ){
remove_all_actions('admin_notices');
remove_all_actions('all_admin_notices');
}
}
/**
* init
*
* Plugins loaded init hook
* @return void
*/
function init() {
/**
* Include required files.
*/
$this->include_files();
/**
* Redirect to option page after plugin activate
*/
$this->plugin_redirect_option_page();
/**
* Add plugin setting link to the plugin.
*/
add_filter('plugin_action_links_' . PIXELAVO_PLUGIN_BASE, [$this, 'plugins_setting_links']);
}
/**
* Include Require Files
*/
function include_files() {
require_once (PIXELAVO_PL_PATH . 'includes/helper-functions.php');
require_once (PIXELAVO_PL_PATH . 'admin/admin-setting.php');
require_once (PIXELAVO_PL_PATH . 'includes/add-pixel.php');
require_once (PIXELAVO_PL_PATH . 'includes/modifier.php');
if(pixelavo_is_woocommerce_active()) {
require_once (PIXELAVO_PL_PATH . 'includes/pixel-events-data.php');
if(pixelavo_get_option('product_feed', 'pixelavo_settings') == 'on') {
require_once (PIXELAVO_PL_PATH . 'includes/pixel-feed.php');
}
}
if(pixelavo_is_edd_active()) {
require_once (PIXELAVO_PL_PATH . 'includes/pixel-edd-events-data.php');
if(pixelavo_get_option('edd_product_feed', 'pixelavo_settings') == 'on') {
require_once (PIXELAVO_PL_PATH . 'includes/pixel-edd-feed.php');
}
}
if(!empty(pixelavo_get_custom_events())) {
require_once (PIXELAVO_PL_PATH . 'includes/pixel-custom-events-data.php');
}
require_once PIXELAVO_PL_PATH . 'includes/pixel-ajax-events-data.php';
if( is_admin() ){
require_once (PIXELAVO_PL_PATH . 'admin/class-notice-manager.php');
require_once (PIXELAVO_PL_PATH . 'admin/class-diagnostic-data.php');
require_once (PIXELAVO_PL_PATH . 'admin/class-notices.php');
}
add_action('wp_footer', [$this, 'localizedEventsData'], 11);
}
function localizedEventsData() {
global $pixelavoEventsLocalizedData;
if(count($pixelavoEventsLocalizedData) > 0) {
wp_localize_script('pixelavo', 'pixelavo_event', $pixelavoEventsLocalizedData);
}
}
/**
* Scripts
*
* Enqueue style and scripts for frontend part
* @return void
*/
function scripts() {
if(pixelavo_pixel_status()) {
wp_enqueue_script('pixelavo', PIXELAVO_DIR_URL . 'assets/public/js/main.js', ['jquery'], PIXELAVO_VERSION, true);
wp_localize_script('pixelavo', 'pixelavo', [
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('pixelavo_ajax_event_nonce'),
'other_events' => wp_json_encode(array_merge(pixelavo_get_other_events(), ['data' => pixelavo_get_event_common_data()])),
'custom_events' => wp_json_encode(pixelavo_get_custom_events()),
'additional_user_info' => apply_filters('pixelavo_additional_user_info', [], [] ),
'common_params' => pixelavo_get_event_common_data(),
'other_event_options' => [
"download_files" => pixelavo_get_option('download_files', 'pixelavo_download_files'),
"page_scroll" => pixelavo_get_option('page_scroll', 'pixelavo_page_scroll'),
"time_on_page" => pixelavo_get_option('time_on_page', 'pixelavo_time_on_page'),
"form" => pixelavo_get_option('form_submission', 'pixelavo_form_submission'),
],
'is_active' => [
"woo" => pixelavo_is_woocommerce_active(),
'edd' => pixelavo_is_edd_active(),
'fluent_form' => pixelavo_is_fluentform_active(),
'cf7' => pixelavo_is_cf7_active(),
'wpforms' => pixelavo_is_wpforms_active(),
'ht_contactform' => pixelavo_is_ht_contactform_active(),
],
]);
wp_localize_script('pixelavo', 'pixelavo_event', []);
}
}
/**
* Plugins setting links
* @param array plugin default action links
* @return array plugin action link
*/
function plugins_setting_links($links) {
$link = sprintf(
'%2$s',
admin_url('admin.php?page=pixelavo#/pixels'),
__( 'Settings', 'pixelavo' )
);
array_unshift($links, $link);
return $links;
}
/**
* Plugin Active Hook
* Run when plugin is activated
*/
public function plugin_activate_hook() {
// Create database tables for AI features
$this->create_ai_tables();
$events = get_option('pixelavo_events', [
'search' => 'on',
'view_content' => 'on',
'view_category' => 'on',
]);
$edd_events = get_option('pixelavo_edd_events', [
'edd_search' => 'on',
'edd_view_content' => 'on',
'edd_view_category' => 'on',
]);
$other_events = get_option('pixelavo_edd_events', [
'youtube_video' => 'off',
'vimeo_video' => 'off',
'self_hosted_video' => 'off',
'page_scroll' => 'on',
'time_on_page' => 'on',
'download_files' => 'on',
'form_submission' => 'on',
'internal_links' => 'off',
'external_links' => 'off',
]);
$download_files = get_option('pixelavo_download_files', [
'download_files' => [
"download_files_extensions" => ["pdf", "zip"]
]
]);
$time_on_page = get_option('pixelavo_time_on_page', [
'time_on_page' => [
"time_on_page_value" => "10"
]
]);
$page_scroll = get_option('pixelavo_page_scroll', [
'page_scroll' => [
"page_scroll_value" => "30"
]
]);
$form_submission = get_option('pixelavo_form_submission', [
'form_submission' => [
"fluent_form" => [],
"contact_form_7" => [],
"wp_forms" => [],
"ht_contactform" => [],
]
]);
update_option('pixelavo_events', $events);
update_option('pixelavo_edd_events', $edd_events);
update_option('pixelavo_other_events', $other_events);
update_option('pixelavo_download_files', $download_files);
update_option('pixelavo_time_on_page', $time_on_page);
update_option('pixelavo_page_scroll', $page_scroll);
update_option('pixelavo_form_submission', $form_submission);
/* ViewContent Event Settings */
$pixelavo_wc_view_content = get_option('pixelavo_wc_view_content', [
'view_content' => [
'view_content_delay' => 0,
],
]);
update_option('pixelavo_wc_view_content', $pixelavo_wc_view_content);
/* Purchase Event Settings */
$pixelavo_wc_purchase = get_option('pixelavo_wc_purchase', [
'purchase' => [
'purchase_event_trigger' => ['on-hold', 'processing'],
'purchase_additional_info' => 'off',
],
]);
update_option('pixelavo_wc_purchase', $pixelavo_wc_purchase);
add_option('pixelavo_do_activation_redirect', true);
flush_rewrite_rules();
if ( ! get_option( 'pixelavo_installed' ) ) {
update_option( 'pixelavo_installed', time() );
}
}
/**
* Create AI database tables
* @return void
*/
private function create_ai_tables() {
// Load DatabaseInstaller class if it exists
$installer_class = PIXELAVO_PL_PATH . 'admin/settings-panel/includes/classes/Api/Ai/DatabaseInstaller.php';
if (file_exists($installer_class)) {
require_once $installer_class;
\Pixelavo\Api\Ai\DatabaseInstaller::create_tables();
}
}
/**
* Ensure AI tables exist on admin init
* This handles cases where activation hook might have been missed
* @return void
*/
public function ensure_ai_tables_exist() {
// Only check once per admin session to avoid performance impact
if (get_transient('pixelavo_ai_tables_checked')) {
return;
}
$installer_class = PIXELAVO_PL_PATH . 'admin/settings-panel/includes/classes/Api/Ai/DatabaseInstaller.php';
if (file_exists($installer_class)) {
require_once $installer_class;
// Check if table exists, create if not
if (!\Pixelavo\Api\Ai\DatabaseInstaller::table_exists()) {
\Pixelavo\Api\Ai\DatabaseInstaller::create_tables();
}
}
// Set transient to avoid repeated checks (expires in 12 hours)
set_transient('pixelavo_ai_tables_checked', true, 12 * HOUR_IN_SECONDS);
}
/**
* Initialize security notices for AI features
* @return void
*/
public function init_security_notices() {
$notices_class = PIXELAVO_PL_PATH . 'admin/settings-panel/includes/classes/Api/Ai/SecurityNotices.php';
if (file_exists($notices_class)) {
require_once $notices_class;
\Pixelavo\Api\Ai\SecurityNotices::init();
// Enqueue JavaScript for notice dismissal
add_action('admin_footer', [\Pixelavo\Api\Ai\SecurityNotices::class, 'enqueue_notice_scripts']);
}
}
public function halloween_notice() {
$plugins = get_plugins();
if(!empty($plugins['pixelavo-pro/pixelavo-pro.php'])) {
return;
}
$url = 'https://pixelavo.com/pricing/?utm_source=halloween&utm_medium=dashboard#pixelavo-pricing';
$image = PIXELAVO_PL_URL . '/admin/settings-panel/assets/images/banner/halloween-2025.png';
\Pixelavo_Notice::set_notice(
[
'id' => 'pixelavo-halloween-notice',
'type' => 'notice',
'dismissible' => true,
'message_type' => 'banner',
'banner' => [
'url' => esc_url_raw($url),
'image' => ''
],
'close_by' => 'transient'
]
);
}
/**
* User Login
* @param string $user_login
* @param \WP_User $user
* @return void
*/
public function user_login($user_login, $user) {
if(pixelavo_other_event_exists('login')) {
// Don't double-fire Login when this is part of a fresh registration
// (CompleteRegistration already fired in the same request).
if($this->auth_event_queued('CompleteRegistration')) {
return;
}
$this->fire_server_auth_event('Login', 'trackCustom', $user);
}
}
/**
* User Register
* @param int $user_id
* @param \WP_User $userdata
* @return void
*/
public function user_register($user_id, $userdata) {
if(pixelavo_other_event_exists('signup')) {
$this->fire_server_auth_event('CompleteRegistration', 'track', get_userdata($user_id));
}
}
/**
* Fire an identity event (Login / CompleteRegistration) server-side.
*
* The Conversions API call is made HERE, from the authenticated wp_login /
* user_register hook — this is the server-side source of truth and cannot be
* forged by a client. A short-lived cookie then carries ONLY the event name
* + the shared event_id to the browser, which fires the fbq pixel for
* deduplication. The cookie is genuinely non-authoritative: forging it can
* at most make the visitor's own browser fire an fbq pixel — it never
* triggers a CAPI call and carries no credentials.
*
* @param string $event_name
* @param string $track 'track' or 'trackCustom'
* @param \WP_User|false $user The authenticated user (for matching data).
* @return void
*/
private function fire_server_auth_event($event_name, $track, $user = null) {
$event_id = $event_name . '.' . time() . '.' . wp_generate_password(12, false, false);
// Make the just-authenticated user available for advanced matching —
// wp_login / user_register run before WordPress sets the current user.
if($user instanceof \WP_User) {
wp_set_current_user($user->ID);
}
// Fire the Conversions API now. Identity events are not page-scoped, so
// skip page-targeting and use the site home as the source URL (there is
// no queried page in this hook). The request is non-blocking, so login
// and registration are not slowed.
//
// Do NOT call pixelavo_get_event_common_data() here — it runs query
// conditionals (is_singular/is_home/...) which trigger a "called
// incorrectly" notice this early (before the main query). A minimal,
// page-independent payload is correct for an identity event anyway.
$common = ['event_url' => home_url('/')];
pixelavo_run_conversions_api($event_name, $common, $event_id, null, [
'event_source_url' => home_url('/'),
'skip_page_check' => true,
]);
// Hand only a browser descriptor to the client for the fbq pixel.
$this->queue_browser_auth_event($event_name, $track, $event_id);
}
/**
* Store a browser-only descriptor (event name + shared event_id) in the
* short-lived cookie so the pixel fires fbq once for deduplication. No PII,
* no credentials, not a trust boundary.
*
* @param string $event_name
* @param string $track
* @param string $event_id
* @return void
*/
private function queue_browser_auth_event($event_name, $track, $event_id) {
$queue = [];
if(!empty($_COOKIE['pixelavo_srv_evt'])) {
$existing = json_decode(wp_unslash($_COOKIE['pixelavo_srv_evt']), true);
if(is_array($existing)) {
$queue = $existing;
}
}
$queue[] = [
'name' => $event_name,
'track' => ($track === 'track') ? 'track' : 'trackCustom',
'id' => $event_id,
];
$this->set_server_auth_cookie(wp_json_encode($queue));
}
/**
* Whether an event of the given name is already in the pending cookie queue.
* @param string $name
* @return bool
*/
private function auth_event_queued($name) {
if(empty($_COOKIE['pixelavo_srv_evt'])) {
return false;
}
$queue = json_decode(wp_unslash($_COOKIE['pixelavo_srv_evt']), true);
if(!is_array($queue)) {
return false;
}
foreach($queue as $event) {
if(!empty($event['name']) && $event['name'] === $name) {
return true;
}
}
return false;
}
/**
* Set the short-lived carrier cookie for pending auth events.
* httponly is intentionally false: the browser JS must read it. It holds no
* secret — only event name + server-generated id.
* @param string $value
* @return void
*/
private function set_server_auth_cookie($value) {
// Reflect immediately so same-request reads (register -> login) see it.
$_COOKIE['pixelavo_srv_evt'] = $value;
if(headers_sent()) {
return;
}
setcookie('pixelavo_srv_evt', $value, [
'expires' => time() + 300,
'path' => defined('COOKIEPATH') && COOKIEPATH ? COOKIEPATH : '/',
'domain' => defined('COOKIE_DOMAIN') && COOKIE_DOMAIN ? COOKIE_DOMAIN : '',
'secure' => is_ssl(),
'httponly' => false,
'samesite' => 'Lax',
]);
}
/**
* After Active the plugin then redirect to option page
* @return void
*/
public function plugin_redirect_option_page() {
if ( get_option( 'pixelavo_do_activation_redirect', false ) ) {
delete_option('pixelavo_do_activation_redirect');
if( !isset( $_GET['activate-multi'] ) ){ // phpcs:ignore WordPress.Security.NonceVerification
wp_safe_redirect( admin_url("admin.php?page=pixelavo#/pixels") );
exit;
}
}
}
function show_diagnostic_notice() {
$notice_instance = \Pixelavo_Diagnostic_Data::get_instance();
if ( ! $notice_instance->should_show_notice() ) {
return;
}
ob_start();
$notice_instance->show_notices();
$message = ob_get_clean();
if (! empty( $message ) ) {
\Pixelavo_Notice::set_notice(
[
'id' => 'diagnostic-data',
'type' => 'success',
'dismissible' => false,
'message_type' => 'html',
'message' => $message,
'display_after' => ( 7 * DAY_IN_SECONDS ),
'expire_time' => ( 0 * DAY_IN_SECONDS ),
'close_by' => 'transient'
]
);
}
}
function show_rating_notice() {
$message = '
'.esc_html__('Would you mind doing us a huge favor by providing your feedback on WordPress? Your support helps us spread the word and greatly boosts our motivation.','pixelavo').'