: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
private function sanitize_email_pattern( $pattern ) {
$chars = [ '.', '*', '/' ];
$replace = [ '\.', '.*', '\/' ];
// Create regex pattern from a string.
return '^' . str_replace( $chars, $replace, $pattern ) . '$';
* Sanitize allow/deny list and default value before saving.
* @param array $form Form array which is usable with `wp_update_post()`.
* @param array $data Data retrieved from $_POST and processed.
* @param array $args Empty by default, may contain custom data not intended to be saved, but used for processing.
public function save_form_args( $form, $data, $args ) {
// Get a filtered form content.
$form_data = json_decode( stripslashes( $form['post_content'] ), true );
if ( ! empty( $form_data['fields'] ) ) {
foreach ( (array) $form_data['fields'] as $key => $field ) {
if ( empty( $field['type'] ) || $field['type'] !== 'email' ) {
$form_data['fields'][ $key ]['allowlist'] = ! empty( $field['allowlist'] ) ? implode( PHP_EOL, $this->sanitize_restricted_rules( $field['allowlist'] ) ) : '';
$form_data['fields'][ $key ]['denylist'] = ! empty( $field['denylist'] ) ? implode( PHP_EOL, $this->sanitize_restricted_rules( $field['denylist'] ) ) : '';
$form_data['fields'][ $key ]['default_value'] = isset( $field['default_value'] ) ? wpforms_is_email( $field['default_value'] ) : '';
$form['post_content'] = wpforms_encode( $form_data );
* Add a custom JS i18n strings for the builder.
* @param array $strings List of strings.
* @param array $form Current form.
public function add_builder_strings( $strings, $form ) {
$strings['allow_deny_lists_intersect'] = esc_html__(
'We’ve detected the same text in your allowlist and denylist. To prevent a conflict, we’ve removed the following text from the list you’re currently viewing:',
* Get Punycode lib class.
* @return WPForms\Vendor\TrueBV\Punycode
private function get_punycode() {
$punycode = new Punycode();
* Get email patterns parts splitted by @ and *.
* @param string $email_pattern Email pattern.
private function get_email_pattern_parts( $email_pattern ) {
$parts = preg_split( '/[*@.]/', $email_pattern, - 1, PREG_SPLIT_OFFSET_CAPTURE );
foreach ( $parts as $key => $part ) {
// Replace split symbol position to the split symbol.
$part[1] = $part[1] > 0 ? $email_pattern[ $part[1] - 1 ] : '';
* Glue email patterns parts.
* @param array $parts Email pattern parts.
private function glue_email_pattern_parts( $parts ) {
foreach ( $parts as $part ) {
$email_pattern .= $part[1] . $part[0];
* Decode email patterns rules array.
* @param array $rules_arr Patterns rules array.
private function decode_email_patterns_rules_array( $rules_arr ) {
$rule = mb_strtolower( trim( $rule ) );
return $this->is_email_pattern( $rule ) ? $this->decode_punycode( $rule ) : '';
* Decode email patterns rules list.
* @param string $rules Patterns rules list.
private function decode_email_patterns_rules_list( $rules ) {
return $this->decode_email_patterns_rules_array( preg_split( '/\r\n|\r|\n|,/', $rules ) );
* @param string $email Email.
private function email_encode_punycode( $email ) {
if ( ! wpforms_is_email( $email ) ) {
return $this->encode_punycode( $email );
* @param string $email Email.
private function is_encoded_punycode( $email ) {
list( $local, $domain ) = $this->parse_email_pattern( $email );
// Check xn-- prefix in the beginning of domain part only.
return strpos( $domain, 'xn--' ) === 0;
* @param string $email_pattern Email pattern.
private function encode_punycode( $email_pattern ) {
$encoded = $this->transform_punycode( $email_pattern, [ $this->get_punycode(), 'encode' ] );
} catch ( Exception $e ) {
* @param string $email_pattern Email pattern.
private function decode_punycode( $email_pattern ) {
return $this->transform_punycode( $email_pattern, [ $this->get_punycode(), 'decode' ] );
* Transform email pattern.
* @param string $email_pattern Email pattern.
* @param callable $callback Punycode callback.
private function transform_punycode( $email_pattern, callable $callback ) {
$parts = $this->get_email_pattern_parts( $email_pattern );
foreach ( $parts as $key => $part ) {
$parts[ $key ][0] = call_user_func( $callback, $part[0] );
return $this->glue_email_pattern_parts( $parts );
* Parse email pattern and return local and domain parts (maybe empty).
* @param string $pattern Email pattern.
private function parse_email_pattern( $pattern ) {
return array_pad( explode( '@', $pattern ), 2, '' );
* Verify that an email pattern without @ is valid.
* @param string $pattern Local part.
private function is_email_pattern_without_at( $pattern ) {
if ( mb_strpos( $pattern, '*' ) === false ) {
* If pattern does not have @ separator, we should check the pattern twice, assuming:
* case 1 - pattern is a local pattern,
* case 2 - pattern is a domain pattern.
$pattern_check = $this->get_pattern( $pattern, 'a.me' );
if ( wpforms_is_email( $pattern_check ) ) {
return $this->get_pattern( $pattern );
// Asterisk in the email is allowed in local part, but not in the domain part.
$pattern_check = $this->get_pattern( 'a', str_replace( '*', '', $pattern ) );
if ( wpforms_is_email( $pattern_check ) ) {
return $this->get_pattern( $pattern );
* Determine if the field requires fieldset instead of the regular field label.
* @param bool $requires_fieldset True if requires fieldset.
* @param array $field Field data.
* @noinspection PhpUnusedParameterInspection
public function is_field_requires_fieldset( $requires_fieldset, $field ) {
return ! empty( $field['confirmation'] );