Polylang crashes my site


#1

Hi!
I am having many problems with Polylang, for some reason the website crashes every time I add a 2nd language or add some CSS on the customizer for example.
I am using the child theme, and I work on a local environment with MAMP. The only way of getting it back to work is by cleaning the database.

Here is the log I get from WP_DEBUG if it helps

Fatal error: Uncaught Error: Call to undefined function add_settings_error() in /Applications/MAMP/htdocs/FootballXP/wp-content/plugins/polylang/admin/admin-static-pages.php:149 Stack trace: #0 /Applications/MAMP/htdocs/FootballXP/wp-includes/class-wp-hook.php(288): PLL_Admin_Static_Pages->update_page_on_front(‘23’, ‘23’) #1 /Applications/MAMP/htdocs/FootballXP/wp-includes/plugin.php(203): WP_Hook->apply_filters(23, Array) #2 /Applications/MAMP/htdocs/FootballXP/wp-includes/option.php(312): apply_filters(‘pre_update_opti…’, 23, ‘23’, ‘page_on_front’) #3 /Applications/MAMP/htdocs/FootballXP/wp-content/themes/jupiterx/lib/api/customizer/classes/class-multilingual.php(260): update_option(‘page_on_front’, 23) #4 /Applications/MAMP/htdocs/FootballXP/wp-includes/class-wp-hook.php(286): JupiterX\Customizer\Multilingual\CustomizerMultilingual::load_settings(’’) #5 /Applications/MAMP/htdocs/FootballXP/wp-includes/class-wp-hook.php(310): WP_Hook->apply_filters(NULL, Array) #6 /Applications/MAMP/htdocs/FootballXP/wp-includes/plugi in /Applications/MAMP/htdocs/FootballXP/wp-content/plugins/polylang/admin/admin-static-pages.php on line 149

Thank you!
Best regards,
David


#2

It seems like the function add_settings_error is missing which is being called by the plugin.

Have you installed the plugin completely? Can you try to re-install the plugin?

Are you using any cache plugin?


#3

Thanks for your answer.
No, I’m not using any cache plugin, and I’ve installed it through the ‘add plugin’ section from WordPress, so I guess it is installed completely.
Now I tried deleting Polylang, cleaning the folder “languages” from wp-content, flushing the cache and re-installing it by uploading the zip file, and the issue is still the same…
When I found this problem the first time I thought it was because I previously tried another plugin, but then I decided to do a fresh install of wordpress and the theme to test it, and the issue was the same.


#4

Okay, I understand.

Which cache are you talking about? Plugin cache?


#5

The cache flush that you have on the theme settings. (on the Jupiter X tab)
I tried yesterday on a live site from a fresh install and seems to work, but I had very little time to test and didn’t use the child theme. Do you have any idea why not on localhost? Since I would prefer to work local.


#6

Ok, after some more testing, I saw that it also crashes the live site… for English and Spanish seemed to work well, but the moment I added Chinese for example, the problem started again. I’m able to access the site, but not the wp-admin, which shows error 500 and my only solution so far has been to clean the database by searching and removing the zh_cn


#7

This is very strange and needs more investigation.
Please log into your Artbees account and start a live chat and explain your issue.


#8

Hello,

I seem to have the exact same Problem as renabing the plugin Polylang seems to work when it désactives it.
But it crashes the wordpress backend for me. Not the front-end.

Any ways to fix this? I choose Jupiter specially for using it with Polylang… :frowning:

Best regards,


#9

Are you using Jupiter 6 or Jupiter X?


#10

I am using the JupiterX template.


#11

Apparently, there is a bug in Polylang and our theme causes that bug to be activated.

For now, to avoid the bug, please kindly make sure your home page which is selected in Settings -> Reading has all the translations for all of your languages before you activate the theme. Otherwise the bug will appear. In case you have access to your files, you can rename the polylang folder in your wp-content/plugins/ directory and this will enable your backend area again. Then deactivate Jupiter X and rename polylang again and enable the polylang plugin. Then make sure the Home page has all the language translations. After that, you can freely activate Jupiter X.

I will report this bug to the devs to avoid it in coming releases. Thanks for sharing.


#12

I have a similar problem. But for me it crashes every time I activate the plugin. Please raise the priority in fixing the PolyLang plugin, I’m sure a lot of people use it.

Call to undefined function add_settings_error() in add_settings_error() in …/plugins/polylang/admin/admin-static-pages.php


#13

Hi Edmond,

Did you check this workaround?


#14

Hi!

It did not work, i got a backup since it was working. If i get into the error again I will update you with all the steps.


#15

Mohsen, any update on how I can fix this?

It’s really becoming and issue for me as it messes up my SEO also.

  1. When I initially installed the plugin i made a redirect from / to /ro. Now as I had to rename the plugin so I can access WP. On the front end it causes and endless loop so i get the too many redirects error. So i had again to remove all the redirects.

Note that my home page was only translated in /ro the rest of the languages have only been activated until i receive all the translations. So your option with make sure the home page is translated does not work.

While over it’s a nice theme, it’s annoying like hell.

Edmond


#16

Please kindly replace the jupiterx/lib/api/customizer/classes/class-multilingual.php with the following code and the issue should be resolved:

<?php
// phpcs:ignoreFile
/**
 * If Polylang is active:
 * - save and retrieve customizer setting per language.
 * - on front-page, set options and theme mod for the selected language.
 *
 * Inspired by https://github.com/fastlinemedia/customizer-export-import
 *
 * @package JupiterX\Framework\API\Customizer
 */

namespace JupiterX\Customizer\Multilingual;

if ( ! \function_exists( 'pll_current_language' ) && ! \class_exists( 'SitePress' ) ) {
	return;
}

\add_action( 'customize_save_after', __NAMESPACE__ . '\CustomizerMultilingual::save_settings', 1000 );
\add_action( 'plugins_loaded', __NAMESPACE__ . '\CustomizerMultilingual::load_settings', 9 );  // Must happen before 10 when _wp_customize_include() fires.
\add_action( 'after_setup_theme', __NAMESPACE__ . '\CustomizerMultilingual::load_settings' );
\add_action( 'customize_controls_enqueue_scripts', __NAMESPACE__ . '\CustomizerMultilingual::add_lang_to_customizer_previewer', 9 );
\add_action( 'wp_before_admin_bar_render', __NAMESPACE__ . '\CustomizerMultilingual::on_wp_before_admin_bar_render', 100 );
\add_action( 'admin_menu', __NAMESPACE__ . '\CustomizerMultilingual::on_admin_menu', 100 );
\add_action( 'after_setup_theme', __NAMESPACE__ . '\CustomizerMultilingual::remove_filters', 5 );


interface CustimizerMultilingualInterface {
	public static function save_settings( $wp_customize); // @phpcs:ignore
	public static function load_settings( $wp_customize = null); // @phpcs:ignore
}

/**
 * Functionality for multilingual customizer.
 *
 * @since 1.0.0
 *
 * @package JupiterX\Framework\API\Customizer
 * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
 */
class CustomizerMultilingual implements CustimizerMultilingualInterface {

	/**
	 * Remove bloginfo update filters. As we save options per language in this class, we don't need WPML functionality for the .
	 *
	 * @since 1.0.0
	 *
	 * @return void
	 */
	public static function remove_filters() {
		global $WPML_String_Translation; // @phpcs:ignore
		remove_filter( 'pre_update_option_blogname', [ $WPML_String_Translation, 'pre_update_option_blogname' ], 5 ); // @phpcs:ignore
		remove_filter( 'pre_update_option_blogdescription', [ $WPML_String_Translation, 'pre_update_option_blogdescription' ], 5 ); // @phpcs:ignore
	}

	/**
	 * Get current language.
	 *
	 * @since 1.0.0
	 *
	 * @return string|bool $language|false Current language or false when none of Polylang & WPML are active.
	 */
	public static function get_language() {
		if ( \function_exists( 'pll_current_language' ) ) {
			$language = pll_current_language();

			if ( ! $language ) {
				$language = pll_default_language();
			}

			return $language;
		}

		if ( class_exists( 'SitePress' ) && defined( 'ICL_LANGUAGE_CODE' ) ) {
			return ICL_LANGUAGE_CODE;
		}

		return false;
	}

	/**
	 * Get a list of active languages with extra parameters like name and slug.
	 *
	 * @since 1.0.0
	 *
	 * @return array|bool $languages|false List of active languages or false when none of Polylang & WPML are active.
	 */
	public static function get_languages_list() {
		if ( \function_exists( 'pll_current_language' ) ) {
			return get_option( '_transient_pll_languages_list' );
		}

		if ( class_exists( 'SitePress' ) && defined( 'ICL_LANGUAGE_CODE' ) ) {
			$list      = icl_get_languages( 'skip_missing=1' );
			$languages = [];

			foreach ( $list as $language ) {
				$temp         = [];
				$temp['name'] = $language['native_name'];
				$temp['slug'] = $language['code'];
				$languages[]  = $temp;
			}

			return $languages;
		}

		return false;
	}

	/**
	 * Get a proper option key per plugin.
	 *
	 * @since 1.0.0
	 *
	 * @return string|bool Option key or false when none of Polylang & WPML are active.
	 */
	public static function get_option_key() {
		if ( \function_exists( 'pll_current_language' ) ) {
			return '_customizer_polylang_settings_';
		}

		if ( class_exists( 'SitePress' ) && defined( 'ICL_LANGUAGE_CODE' ) ) {
			return '_customizer_wpml_settings_';
		}

		return false;
	}

	/**
	 * Get home URL of current language.
	 *
	 * @param string $language current language.
	 *
	 * @since 1.0.0
	 *
	 * @return string|bool Home URL of current language or false when none of Polylang & WPML are active.
	 */
	public static function get_home_url( $language ) {
		if ( \function_exists( 'pll_current_language' ) ) {
			return pll_home_url( $language );
		}

		if ( \class_exists( 'SitePress' ) ) {
			global $sitepress;
			return $sitepress->language_url( $language );
		}

		return false;
	}

	/**
	 * Save settings per language.
	 *
	 * @param object $wp_customize Customizer object.
	 *
	 * @since 1.0.0
	 *
	 * @return void
	 */
	public static function save_settings( $wp_customize ) {
		$language = self::get_language();

		if ( ! $language ) {
			return;
		}

		$theme    = get_stylesheet();
		$template = get_template();
		$charset  = get_option( 'blog_charset' );
		$mods     = get_theme_mods();
		$data     = [
			'template' => $template,
			'mods'     => $mods ? $mods : [],
			'options'  => [],
		];
		// Get options from the Customizer API.
		$settings = $wp_customize->settings();

		foreach ( $settings as $key => $setting ) {
			if ( 'option' === $setting->type ) {
				switch ( $key ) {
					// Ignore these.
					case stristr( $key, 'widget_' ):
					case stristr( $key, 'sidebars_' ):
					case stristr( $key, 'nav_menus_' ):
						break;

					default:
						$data['options'][ $key ] = $setting->value();
						break;
				}
			}
		}

		foreach ( $data['options'] as $option_key ) {
			$option_value = get_option( $option_key );
			if ( $option_value ) {
				$data['options'][ $option_key ] = $option_value;
			}
		}

		if ( \function_exists( 'wp_get_custom_css_post' ) ) {
			$data['wp_css'] = wp_get_custom_css();
		}

		$option_prefix = \str_replace( '-', '_', $template );
		\update_option( $option_prefix . self::get_option_key() . $language, $data );
	}

	/**
	 * Load settings per language.
	 *
	 * @param object $wp_customize Customizer object.
	 *
	 * @since 1.0.0
	 *
	 * @return void
	 * @SuppressWarnings(PHPMD.ElseExpression)
	 * @SuppressWarnings(PHPMD.NPathComplexity)
	 */
	public static function load_settings( $wp_customize = null ) {
		global $cei_error;

		$language = self::get_language();

		if ( ! $language ) {
			return;
		}

		$template      = get_template();
		$option_prefix = \str_replace( '-', '_', $template );
		$data          = get_option( $option_prefix . self::get_option_key() . $language, false );

		if ( $data ) {
			// Data checks.
			if ( 'array' !== gettype( $data ) ) {
				return;
			}

			if ( ! isset( $data['template'] ) || ! isset( $data['mods'] ) ) {
				return;
			}

			if ( $data['template'] !== $template ) {
				return;
			}

			// Import custom options.
			if ( isset( $data['options'] ) ) {
				foreach ( $data['options'] as $option_key => $option_value ) {
					if ( \class_exists( 'Customizermultilingialoption' ) ) {
						$option = new Customizermultilingialoption(
							$wp_customize, $option_key, [
								'default'    => '',
								'type'       => 'option',
								'capability' => 'edit_theme_options',
							]
						);
						$option->import( $option_value );
					} else {
						\update_option( $option_key, $option_value );
					}
				}
			}
			// If wp_css is set then import it.
			if ( \function_exists( 'wp_update_custom_css_post' ) && isset( $data['wp_css'] ) && '' !== $data['wp_css'] ) {
				wp_update_custom_css_post( $data['wp_css'] );
			}
			foreach ( $data['mods'] as $key => $val ) {
				set_theme_mod( $key, $val );
			}
		}
	}

	/**
	 * If Polylang activated, set the preview url and add select language control
	 *
	 * @author soderlind
	 * @version 1.0.0
	 * @link https://gist.github.com/soderlind/1908634f5eb0c1f69428666dd2a291d0
	 *
	 * @since 1.0.0
	 */
	public static function add_lang_to_customizer_previewer() {
		$languages = self::get_languages_list();

		if ( ! $languages ) {
			return;
		}

		$handle      = 'dss-add-lang-to-template';
		$js_path_url = trailingslashit( apply_filters( 'scp_js_path_url', get_stylesheet_directory_uri() . '/js/' ) );
		$src         = $js_path_url . 'customizer-multilingual.js';
		$deps        = [ 'customize-controls' ];
		wp_enqueue_script( $handle, $src, $deps, JUPITERX_VERSION, true );
		$language = ( empty( $_REQUEST['lang'] ) ) ? self::get_language() : $_REQUEST['lang']; // @phpcs:ignore

		if ( empty( $language ) ) {
			$language = self::default_language();
		}

		$url = add_query_arg( 'lang', $language, self::get_home_url( $language ) );

		wp_add_inline_script(
			$handle,
			sprintf(
				'JupiterCustomizerMultilingual.init( %s );', wp_json_encode(
					[
						'url'              => $url,
						'languages'        => $languages,
						'current_language' => $language,
						'switcher_text'    => __( 'Language:', 'jupiterx' ),
					]
				)
			), 'after'
		);
	}

	/**
	 * Append lang="contrycode" to the customizer url in the adminbar
	 *
	 * @since 1.0.0
	 *
	 * @return void
	 */
	public static function on_wp_before_admin_bar_render() {
		global $wp_admin_bar;
		$customize_node = $wp_admin_bar->get_node( 'customize' );
		if ( ! empty( $customize_node ) ) {
			$customize_node->href = add_query_arg( 'lang', self::get_language(), $customize_node->href );
			$wp_admin_bar->add_node( $customize_node );
		}
	}

	/**
	 * Append lang="contrycode" to the customizer url in the Admin->Apperance->Customize menu
	 *
	 * @since 1.0.0
	 *
	 * @return void
	 */
	public static function on_admin_menu() {
		global $menu, $submenu;
		$parent = 'themes.php';
		if ( ! isset( $submenu[ $parent ] ) ) {
			return;
		}
		foreach ( $submenu[ $parent ] as $k => $d ) {
			if ( 'customize' === $d['1'] ) {
				$submenu[ $parent ][ $k ]['2'] = add_query_arg( 'lang', self::get_language(), $submenu[ $parent ][ $k ]['2'] ); // @phpcs:ignore
				break;
			}
		}
	}

}

if ( class_exists( 'WP_Customize_Setting' ) ) {
	/**
	 * A class that extends WP_Customize_Setting so we can access
	 * the protected updated method when importing options.
	 *
	 * @since 0.3
	 */
	final class Customizermultilingialoption extends \WP_Customize_Setting { // @phpcs:ignore


		/**
		 * Import an option value for this setting.
		 *
		 * @since 0.3
		 * @param mixed $value The option value.
		 * @return void
		 */
		public function import( $value ) {
			$this->update( $value );
		}
	}
}