WordPress.org

Make WordPress Core

Opened 6 years ago

Closed 6 years ago

Last modified 6 years ago

#9915 closed defect (bug) (duplicate)

Cannot activate plugin which override function from pluggable.php

Reported by: sirzooro Owned by:
Milestone: Priority: normal
Severity: normal Version: 2.7.1
Component: General Keywords:
Focuses: Cc:

Description

I have plugin which overrides some functions from pluggable.php file. It works fine on my development server (Apache, Windows, WP 2.7.1). On production server (Apache, Linux, WP 2.7.1) it cannot be activated - WP reports following error:

Plugin could not be activated because it triggered a fatal error.
Fatal error: Cannot redeclare wp_new_user_notification() (previously declared in /some/path/wp-includes/pluggable.php:1100) in /some/path/wp-content/plugins/plugin/plugin.php on line xxx

I can workaround this by just checking if function already exists, which will allow to activate plugin. Unfortunately this is not a good solution - some other plugin can override this function too, so my plugin may stop working if it will be loaded after that one. I can add additional code to validate if functions are overridden - this can be checked in init hook, which is not called while plugin is installed.

All of this is a bit complicated (preferred solution is to provide override functions only). Therefore I suggest to add new functions which will allow to register replacement functions like hooks now. See example code:

if ( !function_exists( 'some_function' ) ) :

function some_function( $param ) {
	call_replacement_function( 'some_function', '_some_function', $param );
}

endif;

function _some_function( $param ) {
}

Plugin code:

register_replacement_function( 'some_function', 'new_fun' );

function new_fun( $param ) {}

register_replacement_function() function should check if another replacement function is already registered and report error if there is one.

Change History (7)

comment:1 @dd326 years ago

Plugin could not be activated because it triggered a fatal error. Fatal error: Cannot redeclare wp_new_user_notification() (previously declared in /some/path/wp-includes/pluggable.php:1100) in /some/path/wp-content/plugins/plugin/plugin.php on line xxx

Deactivate all other plugins, and try again.

As long as your plugin file has the function in the global scope when its included, that error shouldnt occur. I think theres 1 or 2 dodgy plugins which do a include_once('pluggables.php'); when they shouldnt (see #9826)

But yes, You're right, There needs to be better support for this sort of thing, Pluggables shouldn't be EVER used, and instead, Filters should be used.. (I only say that, since Pluggable functions, like you've mentioned, can only be replaced once..)

See #8833 for a new direction of pluggables

Probably should close this as a dupe of that. (Because you're original problem is invalid, but the idea to change the rest of it is elsewhere)

comment:2 @westi6 years ago

  • Resolution set to duplicate
  • Status changed from new to closed

Closing as WONTFIX / DUPE of #8833

If you override a pluggable function you must put the check for it already being defined in your code otherwise you will clash with other plugins.

If you want to detect this clash and doing something about it you can do that too.

As for improving the way pluggables work #8833 is the way to go on that as we already have for some of the functions.

comment:3 @sirzooro6 years ago

  • Resolution duplicate deleted
  • Status changed from closed to reopened

Thanks for reply. I checked few more things and was able to reproduce it on my dev box too - I had disabled function overriding option in my plugin. When I enabled it, problem appeared too.

As I mentioned earlier, this problem occurs when plugin is activated. I added few lines to it and found that during plugin activation pluggable.php file is already loaded, so it must cause problems.

Code:

if ( function_exists( 'wp_password_change_notification' ) ) {
	$included_files = get_included_files();

	foreach ($included_files as $filename) {
		echo "$filename<br>\n";
	}
	die;
}

Output:

C:\wordpress.local\wp-admin\plugins.php
C:\wordpress.local\wp-admin\admin.php
C:\wordpress.local\wp-load.php
C:\wordpress.local\wp-config.php
C:\wordpress.local\wp-settings.php
C:\wordpress.local\wp-includes\compat.php
C:\wordpress.local\wp-includes\functions.php
C:\wordpress.local\wp-includes\classes.php
C:\wordpress.local\wp-includes\wp-db.php
C:\wordpress.local\wp-includes\cache.php
C:\wordpress.local\wp-includes\plugin.php
C:\wordpress.local\wp-includes\default-filters.php
C:\wordpress.local\wp-includes\streams.php
C:\wordpress.local\wp-includes\gettext.php
C:\wordpress.local\wp-includes\l10n.php
C:\wordpress.local\wp-includes\formatting.php
C:\wordpress.local\wp-includes\capabilities.php
C:\wordpress.local\wp-includes\query.php
C:\wordpress.local\wp-includes\theme.php
C:\wordpress.local\wp-includes\user.php
C:\wordpress.local\wp-includes\general-template.php
C:\wordpress.local\wp-includes\link-template.php
C:\wordpress.local\wp-includes\author-template.php
C:\wordpress.local\wp-includes\post.php
C:\wordpress.local\wp-includes\post-template.php
C:\wordpress.local\wp-includes\category.php
C:\wordpress.local\wp-includes\category-template.php
C:\wordpress.local\wp-includes\comment.php
C:\wordpress.local\wp-includes\comment-template.php
C:\wordpress.local\wp-includes\rewrite.php
C:\wordpress.local\wp-includes\feed.php
C:\wordpress.local\wp-includes\bookmark.php
C:\wordpress.local\wp-includes\bookmark-template.php
C:\wordpress.local\wp-includes\kses.php
C:\wordpress.local\wp-includes\cron.php
C:\wordpress.local\wp-includes\version.php
C:\wordpress.local\wp-includes\deprecated.php
C:\wordpress.local\wp-includes\script-loader.php
C:\wordpress.local\wp-includes\class.wp-dependencies.php
C:\wordpress.local\wp-includes\class.wp-scripts.php
C:\wordpress.local\wp-includes\functions.wp-scripts.php
C:\wordpress.local\wp-includes\class.wp-styles.php
C:\wordpress.local\wp-includes\functions.wp-styles.php
C:\wordpress.local\wp-includes\taxonomy.php
C:\wordpress.local\wp-includes\update.php
C:\wordpress.local\wp-includes\canonical.php
C:\wordpress.local\wp-includes\shortcodes.php
C:\wordpress.local\wp-includes\media.php
C:\wordpress.local\wp-includes\http.php
C:\wordpress.local\wp-includes\vars.php
C:\wordpress.local\wp-content\plugins\akismet\akismet.php
C:\wordpress.local\wp-includes\pluggable.php
C:\wordpress.local\wp-includes\widgets.php
C:\wordpress.local\wp-includes\locale.php
C:\wordpress.local\wp-content\themes\transient\functions.php
C:\wordpress.local\wp-admin\includes\admin.php
C:\wordpress.local\wp-admin\includes\bookmark.php
C:\wordpress.local\wp-admin\includes\comment.php
C:\wordpress.local\wp-admin\includes\file.php
C:\wordpress.local\wp-admin\includes\image.php
C:\wordpress.local\wp-admin\includes\media.php
C:\wordpress.local\wp-admin\includes\import.php
C:\wordpress.local\wp-admin\includes\misc.php
C:\wordpress.local\wp-admin\includes\plugin.php
C:\wordpress.local\wp-admin\includes\post.php
C:\wordpress.local\wp-admin\includes\taxonomy.php
C:\wordpress.local\wp-admin\includes\template.php
C:\wordpress.local\wp-admin\includes\theme.php
C:\wordpress.local\wp-admin\includes\user.php
C:\wordpress.local\wp-admin\includes\update.php
C:\wordpress.local\wp-includes\registration.php
C:\wordpress.local\wp-admin\menu.php
C:\wordpress.local\wp-content\plugins\test\test.php

comment:4 @Denis-de-Bernardy6 years ago

I've seen similar issues with my own plugins, when declaring classes. Never found out where they came from, and ultimately resolved to adding if !class_exists() calls where needed to make things work.

comment:5 @dd326 years ago

  • Milestone 2.9 deleted
  • Resolution set to duplicate
  • Status changed from reopened to closed

Ah. I see the problem now.

Yes, You *MUST* include function_exists() checks NO MATTER WHAT. (like Westi said)

When plugins are being activated, they are includeded after the pluggables, (Under every version of WordPress, particularly in 2.5+) - there is nothing that can be done here, Which is why the function_exists check must be used regardless when overriding pluggables.

comment:6 @Denis-de-Bernardy6 years ago

Well, in my case, it was classes I defined, rather than functions that WP had already defined. If anything, it seemed that php ignored include_once calls during WP error checks. Just FYI.

comment:7 @sirzooro6 years ago

OK, so I will add function_exists() checks to my plugin - it will be sufficient solution, at least for now.

I also had the problem with duplicate classes in the past, but cannot reproduce it now. When I find it again, will try to investigate it.

One more question: what about executing define('ACTIVATING_PLUGIN', 1); just before activating plugin? Plugin could check this before overriding functions.

Note: See TracTickets for help on using tickets.