#37389·elementor

PHP warning on every front-end request: Attempt to read property "ID" on null in document.php:356, from WooCommerce Product / Product_Archive enqueue_scripts()

Author: eonianvrCreated Sep 22, 2026Updated Sep 22, 2026
Labelsstatus/awaiting_triage

Description

Summary

Elementor Pro's WooCommerce module instantiates its Product and Product_Archive document types as post-less objects. Those instances still register enqueue_scripts on wp_enqueue_scripts, and both implementations call $this->get_main_id(), which dereferences $this->post->ID while $this->post is NULL. This emits two PHP warnings on every front-end request.

Environment

WordPress 7.1.2 Elementor 4.2.4 Elementor Pro 4.3.0 WooCommerce 11.1.1 Theme: Hello Biz PHP 8.3.33 (fpm-fcgi), cPanel/EasyApache display_errors = On

The warning

Warning: Attempt to read property "ID" on null in
/wp-content/plugins/elementor/core/base/document.php on line 356

Emitted twice per request.

Stack traces (captured via a custom error handler)

#0 {closure}() elementor/core/base/document.php:356
#1 Elementor\Core\Base\Document->get_main_id()
   elementor-pro/modules/woocommerce/documents/product.php:63
#2 ElementorPro\Modules\Woocommerce\Documents\Product->enqueue_scripts()
   wp-includes/class-wp-hook.php:353
...
#5 do_action() wp-includes/script-loader.php:2340   [wp_enqueue_scripts]
#0 {closure}() elementor/core/base/document.php:356
#1 Elementor\Core\Base\Document->get_main_id()
   elementor-pro/modules/woocommerce/documents/product-archive.php:59
#2 ElementorPro\Modules\Woocommerce\Documents\Product_Archive->enqueue_scripts()
   wp-includes/class-wp-hook.php:353
...
#5 do_action() wp-includes/script-loader.php:2340   [wp_enqueue_scripts]

Root cause

Both enqueue_scripts() implementations open with a preview-mode check that calls get_main_id():

product.php:63 — if ( Plugin::elementor()->preview->is_preview_mode( $this->get_main_id() ) ) { product-archive.php:59 — same pattern

Document::get_main_id() (elementor/core/base/document.php:354-368) begins:

php
public function get_main_id() {
    if ( ! $this->main_id ) {
        $post_id = $this->post->ID;   // line 356

Dumping the two objects registered on wp_enqueue_scripts confirms they carry no post at all:

ElementorPro\Modules\Woocommerce\Documents\Product -> enqueue_scripts
   Controls_Stack::id   = NULL
   Controls_Stack::data = NULL
   Document::main_id    = NULL
   Document::post       = NULL

Identical for Product_Archive. These are not orphaned templates — they are document-type instances created without a post that nonetheless hook wp_enqueue_scripts. Only these two Woo document classes call get_main_id() inside enqueue_scripts(), which is why exactly two warnings appear and no other document type is affected.

Ruled out (site data is clean)

All 35 theme-builder condition entries (elementor_pro_theme_builder_conditions) reference existing, published posts Zero orphaned _elementor_template_type postmeta rows All WooCommerce page ID options resolve to existing published pages Reproduces with no deleted or trashed templates anywhere on the site

Steps to reproduce

Install Elementor 4.2.4 + Elementor Pro 4.3.0 + WooCommerce on PHP 8.x Set display_errors = On Load any front-end URL

Expected: no PHP warnings. Actual: two Attempt to read property "ID" on null warnings per request.

Impact beyond the log noise

The warnings are emitted during wp_enqueue_scripts, i.e. before the document is fully output. Because the warning markup includes
tags emitted ahead of the doctype, the browser implicitly closes and starts — pushing , the meta description, canonical and Open Graph tags into <body>. On a live site with display_errors on, that is a real SEO regression, not just log noise. It also reproduces on RSS feeds and 404 responses.</p> <p>Suggested fix</p> <p>Null-guard Document::get_main_id(), or skip the wp_enqueue_scripts registration entirely for post-less document instances:</p> <div class="md-code"><div class="md-code-bar"><span class="md-code-lang"></span><button type="button" class="md-code-copy" aria-label="Copy">复制</button></div><pre><code class="hljs">php public function get_main_id() { if ( ! $this->main_id ) { if ( ! $this->post ) { return 0; } $post_id = $this->post->ID; ...</code></pre></div><p>Workaround in use</p> <div class="md-code"><div class="md-code-bar"><span class="md-code-lang"></span><button type="button" class="md-code-copy" aria-label="Copy">复制</button></div><pre><code class="hljs">php add_action( 'wp_enqueue_scripts', function () { global $wp_filter; if ( empty( $wp_filter['wp_enqueue_scripts'] ) ) { return; } $remove = array(); foreach ( $wp_filter['wp_enqueue_scripts']->callbacks as $prio => $cbs ) { foreach ( $cbs as $cb ) { $f = $cb['function']; if ( ! is_array( $f ) || ! isset( $f[1] ) || 'enqueue_scripts' !== $f[1] || ! is_object( $f[0] ) ) { continue; } if ( ! ( $f[0] instanceof \Elementor\Core\Base\Document ) ) { continue; } if ( method_exists( $f[0], 'get_post' ) && null === $f[0]->get_post() ) { $remove[] = array( $f, $prio ); } } } foreach ( $remove as $r ) { remove_action( 'wp_enqueue_scripts', $r[0], $r[1] ); } }, 0 );</code></pre></div><h3>Steps to reproduce</h3> <p>``Here's a tighter, more verifiable "Steps to reproduce" section to drop into the report.</p> <p>Steps to reproduce</p> <p>Prerequisites</p> <p>WordPress 7.1.2 Elementor 4.2.4 + Elementor Pro 4.3.0 (both active) WooCommerce 11.1.1 active PHP 8.x (reproduced on 8.3.33, fpm-fcgi) At least one WooCommerce Single Product and one Products Archive theme-builder template exists (both published, both with valid conditions)</p> <p>Steps</p> <p>Set display_errors = On in php.ini (or .user.ini under PHP-FPM). WP_DEBUG can remain false — WordPress's non-debug error_reporting() mask still includes E_WARNING, so the warning surfaces either way. If a page cache is active (LiteSpeed, WP Rocket, etc.), purge it, or test while logged out of a cache-bypassing session — a cached HTML copy will mask the change in either direction. Load any front-end URL: the homepage, a page, a single product, /?p=1, a 404 URL, or /feed/. View source.</p> <p>Expected</p> <p>Clean output; no PHP warnings.</p> <p>Actual</p> <p>Two warnings emitted before the doctype:</p> <div class="md-code"><div class="md-code-bar"><span class="md-code-lang"></span><button type="button" class="md-code-copy" aria-label="Copy">复制</button></div><pre><code class="hljs">Warning: Attempt to read property "ID" on null in /wp-content/plugins/elementor/core/base/document.php on line 356</code></pre></div><p>Scope notes (from narrowing on the affected site)</p> <p>Fires on every front-end request type tested: pages, single products, product archives, 404s, and RSS feeds Does not fire on REST API requests (/wp-json/...) or in wp-admin — REST short-circuits at parse_request, before the wp action Count is always exactly two per request, one per Woo document type Independent of which page is loaded — no WooCommerce page or product need be involved</p> <p>Deterministic verification (works regardless of display_errors)</p> <p>Add this snippet and load any front-end page. It lists the document objects registered on wp_enqueue_scripts and dumps their properties:</p> <div class="md-code"><div class="md-code-bar"><span class="md-code-lang"></span><button type="button" class="md-code-copy" aria-label="Copy">复制</button></div><pre><code class="hljs">php add_action( 'wp_enqueue_scripts', function () { global $wp_filter; $out = ''; foreach ( $wp_filter['wp_enqueue_scripts']->callbacks as $prio => $cbs ) { foreach ( $cbs as $cb ) { $f = $cb['function']; if ( ! is_array( $f ) || ! is_object( $f[0] ) ) { continue; } if ( ! ( $f[0] instanceof \Elementor\Core\Base\Document ) ) { continue; } $out .= $prio . ' ' . get_class( $f[0] ) . ' -> ' . $f[1] . "\n"; foreach ( (array) $f[0] as $k => $v ) { $k = str_replace( chr( 0 ), '|', $k ); if ( is_scalar( $v ) || null === $v ) { $out .= ' ' . $k . ' = ' . var_export( $v, true ) . "\n"; } } } } error_log( $out ); }, 99999 );</code></pre></div><p>Expected in the log on any front-end request:</p> <div class="md-code"><div class="md-code-bar"><span class="md-code-lang"></span><button type="button" class="md-code-copy" aria-label="Copy">复制</button></div><pre><code class="hljs">11 ElementorPro\Modules\Woocommerce\Documents\Product -> enqueue_scripts |Elementor\Controls_Stack|id = NULL |Elementor\Controls_Stack|data = NULL |Elementor\Core\Base\Document|main_id = NULL |*|post = NULL 11 ElementorPro\Modules\Woocommerce\Documents\Product_Archive -> enqueue_scripts |Elementor\Controls_Stack|id = NULL |Elementor\Controls_Stack|data = NULL |Elementor\Core\Base\Document|main_id = NULL |*|post = NULL</code></pre></div><p>Two Document subclasses hooked to wp_enqueue_scripts with post = NULL is the bug — enqueue_scripts() on each then calls get_main_id(), which dereferences that null.</p> <p>Ruled out — not caused by site data</p> <p>Verified on the affected install before filing:</p> <p>All 35 entries in elementor_pro_theme_builder_conditions point to existing, published posts SELECT for <em>elementor_template_type postmeta rows with no matching post row returns 0 All woocommerce</em>*_page_id options resolve to existing published pages No trashed or deleted templates present</p> <h3>Expected behavior</h3> <p>Elementor Pro's WooCommerce document types should not emit PHP warnings on normal page loads. Document::get_main_id() should handle a null $this->post gracefully, or post-less document instances should not register enqueue_scripts on wp_enqueue_scripts in the first place. Either way, front-end requests should produce no PHP output before the doctype.</p> <h3>Elementor System Info</h3> <div class="md-code" data-lang="txt"><div class="md-code-bar"><span class="md-code-lang">txt</span><button type="button" class="md-code-copy" aria-label="Copy">复制</button></div><pre><code class="hljs language-txt">== Server Environment == Operating System: Linux Software: Apache MySQL version: MySQL Community Server - GPL v8.0.46 PHP Version: 8.3.33 PHP Memory Limit: 1024M PHP Max Input Vars: 1000 PHP Max Post Size: 128M GD Installed: Yes ZIP Installed: Yes Write Permissions: All right Elementor Library: Connected == WordPress Environment == Version: 7.1.2 WP Multisite: No Max Upload Size: 128 MB Memory limit: 256M Max Memory limit: 1024M Permalink Structure: /%year%/%monthnum%/%day%/%postname%/ Language: en_US Timezone: -5 Admin Email: [email protected] Debug Mode: Inactive == Theme == Name: Hello Biz Version: 1.2.2 Author: Elementor Team Child Theme: No == User == Role: administrator WP Profile lang: en-US User Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/153.0.0.0 Safari/537.36 == Active Plugins == Akismet Anti-spam: Spam Protection Version: 5.7.2 Author: Automattic - Anti-spam Team Code Snippets Version: 3.10.2 Author: Code Snippets Pro Download Plugin Version: 2.4.6 Author: Download Plugin Elementor Version: 4.2.4 Author: Elementor.com Elementor Pro Version: 4.3.0 Author: Elementor.com ElementsKit Lite Version: 4.0.6 Author: Wpmet ElementsKit Pro Version: 4.10.5 Author: Wpmet Enable Media Replace Version: 4.2.2 Author: ShortPixel Google for WooCommerce Version: 3.9.4 Author: WooCommerce Gravity Forms Version: 3.1.2 Author: Gravity Forms Gravity Forms Widget for Elementor Version: 1.1.1 Author: GravityKit Gravity SMTP Version: 2.3.3 Author: Gravity Forms Hello Plus Version: 1.7.8 Author: Elementor.com IOS DSPS System Configurator Version: 1.0.0 Author: Innovative Oncology Solutions LiteSpeed Cache Version: 7.9.1 Author: LiteSpeed Technologies Premium Addons for Elementor Version: 4.11.106 Author: Leap13 Premium Addons PRO Version: 2.9.66 Author: Leap13 Product Options and Fields Version: 1.4.1 Author: Addify Rank Math SEO Version: 1.0.279 Author: Rank Math SEO Redirection Version: 5.10.1 Author: John Godley Site Kit by Google Version: 1.188.0 Author: Google Stripe Tax - Sales tax automation for WooCommerce Version: 2.1.0 Author: WebToffee WooCommerce Request A Quote Version: 1.4.1 Author: WebToffee WooCommerce Version: 11.1.1 Author: Automattic WooCommerce Tax Version: 3.6.16 Author: WooCommerce WP File Manager Version: 8.0.4 Author: mndpsingh287 WP phpMyAdmin Version: 5.2.2.01 Author: Puvox.software == Elements Usage == product : 4 button : 4 container : 29 heading : 12 shortcode : 7 woocommerce-breadcrumb : 4 woocommerce-product-add-to-cart : 2 woocommerce-product-content : 3 woocommerce-product-data-tabs : 1 woocommerce-product-images : 4 woocommerce-product-related : 1 woocommerce-product-upsell : 3 section : 12 heading : 12 image : 6 premium-addon-button : 6 spacer : 12 text-editor : 6 wp-post : 0 container : 19 ekit-nav-menu : 1 elementskit-heading : 4 elementskit-mail-chimp : 1 elementskit-page-list : 6 elementskit-social-media : 1 gk_elementor_gravity_form : 1 heading : 3 image : 3 premium-addon-button : 3 premium-addon-dual-header : 1 text-editor : 3 woocommerce-product-content : 1 wp-page : 14 animated-headline : 3 container : 62 elementskit-blog-posts : 1 elementskit-button : 3 elementskit-flip-box : 6 elementskit-heading : 7 elementskit-icon-box : 4 elementskit-image-box : 7 elementskit-image-hover-effect : 6 elementskit-image-morphing : 1 elementskit-team : 6 elementskit-testimonial : 1 elementskit-timeline : 2 gk_elementor_gravity_form : 1 heading : 6 html : 6 premium-addon-button : 3 premium-addon-dual-header : 6 premium-image-accordion : 6 shortcode : 2 text-editor : 10 single-post : 1 container : 4 heading : 3 post-info : 1 post-navigation : 1 posts : 1 share-buttons : 1 theme-post-content : 1 product-archive : 31 container : 34 elementskit-advanced-search : 31 elementskit-flip-box : 6 elementskit-woo-category-list : 4 heading : 33 loop-grid : 1 premium-woo-products : 30 text-editor : 3 woocommerce-breadcrumb : 30 == Settings == cpt_support: post, page allow_tracking: yes editor_break_lines: 1 unfiltered_files_upload: 1 font_display: swap disabled_elements: elementskit-contact-form7, elementskit-drop-caps, elementskit-social-share, elementskit-caldera-forms, elementskit-we-forms, elementskit-wp-forms, elementskit-ninja-forms, elementskit-fluent-forms == Features == Custom Fonts: 0 Custom Icons: 0 == Integrations == woocommerce: Active == Elementor Experiments == Inline Font Icons: Active by default Additional Custom Breakpoints: Active by default Container: Active Optimized Markup: Active by default Panel Promotions: Active by default Default to New Theme Builder: Active by default Elementor MCP WP Abilities API: Inactive by default Pro Free Trial Popup: Active by default Nested Elements: Active Pages Panel: Inactive by default Atomic Widgets: Inactive by default Global Classes: Inactive by default Enforce global classes capabilities: Active by default Variables: Active by default Editor v4 (Opt In Page): Active by default Editor V4: Inactive by default Components: Active by default Interactions: Active by default Widget Creation: Active by default Generate website markdown: Inactive by default Dynamic Assets Management: Inactive by default Import/Export Customization: Active by default Site Builder: Inactive by default Elementor Editor Events: Active by default Atomic Form: Active by default Loop: Active by default Menu: Active In-Editor Feedback: Inactive by default == Log == Log: showing 20 of 392026-07-30 13:03:09 [info] Elementor data updater process has been completed. [array ( 'plugin' => 'Elementor', 'from' => '4.2.0', 'to' => '4.2.1', )] 2026-08-31 14:31:56 [info] Elementor data updater process has been queued. [array ( 'plugin' => 'Elementor', 'from' => '4.2.1', 'to' => '4.2.3', )] 2026-08-31 14:32:48 [info] elementor::elementor_updater Started 2026-08-31 14:32:48 [info] Elementor/Upgrades - _on_each_version Start 2026-08-31 14:32:51 [info] Elementor/Upgrades - _on_each_version Finished 2026-08-31 14:32:51 [info] Elementor data updater process has been completed. [array ( 'plugin' => 'Elementor', 'from' => '4.2.1', 'to' => '4.2.3', )] 2026-08-31 14:32:57 [info] Elementor data updater process has been queued. [array ( 'plugin' => 'Elementor', 'from' => '4.2.1', 'to' => '4.2.3', )] 2026-08-31 14:47:38 [info] elementor-pro::elementor_pro_updater Started 2026-08-31 14:47:38 [info] Elementor Pro/Upgrades - _on_each_version Start 2026-08-31 14:47:38 [info] Elementor Pro/Upgrades - _on_each_version Finished 2026-08-31 14:47:39 [info] Elementor data updater process has been completed. [array ( 'plugin' => 'Elementor Pro', 'from' => '4.2.1', 'to' => '4.2.3', )] 2026-09-07 12:04:50 [info] elementor::elementor_updater Started 2026-09-07 12:04:50 [info] Elementor/Upgrades - _on_each_version Start 2026-09-07 12:04:52 [info] Elementor/Upgrades - _on_each_version Finished 2026-09-07 12:04:52 [info] Elementor data updater process has been completed. [array ( 'plugin' => 'Elementor', 'from' => '4.2.3', 'to' => '4.2.4', )] 2026-09-22 10:58:41 [info] Elementor data updater process has been queued. [array ( 'plugin' => 'Elementor Pro', 'from' => '4.2.3', 'to' => '4.3.0', )] 2026-09-22 11:00:25 [info] elementor-pro::elementor_pro_updater Started 2026-09-22 11:00:25 [info] Elementor Pro/Upgrades - _on_each_version Start 2026-09-22 11:00:25 [info] Elementor Pro/Upgrades - _on_each_version Finished 2026-09-22 11:00:25 [info] Elementor data updater process has been completed. [array ( 'plugin' => 'Elementor Pro', 'from' => '4.2.3', 'to' => '4.3.0', )] JS: showing 3 of 3JS: 2026-07-28 16:40:18 [error X 1][https://domain.com/wp-content/plugins/elementor/assets/lib/backbone/backbone.marionette.min.js?ver=2.4.5.e1:24:19952] View (cid: &quot;view32194&quot;) has already been destroyed and cannot be used. JS: 2026-07-28 16:43:53 [error X 1][https://domain.com/wp-content/plugins/elementor/assets/lib/backbone/backbone.marionette.min.js?ver=2.4.5.e1:24:19952] View (cid: &quot;view40315&quot;) has already been destroyed and cannot be used. JS: 2026-09-22 18:17:03 [error X 1][https://domain.com/wp-content/plugins/elementor/assets/js/admin.min.js?ver=4.2.4:2:42363] r.startsWith is not a function PHP: showing 1 of 1PHP: 2026-09-22 10:58:58 [warning X 79][/home/ios/public_html/wp-content/plugins/elementor/core/base/document.php::356] Attempt to read property &quot;ID&quot; on null [array ( 'trace' => ' #0: Elementor\Core\Logger\Manager -> shutdown() ', )] == Elementor - Compatibility Tag == Elementor Pro: Compatibility not specified Gravity Forms Widget for Elementor: Compatibility not specified Premium Addons for Elementor: Compatibility not specified == Elementor Pro - Compatibility Tag ==</code></pre></div><h3>Agreement</h3> <ul> <li><input checked="" disabled="" type="checkbox"> I confirm I have read and followed all the guidelines and instructions outlined in the Elementor Bug Report form.</li> <li><input checked="" disabled="" type="checkbox"> I agree that my issue may be closed without further action if it doesn't meet all the requirements outlined in the Elementor Bug Report form.</li> </ul>