create_function() removed in PHP 8: fixing old WordPress plugins and themes

By CompatNav · Published · Last reviewed · 8 min read

Short answer

create_function() was deprecated in PHP 7.2 and removed in PHP 8.0. On PHP 8 every call to it is a fatal error: the page stops with “Call to undefined function create_function()”. If you run the site, update or replace the plugin or theme named in the error. If you maintain the code, replace each call with an anonymous function (function () { … }); the replacement also runs on PHP 7.4.

What the error means

create_function() builds a function from two strings: its parameters and its code. PHP 7.2 deprecated it “given the security issues of this function (being a thin wrapper around eval())” (php.net). PHP 8.0 removed it: “create_function() has been removed. Anonymous functions may be used instead.” (php.net)

So the same code behaves differently on the two sides of the upgrade. On PHP 7.4 it runs and only adds a deprecation notice, which a live site normally doesn’t show. On PHP 8.0 and later, the call stops the page. This is the real error from a theme that uses it:

Output on PHP 8.0.30the script stopped

Fatal error: Uncaught Error: Call to undefined function create_function() in /var/www/html/wp-content/themes/classic-blog/functions.php:2
Stack trace:
#0 {main}
  thrown in /var/www/html/wp-content/themes/classic-blog/functions.php on line 2

The folder after wp-content/themes/ (or wp-content/plugins/) names the theme or plugin: here, classic-blog. “There has been a critical error” after a PHP update explains the rest of the message and how to get a broken site back.

If you run the site

  1. Site down? Switch PHP back first. In your hosting control panel, find the PHP version setting (often called “PHP version”, “PHP Selector” or “MultiPHP Manager”) and choose the version the site used before. Then fix the cause calmly.
  2. Find the plugin or theme: the folder name in the error message, as above.
  3. Update it (Dashboard → Updates). The current version may no longer use create_function().
  4. No update, or already on the latest version? Ask its developer, or replace it with a maintained alternative. Not ready yet: what to do explains each option.
  5. Code written for your site? Send the error message to whoever maintains it. Each call is a small change, shown below.

Look for a fix that removes the calls, not one that brings the function back: a replacement create_function() needs eval(), the security problem PHP removed it for.

For developers: replacing create_function()

The first string lists the parameters, the second is the code. Both become an anonymous function: create_function('$title', 'return strtoupper($title);') turns into function ($title) { return strtoupper($title); }. Every example below ran on the official PHP builds, before and after, with unedited output.

A WordPress filter or action

The classic case: a callback for add_filter() or add_action(). On PHP 7.4 it works with a notice; on PHP 8.0 it stops:

wp-content/themes/classic-blog/functions.php

<?php
add_filter('the_title', create_function('$title', 'return strtoupper($title);'));

// WordPress runs the filter whenever it shows a title:
echo apply_filters('the_title', 'Hello world'), "\n";
WordPress isn’t loaded in this example: the WordPress functions it calls come from a small stand-in (show it)
<?php
// A simplified stand-in for two WordPress functions, so the guide examples run on plain PHP
// (WordPress itself isn't loaded). As in WordPress, add_filter() stores a callback for a hook, and
// apply_filters() passes the value through every callback stored for that hook, in order.
function add_filter( $hook, $callback ) {
	$GLOBALS['stand_in_filters'][ $hook ][] = $callback;
	return true;
}

function apply_filters( $hook, $value ) {
	foreach ( $GLOBALS['stand_in_filters'][ $hook ] ?? array() as $callback ) {
		$value = call_user_func( $callback, $value );
	}
	return $value;
}

Output on PHP 7.4.33

Deprecated: Function create_function() is deprecated in /var/www/html/wp-content/themes/classic-blog/functions.php on line 2
HELLO WORLD

Output on PHP 8.0.30the script stopped

Fatal error: Uncaught Error: Call to undefined function create_function() in /var/www/html/wp-content/themes/classic-blog/functions.php:2
Stack trace:
#0 {main}
  thrown in /var/www/html/wp-content/themes/classic-blog/functions.php on line 2

The anonymous function does the same job, on PHP 7.4 and on PHP 8.5:

wp-content/themes/classic-blog/functions.php

<?php
add_filter('the_title', function ($title) {
    return strtoupper($title);
});

// WordPress runs the filter whenever it shows a title:
echo apply_filters('the_title', 'Hello world'), "\n";
WordPress isn’t loaded in this example: the WordPress functions it calls come from a small stand-in (show it)
<?php
// A simplified stand-in for two WordPress functions, so the guide examples run on plain PHP
// (WordPress itself isn't loaded). As in WordPress, add_filter() stores a callback for a hook, and
// apply_filters() passes the value through every callback stored for that hook, in order.
function add_filter( $hook, $callback ) {
	$GLOBALS['stand_in_filters'][ $hook ][] = $callback;
	return true;
}

function apply_filters( $hook, $value ) {
	foreach ( $GLOBALS['stand_in_filters'][ $hook ] ?? array() as $callback ) {
		$value = call_user_func( $callback, $value );
	}
	return $value;
}

Output on PHP 7.4.33

HELLO WORLD

Output on PHP 8.5.11

HELLO WORLD

Values from outside the function: use

Old code often pasted a variable into the code string. An anonymous function takes it with use: “Closures may also inherit variables from the parent scope. Any such variables must be passed to the use language construct.” (php.net)

Code: sorting by a field named in a variable, before and after

wp-content/plugins/team-list/team-list.php

<?php
$members = [['name' => 'Sara'], ['name' => 'Adam']];
$sort_by = 'name';

usort($members, create_function('$a, $b', 'return strcmp($a["' . $sort_by . '"], $b["' . $sort_by . '"]);'));
echo $members[0]['name'], "\n";

Output on PHP 7.4.33

Deprecated: Function create_function() is deprecated in /var/www/html/wp-content/plugins/team-list/team-list.php on line 5
Adam

Output on PHP 8.0.30the script stopped

Fatal error: Uncaught Error: Call to undefined function create_function() in /var/www/html/wp-content/plugins/team-list/team-list.php:5
Stack trace:
#0 {main}
  thrown in /var/www/html/wp-content/plugins/team-list/team-list.php on line 5

wp-content/plugins/team-list/team-list.php

<?php
$members = [['name' => 'Sara'], ['name' => 'Adam']];
$sort_by = 'name';

usort($members, function ($a, $b) use ($sort_by) {
    return strcmp($a[$sort_by], $b[$sort_by]);
});
echo $members[0]['name'], "\n";

Output on PHP 7.4.33

Adam

Output on PHP 8.5.11

Adam

Code: global inside the code string (preg_replace_callback), before and after

wp-content/plugins/contact-details/contact-details.php

<?php
$contact = ['phone' => '555-0100', 'email' => 'hello@example.com'];
$text = 'Call [phone] or write to [email].';

echo preg_replace_callback('/\[(\w+)\]/', create_function('$m', 'global $contact; return $contact[$m[1]];'), $text), "\n";

Output on PHP 7.4.33

Deprecated: Function create_function() is deprecated in /var/www/html/wp-content/plugins/contact-details/contact-details.php on line 5
Call 555-0100 or write to hello@example.com.

Output on PHP 8.0.30the script stopped

Fatal error: Uncaught Error: Call to undefined function create_function() in /var/www/html/wp-content/plugins/contact-details/contact-details.php:5
Stack trace:
#0 {main}
  thrown in /var/www/html/wp-content/plugins/contact-details/contact-details.php on line 5

wp-content/plugins/contact-details/contact-details.php

<?php
$contact = ['phone' => '555-0100', 'email' => 'hello@example.com'];
$text = 'Call [phone] or write to [email].';

echo preg_replace_callback('/\[(\w+)\]/', function ($m) use ($contact) {
    return $contact[$m[1]];
}, $text), "\n";

Output on PHP 7.4.33

Call 555-0100 or write to hello@example.com.

Output on PHP 8.5.11

Call 555-0100 or write to hello@example.com.

Why the code string was a security risk

php.net’s page for the function: “This function internally performs an eval() and as such has the same security issues as eval().” (php.net) Look at the sorting example: $sort_by becomes part of the PHP code. If a value like that ever came from a visitor, for example through a URL parameter, whoever sent it could add their own PHP code to the string, and PHP would run it. An anonymous function never turns data into code: $sort_by stays a value.

each() went the same way

“each() has been removed. foreach or ArrayIterator should be used instead.” (php.net) Like create_function(), it was deprecated in PHP 7.2 (php.net).

Code: each() and foreach

wp-content/themes/old-theme/functions.php

<?php
$options = ['color' => 'blue', 'layout' => 'wide'];
while (list($key, $value) = each($options)) {
    echo $key, ' = ', $value, "\n";
}

Output on PHP 7.4.33

Deprecated: The each() function is deprecated. This message will be suppressed on further calls in /var/www/html/wp-content/themes/old-theme/functions.php on line 3
color = blue
layout = wide

Output on PHP 8.0.30the script stopped

Fatal error: Uncaught Error: Call to undefined function each() in /var/www/html/wp-content/themes/old-theme/functions.php:3
Stack trace:
#0 {main}
  thrown in /var/www/html/wp-content/themes/old-theme/functions.php on line 3

wp-content/themes/old-theme/functions.php

<?php
$options = ['color' => 'blue', 'layout' => 'wide'];
foreach ($options as $key => $value) {
    echo $key, ' = ', $value, "\n";
}

Output on PHP 8.0.30

color = blue
layout = wide

Finding every call before you upgrade

A check that reads the code finds these calls while the site still runs PHP 7.4:

CompatNav reports each call as Will break, because on PHP 8 it stops the page whenever it runs. It doesn’t report calls the code protects itself: a function_exists( 'create_function' ) check with a fallback keeps working on PHP 8, as the first example below shows. What it can’t see is a call through a variable that holds the function’s name; PHP 8 still stops there (second example).

Code: a call with a fallback, and a call through a variable

wp-content/plugins/team-list/team-list.php

<?php
if (function_exists('create_function')) {
    $shout = create_function('$text', 'return strtoupper($text);');
} else {
    $shout = function ($text) {
        return strtoupper($text);
    };
}
echo $shout('Hello world'), "\n";

Output on PHP 7.4.33

Deprecated: Function create_function() is deprecated in /var/www/html/wp-content/plugins/team-list/team-list.php on line 3
HELLO WORLD

Output on PHP 8.0.30

HELLO WORLD

wp-content/plugins/team-list/team-list.php

<?php
$make = 'create_function';
$shout = $make('$text', 'return strtoupper($text);');
echo $shout('Hello world'), "\n";

Output on PHP 8.0.30the script stopped

Fatal error: Uncaught Error: Call to undefined function create_function() in /var/www/html/wp-content/plugins/team-list/team-list.php:3
Stack trace:
#0 {main}
  thrown in /var/www/html/wp-content/plugins/team-list/team-list.php on line 3

Key takeaways

  • create_function() was deprecated in PHP 7.2 and removed in PHP 8.0. On PHP 8 any call to it stops the page with a fatal error.
  • On PHP 7.4 the same code still runs and only adds a deprecation notice, which is why the site breaks right after the upgrade.
  • Site owners: switch PHP back if the site is down, then update, replace or report the plugin or theme named in the error.
  • Developers: replace each call with an anonymous function; variables from outside go in use (…). The replacement also runs on PHP 7.4.
  • Don’t recreate create_function() with eval(): that brings back the security problem it was removed for.

Frequently asked questions

Why does the site break only after the PHP upgrade?

Because PHP 7.4 still has the function: it runs the code and only adds a deprecation notice, which most live sites never display. PHP 8.0 removed the function, so the same call becomes a fatal error.

Is there a drop-in replacement?

No function with the same name and behaviour exists in PHP 8. The replacement is an anonymous function, written once for each call: the code that was in the string becomes the body of the function. The examples above cover the usual cases.

Can I add a polyfill?

A home-made create_function() would have to turn a string into code with eval(), which is exactly the security problem php.net describes. Replace the calls instead.

Is each() the same problem?

Yes. each() was also deprecated in PHP 7.2 and removed in PHP 8.0; foreach replaces it. The example above shows the change.

Check your own site before you upgrade

CompatNav is a free WordPress plugin. It reads the code of your plugins and themes on your own server and tells you, in plain words, what will break and what will only show notices on the PHP version you choose. It never changes your code. It can’t see problems that only appear while code runs with real data, so a quick check of your site after the upgrade still matters.

Get CompatNav on wordpress.org How it works

Sources

About the code examples: each output is the real output of the code shown, run with the official PHP builds, without a php.ini, with all errors reported and displayed. Only the file path was replaced by a neutral server path.