• BUG REPORT: Class “EM_Admin_Notice” Not Found on Plugin Installation

    Plugin: Events Manager v6.6.1
    Error Location: /wp-content/plugins/events-manager/em-install.php:532
    Severity: Critical (blocks plugin installation)

    ================================================================================

    ISSUE DESCRIPTION

    When installing the Events Manager plugin, a fatal PHP error occurs:

    PHP Fatal error: Uncaught Error: Class “EM_Admin_Notice” not found in
    /var/web/site/public_html/wp-content/plugins/events-manager/em-install.php:532

    This error prevents the plugin from being activated successfully.

    ================================================================================

    ROOT CAUSE

    The issue is in classes/em-admin-notices.php at line 224. The file uses a
    relative include path to load the EM_Admin_Notice class:

    include(’em-admin-notice.php’);

    When em-install.php is executed during plugin activation, it attempts to
    instantiate EM_Admin_Notice objects (lines 394, 395, 999, 1000, etc.), but the
    class definition has not been properly loaded due to the relative include
    failing. The relative path cannot resolve correctly depending on the PHP
    execution context and current working directory.

    NOTE: for now I fixed it by adding this code
    // Ensure admin notice classes are available
    if( !class_exists(‘EM_Admin_Notice’) && defined(‘EM_DIR’) ) {
    require_once( EM_DIR . ‘/classes/em-admin-notices.php’ );
    }
    on em-install.php

    • This topic was modified 1 week, 5 days ago by darick0029.
Viewing 2 replies - 1 through 2 (of 2 total)
  • Thread Starter darick0029

    (@darick0029)

    Additional Info:



    # Events Manager — Fatal Error / Blank Admin Menu Diagnosis

    **Site type**: Fresh install, single site (non-multisite)

    **Plugin version**: 7.4.0.1

    ---

    ## Summary

    A fresh install of Events Manager threw a fatal error on the front-end, and after a temporary patch silenced that error, the "Events" top-level admin menu appeared with a blank title. Both issues share the same root cause:
    em_add_options() in em-install.php never runs to completion on this install.

    ---

    ## Issue 1: Fatal error on front-end

    <br><br>Fatal error: Uncaught Error: Class "EM_Admin_Notice" not found in<br><br>/var/web/site/public_html/wp-content/plugins/events-manager/em-install.php:532<br><br>

    ### Root cause

    - EM_Admin_Notice (singular) is defined in classes/em-admin-notice.php. It is only ever loaded as a side effect of loading classes/em-admin-notices.php (plural), which ends with:

      php<br><br>  include('em-admin-notice.php');<br><br>  EM_Admin_Notices::init();<br><br> 

    - classes/em-admin-notices.php itself is only include_once'd inside events-manager.php, gated by:

      php<br><br>  if( is_admin() || ( defined('REST_REQUEST') && REST_REQUEST ) ){<br><br>      include_once( EM_DIR . '/classes/em-admin-notices.php' );<br><br>      ...<br><br>  }<br><br> 

      On a front-end request, this block never runs, so neither class is defined.

    - em_add_options() (called from em_install()) is not restricted to wp-admin. It runs on the init hook for **any** logged-in user with manage_options, via events-manager.php:

      php<br><br>  add_filter('init','em_init',1);<br><br>  ...<br><br>  function em_init(){<br><br>      ...<br><br>      if ( current_user_can('manage_options') ) {<br><br>          em_upgrade_plugin_check(); // -> em_install() if dbem_version doesn't match EM_VERSION<br><br>      }<br><br>  }<br><br> 

    - On a fresh install, dbem_version doesn't match EM_VERSION, so em_install() runs. em_add_options() calls new EM_Admin_Notice(...) near the top of the function — on a front-end request this class doesn't exist yet, hence the fatal.

    ### Temporary patch applied by another AI tool (in em_add_options(), before the new EM_Admin_Notice(...) call)

    php<br><br>// Ensure admin notice classes are available<br><br>if( !class_exists('EM_Admin_Notices') && defined('EM_DIR') ) {<br><br>    require_once( EM_DIR . '/classes/em-admin-notices.php' );<br><br>}<br><br>

    **Why it works**: forcing em-admin-notices.php to load also loads em-admin-notice.php (via that file's own trailing include()), so both classes exist before they're used. The fatal stops.

    **Caveats with this patch**:

    - It checks EM_Admin_Notices (plural) as a proxy for whether EM_Admin_Notice (singular) is available. This happens to be safe today because every code path that defines the plural class also defines the singular one in the same include, but it is an indirect/fragile check compared to the plain, unconditional include_once the codebase already uses elsewhere for the same purpose (see em_upgrade_current_installation() in em-install.php, which does include_once( EM_DIR . '/classes/em-admin-notices.php' ); unconditionally).

    - It is a workaround for the real defect: em_add_options()/em_install() can execute outside of is_admin()/REST context, but assumes admin-only classes are already loaded.

    ### Recommended proper fix

    Replace the class_exists() guard with the same unconditional pattern already used elsewhere in this file, placed at the top of em_add_options() (and/or em_install()), e.g.:

    php<br><br>function em_add_options() {<br><br>    global $wp_locale, $wpdb;<br><br>    include_once( EM_DIR . '/classes/em-admin-notices.php' );<br><br>    ...<br><br>

    This matches the existing convention in em_upgrade_current_installation() and removes the fragile plural/singular class proxy check.

    ---

    ## Issue 2: Blank "Events" menu title in wp-admin sidebar

    Symptoms: top-level "Events" menu and its submenus appear in the sidebar, but the top-level menu **title/label is blank**. Submenus (Settings, Help, Bookings, Locations) still show correct labels because those come from separate add_submenu_page() calls with hardcoded strings.

    ### Root cause

    - The CPT's menu_name label is built in classes/em-archetypes.php, inside Archetypes::init():

      php<br><br>  static::$event = &#091;<br><br>      ...<br><br>      'label' => get_option('dbem_cp_events_label' ),<br><br>      'label_single' => get_option('dbem_cp_events_label_single' ),<br><br>      ...<br><br>  ];<br><br> 

      with **no default value** passed to get_option().

    - dbem_cp_events_label / dbem_cp_events_label_single (and the location equivalents dbem_cp_locations_label / dbem_cp_locations_label_single) are only ever written to the database inside em_add_options(), via:

      php<br><br>  foreach($dbem_options as $key => $value){<br><br>      add_option($key, $value);<br><br>  }<br><br> 

      where $dbem_options includes:

      php<br><br>  'dbem_cp_events_label' => __('Events','events-manager'),<br><br>  'dbem_cp_events_label_single' => __('Event','events-manager'),<br><br>  'dbem_cp_locations_label' => __('Locations','events-manager'),<br><br>  'dbem_cp_locations_label_single' => __('Location','events-manager'),<br><br> 

    - Because the fatal in Issue 1 occurs at the very top of em_add_options() — before this array and its add_option() loop are ever reached — these four options were **never written to the database** on this fresh install.

    - get_option() on a non-existent option returns false. false became the CPT's menu_name → WordPress rendered a blank top-level menu title.

    - This does not occur on other (already-installed) sites because the option rows were already written to the database during a previous, successful install — Archetypes::init() reads the stored value directly and never falls through to a missing-option case there.

    ### Fix applied (in classes/em-archetypes.php)

    Added fallback defaults so the label can never resolve to false, regardless of whether em_add_options() has completed:

    php<br><br>// Before<br><br>'label' => get_option('dbem_cp_events_label' ),<br><br>'label_single' => get_option('dbem_cp_events_label_single' ),<br><br>...<br><br>'label' => get_option('dbem_cp_locations_label' ),<br><br>'label_single' => get_option('dbem_cp_locations_label_single' ),<br><br>// After<br><br>// plain string fallback, not __(), as this runs before WP's init action loads translations<br><br>'label' => get_option('dbem_cp_events_label') ?: 'Events',<br><br>'label_single' => get_option('dbem_cp_events_label_single') ?: 'Event',<br><br>...<br><br>// plain string fallback, not __(), as this runs before WP's init action loads translations<br><br>'label' => get_option('dbem_cp_locations_label') ?: 'Locations',<br><br>'label_single' => get_option('dbem_cp_locations_label_single') ?: 'Location',<br><br>

    **Why plain strings and not __('Events', 'events-manager')**: Archetypes::init() is called unconditionally at the bottom of em-archetypes.php (Archetypes::init();), which executes at plugin-load time — before WordPress's init action fires. Calling a translation function that early triggers WordPress's _load_textdomain_just_in_time "called incorrectly" notice, which this plugin's own changelog (readme.txt, v7.4) already fixed once. Using plain strings in this fallback avoids reintroducing that notice; the fallback only engages when the DB option is missing, and normal translation still applies once em_add_options() successfully writes the real (translated) values to the database.

    **Scope/limits of this fix**: it only prevents the blank _display_. It does not create the missing database rows — those are only ever written by a successful run of em_add_options(). Issue 1's fix is what allows that function to actually complete and persist dbem_cp_events_label, etc., permanently.

    ---

    ## Recommended follow-up for the plugin developer

    1. Replace the class_exists('EM_Admin_Notices') guard in em_add_options() with an unconditional include_once( EM_DIR . '/classes/em-admin-notices.php' );, matching the pattern already used in em_upgrade_current_installation().

    2. Consider auditing other early-executing code (anything called at file-include time rather than hooked to init/admin_init) for admin-only class dependencies, since em_install()/em_add_options() can run in non-admin contexts (front-end requests by logged-in admins) via em_upgrade_plugin_check().

    3. Consider adding default values to the get_option() calls for dbem_cp_events_label, dbem_cp_events_label_single, dbem_cp_locations_label, dbem_cp_locations_label_single upstream (in the plugin's own source), so a partially-completed install never results in a blank admin menu title, independent of this site-specific fallback.

    4. Verify dbem_version correctly updates to EM_VERSION after install on this site — confirms em_add_options() and em_upgrade_current_installation() completed without error and the label options were persisted to the database.


    Plugin Support angelo_nwl

    (@angelo_nwl)

    Just to confirm, could you please try the latest version of Events Manager (v7.4.3) and let me know if the issue still occurs?

Viewing 2 replies - 1 through 2 (of 2 total)

You must be logged in to reply to this topic.