И снова несколько часов DEBUG’a увенчались успехом —  при работе с формами в WordPress при попытке доступа к $_POST (или $_GET или $_REQUEST) оказалось, что данные с «опасными» символами уже экранированы. 

Проблема

Например:

  • если в поле ввода формы ввести It's то в массиве $_REQUEST значение уже будет выглядеть как It's;
  • далее если вы записали такое значение в базу и затем вывели его в поле ввода как сохраненное, то оно будет уже иметь экранированный вид, и после следующего сохранения экранирование отработает еще раз, в следствие чего в базе уже будет значение похожее на это — It\'s.

Такое поведение нам не нужно.

Причина

В WordPress есть функция wp_magic_quotes(), которая появилась, если верить документации, только в версии 3.0. Собственно содержимое этой функции:

/**
 * Add magic quotes to $_GET, $_POST, $_COOKIE, and $_SERVER.
 *
 * Also forces $_REQUEST to be $_GET + $_POST. If $_SERVER, $_COOKIE,
 * or $_ENV are needed, use those superglobals directly.
 *
 * @access private
 * @since 3.0.0
 */
function wp_magic_quotes() {
	// If already slashed, strip.
	if ( get_magic_quotes_gpc() ) {
		$_GET    = stripslashes_deep( $_GET    );
		$_POST   = stripslashes_deep( $_POST   );
		$_COOKIE = stripslashes_deep( $_COOKIE );
	}

	// Escape with wpdb.
	$_GET    = add_magic_quotes( $_GET    );
	$_POST   = add_magic_quotes( $_POST   );
	$_COOKIE = add_magic_quotes( $_COOKIE );
	$_SERVER = add_magic_quotes( $_SERVER );

	// Force REQUEST to be GET + POST.
	$_REQUEST = array_merge( $_GET, $_POST );
}

Как видно из кода, функция экранирует все передаваемые данные. При чем выполняется на раннем этапе, в следствие чего при разработке плагина или темы вам доступны уже экранированные данные. В общем-то понятно зачем разработчики WordPress поступили именно так, но стоить помнить об этом при разработке своих продуктов, чтобы не ломать голову почему ничего не работает.

Решение

Если вы уже сделали так, что ваша система работает образом, который описан в параграфе «Проблема», то можно воспользоваться функцией stripslashes_deep(), пропустив через неё все полученные из базы данные непосредственно перед их выводом куда-либо.