Compare commits

...

8 Commits

Author SHA1 Message Date
Flatlogic Bot
cab0abc008 Auto commit: 2026-01-22T15:29:33.753Z 2026-01-22 15:29:33 +00:00
Flatlogic Bot
2884508100 Auto commit: 2026-01-22T15:17:14.589Z 2026-01-22 15:17:18 +00:00
Flatlogic Bot
b2cdd80bc4 Auto commit: 2026-01-22T15:01:06.050Z 2026-01-22 15:01:06 +00:00
Flatlogic Bot
5c6639841f Revert to version 15b98e0 2026-01-22 14:40:16 +00:00
Flatlogic Bot
fb1b8fe90c Revert to version 41f2bca 2026-01-22 14:39:58 +00:00
Flatlogic Bot
0c8309d338 Revert to version a16d2f1 2026-01-22 14:39:45 +00:00
Flatlogic Bot
15b98e0221 Auto commit: 2026-01-22T14:39:27.618Z 2026-01-22 14:39:27 +00:00
Flatlogic Bot
41f2bcad5f Auto commit: 2026-01-22T14:13:35.575Z 2026-01-22 14:13:35 +00:00
6262 changed files with 837263 additions and 16 deletions

175
.htaccess
View File

@ -1,18 +1,161 @@
DirectoryIndex index.php index.html
Options -Indexes
Options -MultiViews
# BEGIN W3TC Browser Cache
<IfModule mod_mime.c>
AddType text/css .css
AddType text/x-component .htc
AddType application/x-javascript .js
AddType application/javascript .js2
AddType text/javascript .js3
AddType text/x-js .js4
AddType video/asf .asf .asx .wax .wmv .wmx
AddType video/avi .avi
AddType image/avif .avif
AddType image/avif-sequence .avifs
AddType image/bmp .bmp
AddType application/java .class
AddType video/divx .divx
AddType application/msword .doc .docx
AddType application/vnd.ms-fontobject .eot
AddType application/x-msdownload .exe
AddType image/gif .gif
AddType application/x-gzip .gz .gzip
AddType image/x-icon .ico
AddType image/jpeg .jpg .jpeg .jpe
AddType image/webp .webp
AddType application/json .json
AddType application/vnd.ms-access .mdb
AddType audio/midi .mid .midi
AddType video/quicktime .mov .qt
AddType audio/mpeg .mp3 .m4a
AddType video/mp4 .mp4 .m4v
AddType video/mpeg .mpeg .mpg .mpe
AddType video/webm .webm
AddType application/vnd.ms-project .mpp
AddType application/x-font-otf .otf
AddType application/vnd.ms-opentype ._otf
AddType application/vnd.oasis.opendocument.database .odb
AddType application/vnd.oasis.opendocument.chart .odc
AddType application/vnd.oasis.opendocument.formula .odf
AddType application/vnd.oasis.opendocument.graphics .odg
AddType application/vnd.oasis.opendocument.presentation .odp
AddType application/vnd.oasis.opendocument.spreadsheet .ods
AddType application/vnd.oasis.opendocument.text .odt
AddType audio/ogg .ogg
AddType video/ogg .ogv
AddType application/pdf .pdf
AddType image/png .png
AddType application/vnd.ms-powerpoint .pot .pps .ppt .pptx
AddType audio/x-realaudio .ra .ram
AddType image/svg+xml .svg .svgz
AddType application/x-shockwave-flash .swf
AddType application/x-tar .tar
AddType image/tiff .tif .tiff
AddType application/x-font-ttf .ttf .ttc
AddType application/vnd.ms-opentype ._ttf
AddType audio/wav .wav
AddType audio/wma .wma
AddType application/vnd.ms-write .wri
AddType application/font-woff .woff
AddType application/font-woff2 .woff2
AddType application/vnd.ms-excel .xla .xls .xlsx .xlt .xlw
AddType application/zip .zip
</IfModule>
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType text/css A31536000
ExpiresByType text/x-component A31536000
ExpiresByType application/x-javascript A31536000
ExpiresByType application/javascript A31536000
ExpiresByType text/javascript A31536000
ExpiresByType text/x-js A31536000
ExpiresByType video/asf A31536000
ExpiresByType video/avi A31536000
ExpiresByType image/avif A31536000
ExpiresByType image/avif-sequence A31536000
ExpiresByType image/bmp A31536000
ExpiresByType application/java A31536000
ExpiresByType video/divx A31536000
ExpiresByType application/msword A31536000
ExpiresByType application/vnd.ms-fontobject A31536000
ExpiresByType application/x-msdownload A31536000
ExpiresByType image/gif A31536000
ExpiresByType application/x-gzip A31536000
ExpiresByType image/x-icon A31536000
ExpiresByType image/jpeg A31536000
ExpiresByType image/webp A31536000
ExpiresByType application/json A31536000
ExpiresByType application/vnd.ms-access A31536000
ExpiresByType audio/midi A31536000
ExpiresByType video/quicktime A31536000
ExpiresByType audio/mpeg A31536000
ExpiresByType video/mp4 A31536000
ExpiresByType video/mpeg A31536000
ExpiresByType video/webm A31536000
ExpiresByType application/vnd.ms-project A31536000
ExpiresByType application/x-font-otf A31536000
ExpiresByType application/vnd.ms-opentype A31536000
ExpiresByType application/vnd.oasis.opendocument.database A31536000
ExpiresByType application/vnd.oasis.opendocument.chart A31536000
ExpiresByType application/vnd.oasis.opendocument.formula A31536000
ExpiresByType application/vnd.oasis.opendocument.graphics A31536000
ExpiresByType application/vnd.oasis.opendocument.presentation A31536000
ExpiresByType application/vnd.oasis.opendocument.spreadsheet A31536000
ExpiresByType application/vnd.oasis.opendocument.text A31536000
ExpiresByType audio/ogg A31536000
ExpiresByType video/ogg A31536000
ExpiresByType application/pdf A31536000
ExpiresByType image/png A31536000
ExpiresByType application/vnd.ms-powerpoint A31536000
ExpiresByType audio/x-realaudio A31536000
ExpiresByType image/svg+xml A31536000
ExpiresByType application/x-shockwave-flash A31536000
ExpiresByType application/x-tar A31536000
ExpiresByType image/tiff A31536000
ExpiresByType application/x-font-ttf A31536000
ExpiresByType application/vnd.ms-opentype A31536000
ExpiresByType audio/wav A31536000
ExpiresByType audio/wma A31536000
ExpiresByType application/vnd.ms-write A31536000
ExpiresByType application/font-woff A31536000
ExpiresByType application/font-woff2 A31536000
ExpiresByType application/vnd.ms-excel A31536000
ExpiresByType application/zip A31536000
</IfModule>
<IfModule mod_deflate.c>
<IfModule mod_filter.c>
AddOutputFilterByType DEFLATE text/css text/x-component application/x-javascript application/javascript text/javascript text/x-js text/html text/richtext text/plain text/xsd text/xsl text/xml image/bmp application/java application/msword application/vnd.ms-fontobject application/x-msdownload image/x-icon application/json application/vnd.ms-access video/webm application/vnd.ms-project application/x-font-otf application/vnd.ms-opentype application/vnd.oasis.opendocument.database application/vnd.oasis.opendocument.chart application/vnd.oasis.opendocument.formula application/vnd.oasis.opendocument.graphics application/vnd.oasis.opendocument.presentation application/vnd.oasis.opendocument.spreadsheet application/vnd.oasis.opendocument.text audio/ogg application/pdf application/vnd.ms-powerpoint image/svg+xml application/x-shockwave-flash image/tiff application/x-font-ttf application/vnd.ms-opentype audio/wav application/vnd.ms-write application/font-woff application/font-woff2 application/vnd.ms-excel
<IfModule mod_mime.c>
# DEFLATE by extension
AddOutputFilter DEFLATE js css htm html xml
</IfModule>
</IfModule>
</IfModule>
<FilesMatch "\.(css|htc|less|js|js2|js3|js4|CSS|HTC|LESS|JS|JS2|JS3|JS4)$">
FileETag MTime Size
<IfModule mod_headers.c>
Header unset Set-Cookie
</IfModule>
</FilesMatch>
<FilesMatch "\.(html|htm|rtf|rtx|txt|xsd|xsl|xml|HTML|HTM|RTF|RTX|TXT|XSD|XSL|XML)$">
FileETag MTime Size
</FilesMatch>
<FilesMatch "\.(asf|asx|wax|wmv|wmx|avi|avif|avifs|bmp|class|divx|doc|docx|eot|exe|gif|gz|gzip|ico|jpg|jpeg|jpe|webp|json|mdb|mid|midi|mov|qt|mp3|m4a|mp4|m4v|mpeg|mpg|mpe|webm|mpp|otf|_otf|odb|odc|odf|odg|odp|ods|odt|ogg|ogv|pdf|png|pot|pps|ppt|pptx|ra|ram|svg|svgz|swf|tar|tif|tiff|ttf|ttc|_ttf|wav|wma|wri|woff|woff2|xla|xls|xlsx|xlt|xlw|zip|ASF|ASX|WAX|WMV|WMX|AVI|AVIF|AVIFS|BMP|CLASS|DIVX|DOC|DOCX|EOT|EXE|GIF|GZ|GZIP|ICO|JPG|JPEG|JPE|WEBP|JSON|MDB|MID|MIDI|MOV|QT|MP3|M4A|MP4|M4V|MPEG|MPG|MPE|WEBM|MPP|OTF|_OTF|ODB|ODC|ODF|ODG|ODP|ODS|ODT|OGG|OGV|PDF|PNG|POT|PPS|PPT|PPTX|RA|RAM|SVG|SVGZ|SWF|TAR|TIF|TIFF|TTF|TTC|_TTF|WAV|WMA|WRI|WOFF|WOFF2|XLA|XLS|XLSX|XLT|XLW|ZIP)$">
FileETag MTime Size
<IfModule mod_headers.c>
Header unset Set-Cookie
</IfModule>
</FilesMatch>
<IfModule mod_headers.c>
Header set Referrer-Policy "no-referrer-when-downgrade"
</IfModule>
# END W3TC Browser Cache
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
# 0) Serve existing files/directories as-is
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
# 1) Internal map: /page or /page/ -> /page.php (if such PHP file exists)
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.+?)/?$ $1.php [L]
# 2) Optional: strip trailing slash for non-directories (keeps .php links working)
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)/$ $1 [R=301,L]
RewriteRule . /index.php [L]
</IfModule>
# END WordPress

4
admin_credentials.txt Normal file
View File

@ -0,0 +1,4 @@
WordPress Admin Credentials:
URL: http://localhost/wp-admin
Username: admin
Password: qtWbo5uE2epruH8y

BIN
assets/images/about-bg.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 612 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 676 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

25
includes/pexels.php Normal file
View File

@ -0,0 +1,25 @@
<?php
function pexels_key() {
$k = getenv('PEXELS_KEY');
return $k && strlen($k) > 0 ? $k : 'Vc99rnmOhHhJAbgGQoKLZtsaIVfkeownoQNbTj78VemUjKh08ZYRbf18';
}
function pexels_get($url) {
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [ 'Authorization: '. pexels_key() ],
CURLOPT_TIMEOUT => 15,
]);
$resp = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($code >= 200 && $code < 300 && $resp) return json_decode($resp, true);
return null;
}
function download_to($srcUrl, $destPath) {
$data = file_get_contents($srcUrl);
if ($data === false) return false;
if (!is_dir(dirname($destPath))) mkdir(dirname($destPath), 0775, true);
return file_put_contents($destPath, $data) !== false;
}

View File

@ -1,4 +1,7 @@
<?php
/** Enable W3 Total Cache */
define('WP_CACHE', true); // Added by W3 Total Cache
if ( defined( 'WP_CLI' ) ) {
$_SERVER['HTTP_HOST'] = 'localhost';
}

View File

@ -0,0 +1,46 @@
<?php
/**
* File: advanced-cache.php
*
* W3 Total Cache advanced cache module.
*
* @package W3TC
*/
defined( 'ABSPATH' ) || die();
global $w3tc_start_microtime;
$w3tc_start_microtime = microtime( true );
/**
* Abort W3TC loading if WordPress is upgrading.
*/
if ( defined( 'WP_INSTALLING' ) && WP_INSTALLING ) {
return;
}
if ( ! defined( 'W3TC_IN_MINIFY' ) ) {
if ( ! defined( 'W3TC_DIR' ) ) {
define( 'W3TC_DIR', ( defined( 'WP_PLUGIN_DIR' ) ? WP_PLUGIN_DIR : WP_CONTENT_DIR . '/plugins' ) . '/w3-total-cache' );
}
if ( ! @is_dir( W3TC_DIR ) || ! file_exists( W3TC_DIR . '/w3-total-cache-api.php' ) ) {
if ( defined( 'WP_ADMIN' ) ) {
// Only display errors in wp-admin.
printf( '<strong>W3 Total Cache Error:</strong> some files appear to be missing or out of place. Please re-install plugin or remove <strong>%s</strong>. <br />', __FILE__ );
}
} else {
require_once W3TC_DIR . '/w3-total-cache-api.php';
if ( class_exists( '\W3TC\Dispatcher' ) ) {
$w3tc_redirect = \W3TC\Dispatcher::component( 'Mobile_Redirect' );
$w3tc_redirect->process();
$w3tc_config = \W3TC\Dispatcher::config();
if ( $w3tc_config->get_boolean( 'pgcache.enabled' ) ) {
$o = \W3TC\Dispatcher::component( 'PgCache_ContentGrabber' );
$o->process();
}
}
}
}

0
wp-content/cache/index.html vendored Normal file
View File

View File

@ -0,0 +1,759 @@
<?php
require_once WPCF7_PLUGIN_DIR . '/admin/includes/admin-functions.php';
require_once WPCF7_PLUGIN_DIR . '/admin/includes/help-tabs.php';
require_once WPCF7_PLUGIN_DIR . '/admin/includes/tag-generator.php';
require_once WPCF7_PLUGIN_DIR . '/admin/includes/welcome-panel.php';
require_once WPCF7_PLUGIN_DIR . '/admin/includes/config-validator.php';
add_action(
'admin_init',
static function () {
do_action( 'wpcf7_admin_init' );
},
10, 0
);
add_action(
'admin_menu',
'wpcf7_admin_menu',
9, 0
);
function wpcf7_admin_menu() {
do_action( 'wpcf7_admin_menu' );
add_menu_page(
__( 'Contact Form 7', 'contact-form-7' ),
__( 'Contact', 'contact-form-7' )
. wpcf7_admin_menu_change_notice(),
'wpcf7_read_contact_forms',
'wpcf7',
'wpcf7_admin_management_page',
'dashicons-email',
30
);
$edit = add_submenu_page( 'wpcf7',
__( 'Edit Contact Form', 'contact-form-7' ),
__( 'Contact Forms', 'contact-form-7' )
. wpcf7_admin_menu_change_notice( 'wpcf7' ),
'wpcf7_read_contact_forms',
'wpcf7',
'wpcf7_admin_management_page'
);
add_action( 'load-' . $edit, 'wpcf7_load_contact_form_admin', 10, 0 );
$addnew = add_submenu_page( 'wpcf7',
__( 'Add Contact Form', 'contact-form-7' ),
__( 'Add Contact Form', 'contact-form-7' )
. wpcf7_admin_menu_change_notice( 'wpcf7-new' ),
'wpcf7_edit_contact_forms',
'wpcf7-new',
'wpcf7_admin_add_new_page'
);
add_action( 'load-' . $addnew, 'wpcf7_load_contact_form_admin', 10, 0 );
$integration = WPCF7_Integration::get_instance();
if ( $integration->service_exists() ) {
$integration = add_submenu_page( 'wpcf7',
__( 'Integration with External API', 'contact-form-7' ),
__( 'Integration', 'contact-form-7' )
. wpcf7_admin_menu_change_notice( 'wpcf7-integration' ),
'wpcf7_manage_integration',
'wpcf7-integration',
'wpcf7_admin_integration_page'
);
add_action( 'load-' . $integration, 'wpcf7_load_integration_page', 10, 0 );
}
}
function wpcf7_admin_menu_change_notice( $menu_slug = '' ) {
$counts = apply_filters( 'wpcf7_admin_menu_change_notice',
array(
'wpcf7' => 0,
'wpcf7-new' => 0,
'wpcf7-integration' => 0,
)
);
if ( empty( $menu_slug ) ) {
$count = absint( array_sum( $counts ) );
} elseif ( isset( $counts[$menu_slug] ) ) {
$count = absint( $counts[$menu_slug] );
} else {
$count = 0;
}
if ( $count ) {
return sprintf(
' <span class="update-plugins %1$d"><span class="plugin-count">%2$s</span></span>',
$count,
esc_html( number_format_i18n( $count ) )
);
}
return '';
}
add_action(
'admin_enqueue_scripts',
'wpcf7_admin_enqueue_scripts',
10, 1
);
function wpcf7_admin_enqueue_scripts( $hook_suffix ) {
if ( false === strpos( $hook_suffix, 'wpcf7' ) ) {
return;
}
wp_enqueue_style( 'contact-form-7-admin',
wpcf7_plugin_url( 'admin/includes/css/styles.css' ),
array(), WPCF7_VERSION, 'all'
);
if ( wpcf7_is_rtl() ) {
wp_enqueue_style( 'contact-form-7-admin-rtl',
wpcf7_plugin_url( 'admin/includes/css/styles-rtl.css' ),
array(), WPCF7_VERSION, 'all'
);
}
$assets = include wpcf7_plugin_path( 'admin/includes/js/index.asset.php' );
$assets = wp_parse_args( $assets, array(
'dependencies' => array(),
'version' => WPCF7_VERSION,
) );
wp_enqueue_script( 'wpcf7-admin',
wpcf7_plugin_url( 'admin/includes/js/index.js' ),
$assets['dependencies'],
$assets['version'],
array( 'in_footer' => true )
);
wp_set_script_translations( 'wpcf7-admin', 'contact-form-7' );
$wpcf7_obj = array(
'apiSettings' => array(
'root' => sanitize_url( rest_url( 'contact-form-7/v1' ) ),
'namespace' => 'contact-form-7/v1',
),
);
$post = wpcf7_get_current_contact_form();
if ( $post ) {
$wpcf7_obj = array_merge( $wpcf7_obj, array(
'nonce' => array(
'save' => wp_create_nonce(
sprintf(
'wpcf7-save-contact-form_%s',
$post->initial() ? -1 : $post->id()
)
),
'copy' => wp_create_nonce(
sprintf(
'wpcf7-copy-contact-form_%s',
$post->initial() ? -1 : $post->id()
)
),
'delete' => wp_create_nonce(
sprintf(
'wpcf7-delete-contact-form_%s',
$post->initial() ? -1 : $post->id()
)
),
),
'configValidator' => array(
'errors' => array(),
'docUrl' => WPCF7_ConfigValidator::get_doc_link(),
),
) );
if (
current_user_can( 'wpcf7_edit_contact_form', $post->id() ) and
wpcf7_validate_configuration()
) {
$config_validator = new WPCF7_ConfigValidator( $post );
$config_validator->restore();
$wpcf7_obj['configValidator'] = array_merge(
$wpcf7_obj['configValidator'],
array(
'errors' => $config_validator->collect_error_messages(
array( 'decodes_html_entities' => true )
),
)
);
}
}
wp_add_inline_script( 'wpcf7-admin',
sprintf(
'var wpcf7 = %s;',
wp_json_encode( $wpcf7_obj, JSON_PRETTY_PRINT )
),
'before'
);
}
add_filter(
'set_screen_option_wpcf7_contact_forms_per_page',
static function ( $result, $option, $value ) {
$wpcf7_screens = array(
'wpcf7_contact_forms_per_page',
);
if ( in_array( $option, $wpcf7_screens, true ) ) {
$result = $value;
}
return $result;
},
10, 3
);
function wpcf7_load_contact_form_admin() {
global $plugin_page;
$action = wpcf7_current_action();
do_action( 'wpcf7_admin_load',
wpcf7_superglobal_get( 'page' ),
$action
);
if ( 'save' === $action ) {
$id = wpcf7_superglobal_post( 'post_ID', '-1' );
check_admin_referer( 'wpcf7-save-contact-form_' . $id );
if ( ! current_user_can( 'wpcf7_edit_contact_form', $id ) ) {
wp_die(
esc_html( __( 'You are not allowed to edit this item.', 'contact-form-7' ) )
);
}
$contact_form = wpcf7_save_contact_form(
array_merge(
wp_unslash( $_REQUEST ),
array(
'id' => $id,
'title' => wpcf7_superglobal_post( 'post_title', null ),
'locale' => wpcf7_superglobal_post( 'wpcf7-locale', null ),
'form' => wpcf7_superglobal_post( 'wpcf7-form', '' ),
'mail' => wpcf7_superglobal_post( 'wpcf7-mail', array() ),
'mail_2' => wpcf7_superglobal_post( 'wpcf7-mail-2', array() ),
'messages' => wpcf7_superglobal_post( 'wpcf7-messages', array() ),
'additional_settings' => wpcf7_superglobal_post( 'wpcf7-additional-settings', '' ),
)
)
);
if ( $contact_form and wpcf7_validate_configuration() ) {
$config_validator = new WPCF7_ConfigValidator( $contact_form );
$config_validator->validate();
$config_validator->save();
}
$query = array(
'post' => $contact_form ? $contact_form->id() : 0,
'active-tab' => wpcf7_canonicalize_name(
wpcf7_superglobal_post( 'active-tab' )
),
);
if ( ! $contact_form ) {
$query['message'] = 'failed';
} elseif ( -1 === (int) $id ) {
$query['message'] = 'created';
} else {
$query['message'] = 'saved';
}
$redirect_to = add_query_arg( $query, menu_page_url( 'wpcf7', false ) );
wp_safe_redirect( $redirect_to );
exit();
}
if ( 'copy' === $action ) {
$id = absint( $_POST['post_ID'] ?? $_REQUEST['post'] ?? '' );
check_admin_referer( 'wpcf7-copy-contact-form_' . $id );
if ( ! current_user_can( 'wpcf7_edit_contact_form', $id ) ) {
wp_die(
esc_html( __( 'You are not allowed to edit this item.', 'contact-form-7' ) )
);
}
$query = array();
if ( $contact_form = wpcf7_contact_form( $id ) ) {
$new_contact_form = $contact_form->copy();
$new_contact_form->save();
$query['post'] = $new_contact_form->id();
$query['message'] = 'created';
}
$redirect_to = add_query_arg( $query, menu_page_url( 'wpcf7', false ) );
wp_safe_redirect( $redirect_to );
exit();
}
if ( 'delete' === $action ) {
$nonce_action = 'bulk-posts';
if (
$post_id = wpcf7_superglobal_post( 'post_ID' ) or
! is_array( $post_id = wpcf7_superglobal_request( 'post', array() ) )
) {
$nonce_action = sprintf( 'wpcf7-delete-contact-form_%s', $post_id );
}
check_admin_referer( $nonce_action );
$posts = array_filter( (array) $post_id );
$deleted = 0;
foreach ( $posts as $post ) {
$post = WPCF7_ContactForm::get_instance( $post );
if ( empty( $post ) ) {
continue;
}
if ( ! current_user_can( 'wpcf7_delete_contact_form', $post->id() ) ) {
wp_die(
esc_html( __( 'You are not allowed to delete this item.', 'contact-form-7' ) )
);
}
if ( ! $post->delete() ) {
wp_die(
esc_html( __( 'Error in deleting.', 'contact-form-7' ) )
);
}
$deleted += 1;
}
$query = array();
if ( ! empty( $deleted ) ) {
$query['message'] = 'deleted';
}
$redirect_to = add_query_arg( $query, menu_page_url( 'wpcf7', false ) );
wp_safe_redirect( $redirect_to );
exit();
}
$post = null;
if ( 'wpcf7-new' === $plugin_page ) {
$post = WPCF7_ContactForm::get_template( array(
'locale' => wpcf7_superglobal_get( 'locale', null ),
) );
} elseif ( $post_id = wpcf7_superglobal_get( 'post' ) ) {
$post = WPCF7_ContactForm::get_instance( $post_id );
}
$current_screen = get_current_screen();
$help_tabs = new WPCF7_Help_Tabs( $current_screen );
if ( $post and current_user_can( 'wpcf7_edit_contact_form', $post->id() ) ) {
$help_tabs->set_help_tabs( 'edit' );
} else {
$help_tabs->set_help_tabs( 'list' );
if ( ! class_exists( 'WPCF7_Contact_Form_List_Table' ) ) {
require_once WPCF7_PLUGIN_DIR . '/admin/includes/class-contact-forms-list-table.php';
}
add_filter(
'manage_' . $current_screen->id . '_columns',
array( 'WPCF7_Contact_Form_List_Table', 'define_columns' ),
10, 0
);
add_screen_option( 'per_page', array(
'default' => 20,
'option' => 'wpcf7_contact_forms_per_page',
) );
}
}
function wpcf7_admin_management_page() {
if ( $post = wpcf7_get_current_contact_form() ) {
$post_id = $post->initial() ? -1 : $post->id();
require_once WPCF7_PLUGIN_DIR . '/admin/includes/editor.php';
require_once WPCF7_PLUGIN_DIR . '/admin/edit-contact-form.php';
return;
}
if (
'validate' === wpcf7_current_action() and
wpcf7_validate_configuration() and
current_user_can( 'wpcf7_edit_contact_forms' )
) {
wpcf7_admin_bulk_validate_page();
return;
}
$list_table = new WPCF7_Contact_Form_List_Table();
$list_table->prepare_items();
$formatter = new WPCF7_HTMLFormatter( array(
'allowed_html' => array_merge( wpcf7_kses_allowed_html(), array(
'form' => array(
'method' => true,
),
) ),
) );
$formatter->append_start_tag( 'div', array(
'class' => 'wrap',
'id' => 'wpcf7-contact-form-list-table',
) );
$formatter->append_start_tag( 'h1', array(
'class' => 'wp-heading-inline',
) );
$formatter->append_preformatted(
esc_html( __( 'Contact Forms', 'contact-form-7' ) )
);
$formatter->end_tag( 'h1' );
if ( current_user_can( 'wpcf7_edit_contact_forms' ) ) {
$formatter->append_preformatted(
wpcf7_link(
menu_page_url( 'wpcf7-new', false ),
__( 'Add Contact Form', 'contact-form-7' ),
array( 'class' => 'page-title-action' )
)
);
}
if ( $search_keyword = wpcf7_superglobal_request( 's' ) ) {
$formatter->append_start_tag( 'span', array(
'class' => 'subtitle',
) );
$formatter->append_preformatted(
sprintf(
/* translators: %s: Search query. */
__( 'Search results for: <strong>%s</strong>', 'contact-form-7' ),
esc_html( $search_keyword )
)
);
$formatter->end_tag( 'span' );
}
$formatter->append_start_tag( 'hr', array(
'class' => 'wp-header-end',
) );
$formatter->call_user_func( static function () {
do_action( 'wpcf7_admin_warnings',
'wpcf7', wpcf7_current_action(), null
);
wpcf7_welcome_panel();
do_action( 'wpcf7_admin_notices',
'wpcf7', wpcf7_current_action(), null
);
} );
$formatter->append_start_tag( 'form', array(
'method' => 'get',
) );
$formatter->append_start_tag( 'input', array(
'type' => 'hidden',
'name' => 'page',
'value' => wpcf7_superglobal_request( 'page' ),
) );
$formatter->call_user_func( static function () use ( $list_table ) {
$list_table->search_box(
__( 'Search Contact Forms', 'contact-form-7' ),
'wpcf7-contact'
);
$list_table->display();
} );
$formatter->print();
}
function wpcf7_admin_add_new_page() {
$post = wpcf7_get_current_contact_form();
if ( ! $post ) {
$post = WPCF7_ContactForm::get_template();
}
$post_id = -1;
require_once WPCF7_PLUGIN_DIR . '/admin/includes/editor.php';
require_once WPCF7_PLUGIN_DIR . '/admin/edit-contact-form.php';
}
function wpcf7_load_integration_page() {
do_action( 'wpcf7_admin_load',
wpcf7_superglobal_get( 'page' ),
wpcf7_current_action()
);
$integration = WPCF7_Integration::get_instance();
if (
$service_name = wpcf7_superglobal_request( 'service' ) and
$integration->service_exists( $service_name )
) {
$service = $integration->get_service( $service_name );
$service->load( wpcf7_current_action() );
}
$help_tabs = new WPCF7_Help_Tabs( get_current_screen() );
$help_tabs->set_help_tabs( 'integration' );
}
function wpcf7_admin_integration_page() {
$integration = WPCF7_Integration::get_instance();
$service_name = wpcf7_superglobal_request( 'service' );
$service = null;
if ( $service_name and $integration->service_exists( $service_name ) ) {
$service = $integration->get_service( $service_name );
}
$formatter = new WPCF7_HTMLFormatter( array(
'allowed_html' => array_merge( wpcf7_kses_allowed_html(), array(
'form' => array(
'action' => true,
'method' => true,
),
) ),
) );
$formatter->append_start_tag( 'div', array(
'class' => 'wrap',
'id' => 'wpcf7-integration',
) );
$formatter->append_start_tag( 'h1' );
$formatter->append_preformatted(
esc_html( __( 'Integration with External API', 'contact-form-7' ) )
);
$formatter->end_tag( 'h1' );
$formatter->append_start_tag( 'p' );
$formatter->append_preformatted(
sprintf(
/* translators: %s: URL to support page about integration with external APIs */
__( 'You can expand the possibilities of your contact forms by integrating them with external services. For details, see <a href="%s">Integration with external APIs</a>.', 'contact-form-7' ),
__( 'https://contactform7.com/integration-with-external-apis/', 'contact-form-7' )
)
);
$formatter->end_tag( 'p' );
$formatter->call_user_func(
static function () use ( $integration, $service, $service_name ) {
do_action( 'wpcf7_admin_warnings',
'wpcf7-integration', wpcf7_current_action(), $service
);
do_action( 'wpcf7_admin_notices',
'wpcf7-integration', wpcf7_current_action(), $service
);
if ( $service ) {
$message = wpcf7_superglobal_request( 'message' );
$service->admin_notice( $message );
$integration->list_services( array(
'include' => $service_name,
) );
} else {
$integration->list_services();
}
}
);
$formatter->print();
}
add_action( 'wpcf7_admin_notices', 'wpcf7_admin_updated_message', 10, 3 );
function wpcf7_admin_updated_message( $page, $action, $object ) {
if ( ! in_array( $page, array( 'wpcf7', 'wpcf7-new' ), true ) ) {
return;
}
$message_type = wpcf7_superglobal_request( 'message' );
if ( ! $message_type ) {
return;
}
$notice_type = 'success';
if ( 'created' === $message_type ) {
$message = __( 'Contact form created.', 'contact-form-7' );
} elseif ( 'saved' === $message_type ) {
$message = __( 'Contact form saved.', 'contact-form-7' );
} elseif ( 'deleted' === $message_type ) {
$message = __( 'Contact form deleted.', 'contact-form-7' );
} elseif ( 'failed' === $message_type ) {
$notice_type = 'error';
$message = __( 'There was an error saving the contact form.', 'contact-form-7' );
} elseif ( 'validated' === $message_type ) {
$bulk_validate = WPCF7::get_option( 'bulk_validate', array() );
$count_invalid = absint( $bulk_validate['count_invalid'] ?? 0 );
if ( $count_invalid ) {
$notice_type = 'warning';
$message = sprintf(
/* translators: %s: number of contact forms */
_n(
'Configuration validation completed. %s invalid contact form was found.',
'Configuration validation completed. %s invalid contact forms were found.',
$count_invalid, 'contact-form-7'
),
number_format_i18n( $count_invalid )
);
} else {
$message = __( 'Configuration validation completed. No invalid contact form was found.', 'contact-form-7' );
}
}
if ( ! empty( $message ) ) {
wp_admin_notice(
$message,
array( 'type' => $notice_type )
);
}
}
add_filter( 'plugin_action_links', 'wpcf7_plugin_action_links', 10, 2 );
function wpcf7_plugin_action_links( $links, $file ) {
if ( WPCF7_PLUGIN_BASENAME !== $file ) {
return $links;
}
if ( ! current_user_can( 'wpcf7_read_contact_forms' ) ) {
return $links;
}
$settings_link = wpcf7_link(
menu_page_url( 'wpcf7', false ),
__( 'Settings', 'contact-form-7' )
);
array_unshift( $links, $settings_link );
return $links;
}
add_action( 'wpcf7_admin_warnings', 'wpcf7_old_wp_version_error', 10, 3 );
function wpcf7_old_wp_version_error( $page, $action, $object ) {
$wp_version = get_bloginfo( 'version' );
if ( version_compare( $wp_version, WPCF7_REQUIRED_WP_VERSION, '<' ) ) {
wp_admin_notice(
sprintf(
/* translators: 1: version of Contact Form 7, 2: version of WordPress, 3: URL */
__( '<strong>Contact Form 7 %1$s requires WordPress %2$s or higher.</strong> Please <a href="%3$s">update WordPress</a> first.', 'contact-form-7' ),
WPCF7_VERSION,
WPCF7_REQUIRED_WP_VERSION,
admin_url( 'update-core.php' )
),
array( 'type' => 'warning' )
);
}
}
add_action( 'wpcf7_admin_warnings', 'wpcf7_not_allowed_to_edit', 10, 3 );
function wpcf7_not_allowed_to_edit( $page, $action, $object ) {
if ( $object instanceof WPCF7_ContactForm ) {
$contact_form = $object;
} else {
return;
}
if ( ! current_user_can( 'wpcf7_edit_contact_form', $contact_form->id() ) ) {
wp_admin_notice(
__( 'You are not allowed to edit this contact form.', 'contact-form-7' ),
array( 'type' => 'warning' )
);
}
}
add_action( 'wpcf7_admin_warnings', 'wpcf7_ctct_deprecated_warning', 10, 3 );
function wpcf7_ctct_deprecated_warning( $page, $action, $object ) {
$service = WPCF7_ConstantContact::get_instance();
if ( $service->is_active() ) {
wp_admin_notice(
__( 'Contact Form 7 has completed the <a href="https://contactform7.com/2025/01/08/complete-removal-of-constant-contact-integration/">removal of the Constant Contact integration</a>. We recommend <a href="https://contactform7.com/sendinblue-integration/">Brevo</a> as an alternative.', 'contact-form-7' ),
array( 'type' => 'warning' )
);
}
}
add_action( 'wpcf7_admin_warnings', 'wpcf7_captcha_future_warning', 10, 3 );
function wpcf7_captcha_future_warning( $page, $action, $object ) {
$service = WPCF7_RECAPTCHA::get_instance();
if ( $service->is_active() ) {
wp_admin_notice(
__( '<strong>Attention reCAPTCHA users:</strong> Google attempts to make all reCAPTCHA users migrate to reCAPTCHA Enterprise, meaning Google charges you for API calls exceeding the free tier. Contact Form 7 supports <a href="https://contactform7.com/turnstile-integration/">Cloudflare Turnstile</a>, and we recommend it unless you have reasons to use reCAPTCHA.', 'contact-form-7' ),
array( 'type' => 'warning' )
);
}
}

View File

@ -0,0 +1,484 @@
<?php
// don't load directly
if ( ! defined( 'ABSPATH' ) ) {
die( '-1' );
}
$save_button = sprintf(
'<input %s />',
wpcf7_format_atts( array(
'type' => 'submit',
'class' => 'button-primary',
'name' => 'wpcf7-save',
'value' => __( 'Save', 'contact-form-7' ),
) )
);
$formatter = new WPCF7_HTMLFormatter( array(
'allowed_html' => array_merge( wpcf7_kses_allowed_html(), array(
'form' => array(
'method' => true,
'action' => true,
'id' => true,
'class' => true,
'disabled' => true,
),
) ),
) );
$formatter->append_start_tag( 'div', array(
'class' => 'wrap',
'id' => 'wpcf7-contact-form-editor',
) );
$formatter->append_start_tag( 'h1', array(
'class' => 'wp-heading-inline',
) );
$formatter->append_preformatted(
esc_html( $post->initial()
? __( 'Add Contact Form', 'contact-form-7' )
: __( 'Edit Contact Form', 'contact-form-7' )
)
);
$formatter->end_tag( 'h1' );
if ( ! $post->initial() and current_user_can( 'wpcf7_edit_contact_forms' ) ) {
$formatter->append_whitespace();
$formatter->append_preformatted(
wpcf7_link(
menu_page_url( 'wpcf7-new', false ),
__( 'Add Contact Form', 'contact-form-7' ),
array( 'class' => 'page-title-action' )
)
);
}
$formatter->append_start_tag( 'hr', array(
'class' => 'wp-header-end',
) );
$formatter->call_user_func( static function () use ( $post ) {
do_action( 'wpcf7_admin_warnings',
$post->initial() ? 'wpcf7-new' : 'wpcf7',
wpcf7_current_action(),
$post
);
do_action( 'wpcf7_admin_notices',
$post->initial() ? 'wpcf7-new' : 'wpcf7',
wpcf7_current_action(),
$post
);
} );
if ( $post ) {
$formatter->append_start_tag( 'form', array(
'method' => 'post',
'action' => esc_url( add_query_arg(
array( 'post' => $post_id ),
menu_page_url( 'wpcf7', false )
) ),
'id' => 'wpcf7-admin-form-element',
'disabled' => ! current_user_can( 'wpcf7_edit_contact_form', $post_id ),
) );
if ( current_user_can( 'wpcf7_edit_contact_form', $post_id ) ) {
$formatter->call_user_func( static function () use ( $post_id ) {
wp_nonce_field( 'wpcf7-save-contact-form_' . $post_id );
} );
}
$formatter->append_start_tag( 'input', array(
'type' => 'hidden',
'id' => 'post_ID',
'name' => 'post_ID',
'value' => (int) $post_id,
) );
$formatter->append_start_tag( 'input', array(
'type' => 'hidden',
'id' => 'wpcf7-locale',
'name' => 'wpcf7-locale',
'value' => $post->locale(),
) );
$formatter->append_start_tag( 'input', array(
'type' => 'hidden',
'id' => 'hiddenaction',
'name' => 'action',
'value' => 'save',
) );
$formatter->append_start_tag( 'input', array(
'type' => 'hidden',
'id' => 'active-tab',
'name' => 'active-tab',
'value' => wpcf7_superglobal_get( 'active-tab' ),
) );
$formatter->append_start_tag( 'div', array(
'id' => 'poststuff',
) );
$formatter->append_start_tag( 'div', array(
'id' => 'post-body',
'class' => 'metabox-holder columns-2 wp-clearfix',
) );
$formatter->append_start_tag( 'div', array(
'id' => 'post-body-content',
) );
$formatter->append_start_tag( 'div', array(
'id' => 'titlediv',
) );
$formatter->append_start_tag( 'div', array(
'id' => 'titlewrap',
) );
$formatter->append_start_tag( 'input', array(
'type' => 'text',
'name' => 'post_title',
'value' => $post->initial() ? '' : $post->title(),
'id' => 'title',
'spellcheck' => 'true',
'autocomplete' => 'off',
'disabled' => ! current_user_can( 'wpcf7_edit_contact_form', $post_id ),
'placeholder' => __( 'Enter title here', 'contact-form-7' ),
'aria-label' => __( 'Enter title here', 'contact-form-7' ),
) );
$formatter->end_tag( 'div' ); // #titlewrap
$formatter->append_start_tag( 'div', array(
'class' => 'inside',
) );
if ( ! $post->initial() ) {
if ( $shortcode = $post->shortcode() ) {
$formatter->append_start_tag( 'p', array(
'class' => 'description',
) );
$formatter->append_start_tag( 'label', array(
'for' => 'wpcf7-shortcode',
) );
$formatter->append_preformatted(
esc_html( __( 'Copy this shortcode and paste it into your post, page, or text widget content:', 'contact-form-7' ) )
);
$formatter->end_tag( 'label' );
$formatter->append_whitespace();
$formatter->append_start_tag( 'span', array(
'class' => 'shortcode wp-ui-highlight',
) );
$formatter->append_start_tag( 'input', array(
'type' => 'text',
'id' => 'wpcf7-shortcode',
'readonly' => true,
'class' => 'large-text code selectable',
'value' => $shortcode,
) );
$formatter->end_tag( 'p' );
}
if ( $shortcode = $post->shortcode( array( 'use_old_format' => true ) ) ) {
$formatter->append_start_tag( 'p', array(
'class' => 'description',
) );
$formatter->append_start_tag( 'label', array(
'for' => 'wpcf7-shortcode-old',
) );
$formatter->append_preformatted(
esc_html( __( 'You can also use this old-style shortcode:', 'contact-form-7' ) )
);
$formatter->end_tag( 'label' );
$formatter->append_whitespace();
$formatter->append_start_tag( 'span', array(
'class' => 'shortcode old',
) );
$formatter->append_start_tag( 'input', array(
'type' => 'text',
'id' => 'wpcf7-shortcode-old',
'readonly' => true,
'class' => 'large-text code selectable',
'value' => $shortcode,
) );
$formatter->end_tag( 'p' );
}
}
$formatter->end_tag( 'div' ); // .inside
$formatter->end_tag( 'div' ); // #titlediv
$formatter->end_tag( 'div' ); // #post-body-content
$formatter->append_start_tag( 'div', array(
'id' => 'postbox-container-1',
'class' => 'postbox-container',
) );
if ( current_user_can( 'wpcf7_edit_contact_form', $post_id ) ) {
$formatter->append_start_tag( 'section', array(
'id' => 'submitdiv',
'class' => 'postbox',
) );
$formatter->append_start_tag( 'h2' );
$formatter->append_preformatted(
esc_html( __( 'Status', 'contact-form-7' ) )
);
$formatter->end_tag( 'h2' );
$formatter->append_start_tag( 'div', array(
'class' => 'inside',
) );
$formatter->append_start_tag( 'div', array(
'class' => 'submitbox',
'id' => 'submitpost',
) );
$formatter->append_start_tag( 'div', array(
'id' => 'minor-publishing-actions',
) );
$formatter->append_start_tag( 'div', array(
'class' => 'hidden',
) );
$formatter->append_start_tag( 'input', array(
'type' => 'submit',
'class' => 'button-primary',
'name' => 'wpcf7-save',
'value' => __( 'Save', 'contact-form-7' ),
) );
$formatter->end_tag( 'div' ); // .hidden
if ( ! $post->initial() ) {
$formatter->append_start_tag( 'input', array(
'type' => 'submit',
'name' => 'wpcf7-copy',
'class' => 'copy button',
'value' => __( 'Duplicate', 'contact-form-7' ),
) );
}
$formatter->end_tag( 'div' ); // #minor-publishing-actions
$formatter->append_start_tag( 'div', array(
'id' => 'misc-publishing-actions',
) );
$formatter->call_user_func( static function () use ( $post_id ) {
do_action( 'wpcf7_admin_misc_pub_section', $post_id );
} );
$formatter->end_tag( 'div' ); // #misc-publishing-actions
$formatter->append_start_tag( 'div', array(
'id' => 'major-publishing-actions',
) );
if ( ! $post->initial() ) {
$formatter->append_start_tag( 'div', array(
'id' => 'delete-action',
) );
$formatter->append_start_tag( 'input', array(
'type' => 'submit',
'name' => 'wpcf7-delete',
'class' => 'delete submitdelete',
'value' => __( 'Delete', 'contact-form-7' ),
) );
$formatter->end_tag( 'div' ); // #delete-action
}
$formatter->append_start_tag( 'div', array(
'id' => 'publishing-action',
) );
$formatter->append_preformatted( '<span class="spinner"></span>' );
$formatter->append_preformatted( $save_button );
$formatter->end_tag( 'div' ); // #publishing-action
$formatter->append_preformatted( '<div class="clear"></div>' );
$formatter->end_tag( 'div' ); // #major-publishing-actions
$formatter->end_tag( 'div' ); // #submitpost
$formatter->end_tag( 'div' ); // .inside
$formatter->end_tag( 'section' ); // #submitdiv
}
$formatter->append_start_tag( 'section', array(
'id' => 'informationdiv',
'class' => 'postbox',
) );
$formatter->append_start_tag( 'h2' );
$formatter->append_preformatted(
esc_html( __( 'Do you need help?', 'contact-form-7' ) )
);
$formatter->end_tag( 'h2' );
$formatter->append_start_tag( 'div', array(
'class' => 'inside',
) );
$formatter->append_start_tag( 'p' );
$formatter->append_preformatted(
esc_html( __( 'Here are some available options to help solve your problems.', 'contact-form-7' ) )
);
$formatter->end_tag( 'p' );
$formatter->append_start_tag( 'ol' );
$formatter->append_start_tag( 'li' );
$formatter->append_preformatted(
sprintf(
/* translators: 1: URL to FAQ, 2: URL to docs */
'<a href="%1$s">FAQ</a> and <a href="%2$s">docs</a>',
__( 'https://contactform7.com/faq/', 'contact-form-7' ),
__( 'https://contactform7.com/docs/', 'contact-form-7' )
)
);
$formatter->append_start_tag( 'li' );
$formatter->append_preformatted(
wpcf7_link(
__( 'https://wordpress.org/support/plugin/contact-form-7/', 'contact-form-7' ),
__( 'Support forums', 'contact-form-7' )
)
);
$formatter->append_start_tag( 'li' );
$formatter->append_preformatted(
wpcf7_link(
__( 'https://contactform7.com/custom-development/', 'contact-form-7' ),
__( 'Professional services', 'contact-form-7' )
)
);
$formatter->end_tag( 'ol' );
$formatter->end_tag( 'div' ); // .inside
$formatter->end_tag( 'section' ); // #informationdiv
$formatter->end_tag( 'div' ); // #postbox-container-1
$formatter->append_start_tag( 'div', array(
'id' => 'postbox-container-2',
'class' => 'postbox-container',
) );
$formatter->append_start_tag( 'div', array(
'id' => 'contact-form-editor',
) );
$formatter->call_user_func( static function () use ( $post, $post_id ) {
$editor = new WPCF7_Editor( $post );
$panels = array();
if ( current_user_can( 'wpcf7_edit_contact_form', $post_id ) ) {
$panels = array(
'form-panel' => array(
'title' => __( 'Form', 'contact-form-7' ),
'callback' => 'wpcf7_editor_panel_form',
),
'mail-panel' => array(
'title' => __( 'Mail', 'contact-form-7' ),
'callback' => 'wpcf7_editor_panel_mail',
),
'messages-panel' => array(
'title' => __( 'Messages', 'contact-form-7' ),
'callback' => 'wpcf7_editor_panel_messages',
),
);
$additional_settings = $post->prop( 'additional_settings' );
if ( ! is_scalar( $additional_settings ) ) {
$additional_settings = '';
}
$additional_settings = trim( $additional_settings );
$additional_settings = explode( "\n", $additional_settings );
$additional_settings = array_filter( $additional_settings );
$additional_settings = count( $additional_settings );
$panels['additional-settings-panel'] = array(
'title' => $additional_settings
? sprintf(
/* translators: %d: number of additional settings */
__( 'Additional Settings (%d)', 'contact-form-7' ),
$additional_settings
)
: __( 'Additional Settings', 'contact-form-7' ),
'callback' => 'wpcf7_editor_panel_additional_settings',
);
}
$panels = apply_filters( 'wpcf7_editor_panels', $panels );
foreach ( $panels as $id => $panel ) {
$editor->add_panel( $id, $panel['title'], $panel['callback'] );
}
$editor->display();
} );
$formatter->end_tag( 'div' ); // #contact-form-editor
if ( current_user_can( 'wpcf7_edit_contact_form', $post_id ) ) {
$formatter->append_start_tag( 'p', array(
'class' => 'submit',
) );
$formatter->append_preformatted( $save_button );
$formatter->end_tag( 'p' );
}
$formatter->end_tag( 'div' ); // #postbox-container-2
$formatter->end_tag( 'div' ); // #post-body
$formatter->append_preformatted( '<br class="clear" />' );
$formatter->end_tag( 'div' ); // #poststuff
$formatter->end_tag( 'form' );
}
$formatter->end_tag( 'div' ); // .wrap
$formatter->print();
$tag_generator = WPCF7_TagGenerator::get_instance();
$tag_generator->print_panels( $post );
do_action( 'wpcf7_admin_footer', $post );

View File

@ -0,0 +1,22 @@
<?php
function wpcf7_current_action() {
foreach ( array( 'action', 'action2' ) as $var ) {
$action = wpcf7_superglobal_request( $var, null );
if ( isset( $action ) and -1 !== $action ) {
return $action;
}
}
return false;
}
function wpcf7_admin_has_edit_cap() {
return current_user_can( 'wpcf7_edit_contact_forms' );
}
function wpcf7_add_tag_generator( $name, $title, $elm_id, $callback, $options = array() ) {
$tag_generator = WPCF7_TagGenerator::get_instance();
return $tag_generator->add( $name, $title, $callback, $options );
}

View File

@ -0,0 +1,241 @@
<?php
if ( ! class_exists( 'WP_List_Table' ) ) {
require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
}
class WPCF7_Contact_Form_List_Table extends WP_List_Table {
public static function define_columns() {
$columns = array(
'cb' => '<input type="checkbox" />',
'title' => __( 'Title', 'contact-form-7' ),
'shortcode' => __( 'Shortcode', 'contact-form-7' ),
'author' => __( 'Author', 'contact-form-7' ),
'date' => __( 'Date', 'contact-form-7' ),
);
return $columns;
}
public function __construct() {
parent::__construct( array(
'singular' => 'post',
'plural' => 'posts',
'ajax' => false,
) );
}
public function prepare_items() {
$current_screen = get_current_screen();
$per_page = $this->get_items_per_page( 'wpcf7_contact_forms_per_page' );
$args = array(
'posts_per_page' => $per_page,
'orderby' => 'title',
'order' => 'ASC',
'offset' => ( $this->get_pagenum() - 1 ) * $per_page,
);
if ( $search_keyword = wpcf7_superglobal_request( 's' ) ) {
$args['s'] = $search_keyword;
}
if ( $order_by = wpcf7_superglobal_request( 'orderby' ) ) {
$args['orderby'] = $order_by;
}
if (
$order = wpcf7_superglobal_request( 'order' ) and
'desc' === strtolower( $order )
) {
$args['order'] = 'DESC';
}
$this->items = WPCF7_ContactForm::find( $args );
$total_items = WPCF7_ContactForm::count();
$total_pages = ceil( $total_items / $per_page );
$this->set_pagination_args( array(
'total_items' => $total_items,
'total_pages' => $total_pages,
'per_page' => $per_page,
) );
}
public function get_columns() {
return get_column_headers( get_current_screen() );
}
protected function get_sortable_columns() {
$columns = array(
'title' => array( 'title', true ),
'author' => array( 'author', false ),
'date' => array( 'date', false ),
);
return $columns;
}
protected function get_bulk_actions() {
$actions = array(
'delete' => __( 'Delete', 'contact-form-7' ),
);
return $actions;
}
protected function column_default( $item, $column_name ) {
return '';
}
public function column_cb( $item ) {
return sprintf(
'<input type="checkbox" name="%1$s[]" value="%2$s" />',
$this->_args['singular'],
$item->id()
);
}
public function column_title( $item ) {
$edit_link = add_query_arg(
array(
'post' => absint( $item->id() ),
'action' => 'edit',
),
menu_page_url( 'wpcf7', false )
);
$output = sprintf(
'<a class="row-title" href="%1$s" aria-label="%2$s">%3$s</a>',
esc_url( $edit_link ),
esc_attr( sprintf(
/* translators: %s: title of contact form */
__( 'Edit &#8220;%s&#8221;', 'contact-form-7' ),
$item->title()
) ),
esc_html( $item->title() )
);
$output = sprintf( '<strong>%s</strong>', $output );
if ( wpcf7_validate_configuration()
and current_user_can( 'wpcf7_edit_contact_form', $item->id() ) ) {
$config_validator = new WPCF7_ConfigValidator( $item );
$config_validator->restore();
if ( $count_errors = $config_validator->count_errors() ) {
$error_notice = sprintf(
/* translators: %s: number of errors detected */
_n(
'%s configuration error detected',
'%s configuration errors detected',
$count_errors, 'contact-form-7' ),
number_format_i18n( $count_errors )
);
$output .= sprintf(
'<div class="config-error"><span class="icon-in-circle" aria-hidden="true">!</span> %s</div>',
$error_notice
);
}
}
return $output;
}
protected function handle_row_actions( $item, $column_name, $primary ) {
if ( $column_name !== $primary ) {
return '';
}
$edit_link = add_query_arg(
array(
'post' => absint( $item->id() ),
'action' => 'edit',
),
menu_page_url( 'wpcf7', false )
);
$actions = array(
'edit' => wpcf7_link( $edit_link, __( 'Edit', 'contact-form-7' ) ),
);
if ( current_user_can( 'wpcf7_edit_contact_form', $item->id() ) ) {
$copy_link = add_query_arg(
array(
'post' => absint( $item->id() ),
'action' => 'copy',
),
menu_page_url( 'wpcf7', false )
);
$copy_link = wp_nonce_url(
$copy_link,
'wpcf7-copy-contact-form_' . absint( $item->id() )
);
$actions = array_merge( $actions, array(
'copy' => wpcf7_link( $copy_link, __( 'Duplicate', 'contact-form-7' ) ),
) );
}
return $this->row_actions( $actions );
}
public function column_author( $item ) {
$post = get_post( $item->id() );
if ( ! $post ) {
return;
}
$author = get_userdata( $post->post_author );
if ( false === $author ) {
return;
}
return esc_html( $author->display_name );
}
public function column_shortcode( $item ) {
$shortcodes = array( $item->shortcode() );
$output = '';
foreach ( $shortcodes as $shortcode ) {
$output .= "\n" . sprintf(
'<span class="shortcode"><input %s /></span>',
wpcf7_format_atts( array(
'type' => 'text',
'readonly' => true,
'value' => $shortcode,
'class' => 'large-text code selectable',
) )
);
}
return trim( $output );
}
public function column_date( $item ) {
$datetime = get_post_datetime( $item->id() );
if ( false === $datetime ) {
return '';
}
$t_time = sprintf(
/* translators: 1: date, 2: time */
__( '%1$s at %2$s', 'contact-form-7' ),
/* translators: date format, see https://www.php.net/date */
$datetime->format( __( 'Y/m/d', 'contact-form-7' ) ),
/* translators: time format, see https://www.php.net/date */
$datetime->format( __( 'g:i a', 'contact-form-7' ) )
);
return $t_time;
}
}

View File

@ -0,0 +1,180 @@
<?php
add_action( 'wpcf7_admin_menu', 'wpcf7_admin_init_bulk_cv', 10, 0 );
function wpcf7_admin_init_bulk_cv() {
if (
! wpcf7_validate_configuration() or
! current_user_can( 'wpcf7_edit_contact_forms' )
) {
return;
}
$result = WPCF7::get_option( 'bulk_validate' );
$last_important_update = WPCF7_ConfigValidator::last_important_update;
if (
! empty( $result['version'] ) and
version_compare( $last_important_update, $result['version'], '<=' )
) {
return;
}
add_filter( 'wpcf7_admin_menu_change_notice',
'wpcf7_admin_menu_change_notice_bulk_cv',
10, 1
);
add_action( 'wpcf7_admin_warnings',
'wpcf7_admin_warnings_bulk_cv',
5, 3
);
}
function wpcf7_admin_menu_change_notice_bulk_cv( $counts ) {
$counts['wpcf7'] += 1;
return $counts;
}
function wpcf7_admin_warnings_bulk_cv( $page, $action, $object ) {
if ( 'wpcf7' === $page and 'validate' === $action ) {
return;
}
wp_admin_notice(
sprintf(
'%1$s &raquo; %2$s',
__( 'Misconfiguration leads to mail delivery failure or other troubles. Validate your contact forms now.', 'contact-form-7' ),
wpcf7_link(
add_query_arg(
array( 'action' => 'validate' ),
menu_page_url( 'wpcf7', false )
),
__( 'Validate Contact Form 7 Configuration', 'contact-form-7' )
)
),
array( 'type' => 'warning' )
);
}
add_action( 'wpcf7_admin_load', 'wpcf7_load_bulk_validate_page', 10, 2 );
function wpcf7_load_bulk_validate_page( $page, $action ) {
if (
'wpcf7' !== $page or
'validate' !== $action or
! wpcf7_validate_configuration() or
'POST' !== wpcf7_superglobal_server( 'REQUEST_METHOD' )
) {
return;
}
check_admin_referer( 'wpcf7-bulk-validate' );
if ( ! current_user_can( 'wpcf7_edit_contact_forms' ) ) {
wp_die( wp_kses_data( __( 'You are not allowed to validate configuration.', 'contact-form-7' ) ) );
}
$contact_forms = WPCF7_ContactForm::find();
$result = array(
'timestamp' => time(),
'version' => WPCF7_VERSION,
'count_valid' => 0,
'count_invalid' => 0,
);
foreach ( $contact_forms as $contact_form ) {
$config_validator = new WPCF7_ConfigValidator( $contact_form );
$config_validator->validate();
$config_validator->save();
if ( $config_validator->is_valid() ) {
$result['count_valid'] += 1;
} else {
$result['count_invalid'] += 1;
}
}
WPCF7::update_option( 'bulk_validate', $result );
$redirect_to = add_query_arg(
array(
'message' => 'validated',
),
menu_page_url( 'wpcf7', false )
);
wp_safe_redirect( $redirect_to );
exit();
}
function wpcf7_admin_bulk_validate_page() {
$contact_forms = WPCF7_ContactForm::find();
$count = WPCF7_ContactForm::count();
$submit_text = sprintf(
/* translators: %s: number of contact forms */
_n(
'Validate %s contact form now',
'Validate %s contact forms now',
$count, 'contact-form-7'
),
number_format_i18n( $count )
);
$formatter = new WPCF7_HTMLFormatter( array(
'allowed_html' => array_merge( wpcf7_kses_allowed_html(), array(
'form' => array(
'action' => true,
'method' => true,
),
) ),
) );
$formatter->append_start_tag( 'div', array(
'class' => 'wrap',
) );
$formatter->append_start_tag( 'h1' );
$formatter->append_preformatted(
esc_html( __( 'Validate Configuration', 'contact-form-7' ) )
);
$formatter->end_tag( 'h1' );
$formatter->append_start_tag( 'form', array(
'method' => 'post',
'action' => '',
) );
$formatter->append_start_tag( 'p' );
$formatter->call_user_func( static function () {
wp_nonce_field( 'wpcf7-bulk-validate' );
} );
$formatter->append_start_tag( 'input', array(
'type' => 'hidden',
'name' => 'action',
'value' => 'validate',
) );
$formatter->append_start_tag( 'input', array(
'type' => 'submit',
'class' => 'button',
'value' => $submit_text,
) );
$formatter->end_tag( 'form' );
$formatter->append_preformatted(
wpcf7_link(
__( 'https://contactform7.com/configuration-validator-faq/', 'contact-form-7' ),
__( 'FAQ about Configuration Validator', 'contact-form-7' )
)
);
$formatter->print();
}

View File

@ -0,0 +1,77 @@
/*
* Form Tab
*/
.tag-generator-panel {
text-align: right;
}
.tag-generator-dialog > .close-button {
right: auto;
left: 8px;
}
form.tag-generator-panel[data-version="1"] {
.control-box > fieldset > legend {
border: 1px solid #dfdfdf;
border-right: 4px solid #00a0d2;
}
.insert-box input.tag {
float: right;
}
.insert-box .submitbox input[type="button"] {
float: left;
}
}
/*
* Mail Tab
*/
.contact-form-editor-box-mail span.mailtag {
margin: 0 4px 0 0;
}
/*
* Welcome Panel
*/
.wpcf7-welcome-panel .welcome-panel-close {
left: 10px;
right: auto;
padding: 10px 21px 10px 15px;
}
.wpcf7-welcome-panel .welcome-panel-close::before {
right: 0;
left: auto;
}
.wpcf7-welcome-panel .welcome-panel-content {
margin-right: 13px;
}
.wpcf7-welcome-panel .welcome-panel-column {
float: right;
padding: 0 0 0 2%;
}
/*
* Integration
*/
.card {
border-left: 1px solid #e5e5e5;
border-right: 4px solid #e5e5e5;
}
.card img.icon {
float: right;
margin: 8px -8px 8px 8px;
}
.card h2.title {
float: right;
}
.card .infobox {
float: left;
}

View File

@ -0,0 +1,614 @@
#titlediv .inside p.description {
margin: 8px 2px 0;
}
#titlediv .inside p.description label {
cursor: pointer;
}
span.shortcode {
display: block;
margin: 2px 0;
}
span.shortcode.old {
background: #777;
color: #fff;
}
span.shortcode input {
font-size: 12px;
border: none;
box-shadow: none;
padding: 4px 8px;
margin: 0;
}
#wpcf7-contact-form-list-table span.shortcode input,
#wpcf7-contact-form-editor span.shortcode input {
background: transparent;
}
#wpcf7-contact-form-list-table span.shortcode input {
color: #444;
}
#wpcf7-contact-form-editor span.shortcode input {
color: #fff;
width: 100%;
}
#submitpost input.copy {
margin-bottom: 10px;
}
#submitpost input.delete {
padding: 0;
margin: 0;
border: none;
cursor: pointer;
background: inherit;
color: #a00;
}
#submitpost input.delete:hover {
color: #dc3232; /* Red */
}
#submitpost input.delete:focus {
outline: thin dotted;
}
.postbox-container .postbox h3 {
border-bottom: 1px solid transparent;
}
div.config-error, span.config-error, ul.config-error {
color: #444;
font-style: normal;
font-size: 13px;
}
ul.config-error {
margin: 2px 0;
}
ul.config-error li {
list-style: none;
padding: 2px 2px;
margin: 0;
}
#misc-publishing-actions .config-error {
line-height: 2;
}
[data-config-field][aria-invalid="true"] {
border-color: #dc3232;
}
#contact-form-editor-tabs .icon-in-circle,
#contact-form-editor .config-error .icon-in-circle,
.wp-list-table .config-error .icon-in-circle,
.icon-in-circle {
display: inline-block;
vertical-align: baseline;
margin: 1px 6px 0;
padding: 0 5px;
min-width: 7px;
height: 17px;
border-radius: 11px;
background-color: #ca4a1f;
color: #fff;
font-size: 12px;
font-weight: bold;
line-height: 17px;
text-align: center;
z-index: 26;
}
/*
* Tabs
*/
#contact-form-editor-tabs {
border-bottom: 1px solid #aaa;
padding: 9px 10px 0;
margin: 0;
}
#contact-form-editor-tabs button {
display: inline-block;
border: 1px solid #ccc;
border-bottom: 1px solid #aaa;
padding: 6px 10px;
margin: 0 4px -1px;
color: #333;
background-color: #e4e4e4;
font-size: 14px;
font-weight: normal;
line-height: 20px;
}
#contact-form-editor-tabs button[aria-selected="true"] {
border-top: 1px solid #aaa;
border-right: 1px solid #aaa;
border-left: 1px solid #aaa;
border-bottom: 1px solid #f5f5f5;
color: #000;
background-color: #f5f5f5;
font-weight: bold;
}
#contact-form-editor-tabs button:hover {
color: #000;
}
#contact-form-editor .contact-form-editor-panel > div.config-error {
margin-bottom: 1.4em;
}
#contact-form-editor-tabs button[aria-selected="true"] .icon-in-circle {
display: none;
}
#contact-form-editor .contact-form-editor-panel h2 {
font-size: 18px;
font-weight: 400;
line-height: 24px;
margin: 8px 0;
padding: 0;
}
#contact-form-editor .contact-form-editor-panel {
background-color: #f5f5f5;
border: 1px solid #aaa;
border-top: none;
padding: 16px;
}
#contact-form-editor .form-table th {
width: 100px;
}
#contact-form-editor .contact-form-editor-panel fieldset legend {
line-height: 1.5;
margin: .6em 0 .4em;
}
/*
* Form Tab
*/
#tag-generator-list button {
font-size: 12px;
height: 26px;
line-height: 24px;
margin: 2px;
padding: 0 8px 1px;
}
.tag-generator-dialog {
padding: 12px;
border: 1px solid #c3c4c7;
box-shadow: 0 1px 1px rgba( 0, 0, 0, 0.04 );
height: 720px;
width: 720px;
overflow: auto;
}
.tag-generator-dialog::backdrop {
background: rgb( 0 0 0 / 50% );
}
.tag-generator-dialog > .close-button {
position: absolute;
top: 8px;
right: 8px;
}
form.tag-generator-panel {
display: flex;
flex-direction: column;
height: 720px;
width: 720px;
max-height: 100%;
max-width: 100%;
margin-block-end: 0;
}
form.tag-generator-panel[data-version="2"] {
&:invalid .mail-tag-tip {
display: none;
}
.description-box {
box-sizing: border-box;
flex: none;
margin-inline: -12px;
padding-inline: 12px;
border-bottom: 1px solid #dfdfdf;
}
.control-box {
box-sizing: border-box;
flex: auto;
display: flex;
flex-direction: column;
gap: 12px 0;
min-height: 120px;
overflow: auto;
}
.control-box > fieldset {
margin-block: 8px;
margin-inline-start: 10em;
line-height: 2.25;
}
.control-box > fieldset > legend {
font-weight: bolder;
margin-block: 8px;
margin-inline-start: -10em;
line-height: 1.25;
}
.control-box input[type="text"] {
width: 20rem;
max-width: 88%;
}
.control-box input[type="number"] {
width: 8rem;
max-width: 44%;
}
.control-box textarea {
height: 12ex;
width: 20rem;
max-width: 88%;
}
.control-box select {
width: 20rem;
max-width: 88%;
}
.control-box input:invalid,
.control-box textarea:invalid {
background-color: #ffe9de;
}
.insert-box {
box-sizing: border-box;
flex: none;
margin-block-end: -12px;
margin-inline: -12px;
padding-block: 24px 12px;
padding-inline: 12px;
background-color: #fcfcfc;
border-top: 1px solid #dfdfdf;
}
.insert-box .flex-container {
display: flex;
}
.insert-box .flex-container > [data-tag-part="tag"] {
flex: auto;
margin-inline-end: 8px;
}
.insert-box .mail-tag-tip::before {
font: 1.2rem dashicons;
content: "\f348" / '';
color: #646970;
padding-inline-end: 4px;
vertical-align: top;
}
}
form.tag-generator-panel[data-version="1"] {
.control-box {
padding: 0;
margin: 0;
overflow: auto;
flex-grow: 1;
}
.control-box > fieldset > legend {
border: 1px solid #dfdfdf;
border-left: 4px solid #00a0d2;
background: #f7fcfe;
padding: 4px 12px;
margin: 4px 0;
line-height: 1.4em;
width: 100%;
box-sizing: border-box;
}
table {
width: 100%;
}
table.form-table th {
width: 120px;
padding: 4px 10px 4px 0;
font-size: 13px;
}
table.form-table td {
padding: 4px 10px;
font-size: 13px;
}
.control-box input.oneline {
width: 200px;
}
.control-box input.large-text {
width: 400px;
}
.control-box textarea.values {
width: 200px;
height: 6em;
}
.control-box input[type="number"],
.control-box input[type="date"] {
width: 88px;
}
.control-box table caption {
text-align: left;
font-size: 110%;
font-weight: bold;
color: #777;
margin: 10px 0 5px;
}
.control-box table.form-table td label {
line-height: 1.1em;
}
.control-box table.form-table td label .description {
line-height: 1.4em;
}
.insert-box {
margin: 0 -15px -15px;
padding: 8px 16px;
background-color: #fcfcfc;
border-top: 1px solid #dfdfdf;
overflow: auto;
}
.insert-box input.tag {
width: 510px;
float: left;
background-color: transparent;
box-shadow: none;
}
.insert-box .submitbox {
padding: 0;
}
.insert-box .submitbox input[type="button"] {
float: right;
}
.insert-box .description label {
cursor: text;
}
}
/*
* Mail Tab
*/
.contact-form-editor-box-mail span.mailtag {
display: inline-block;
margin: 0 0 0 4px;
padding: 1px 2px;
cursor: pointer;
color: #000;
}
.contact-form-editor-box-mail span.mailtag.used {
color: #666;
}
.contact-form-editor-box-mail span.mailtag.unused {
font-weight: bold;
}
/*
* Messages Tab
*/
#messages-panel p.description {
margin: 5px 0 10px;
}
/*
* Tabs for integration modules
*/
#sendinblue-panel table tr.inactive ~ tr {
display: none;
}
#sendinblue-panel .dashicons {
text-decoration: none;
}
#sendinblue-panel td p {
margin-top: 12px;
}
/*
* List Table
*/
.fixed .column-title {
width: 38%;
}
.fixed .column-shortcode {
width: 38%;
}
/*
* Welcome Panel
*/
.wpcf7-welcome-panel {
position: relative;
overflow: auto;
margin: 16px 0;
padding: 23px 10px 0;
border: 1px solid #c3c4c7;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.04);
background: #fff;
font-size: 13px;
line-height: 1.7;
}
.wpcf7-welcome-panel h3 {
font-size: 16px;
font-weight: 600;
line-height: 2.1em;
margin: 1em 0 1.2em;
}
.wpcf7-welcome-panel h3 .dashicons {
position: relative;
top: -2px;
display: inline-block;
width: 60px;
color: #575757;
font-size: 40px;
}
.wpcf7-welcome-panel p {
color: #646970;
}
.wpcf7-welcome-panel p a {
font-weight: bold;
}
.wpcf7-welcome-panel .welcome-panel-close {
position: absolute;
z-index: 2;
top: 10px;
right: 10px;
padding: 10px 15px 10px 21px;
font-size: 13px;
line-height: 1.23076923; /* Chrome rounding, needs to be 16px equivalent */
text-decoration: none;
}
.wpcf7-welcome-panel .welcome-panel-close::before {
background: 0 0;
color: #787c82;
content: "\f153" / '';
display: block;
font: normal 16px/20px dashicons;
speak: never;
height: 20px;
text-align: center;
width: 20px;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
position: absolute;
top: 8px;
left: 0;
transition: all .1s ease-in-out;
}
.wpcf7-welcome-panel .welcome-panel-content {
display: block;
margin-left: 13px;
max-width: 1500px;
min-height: auto;
}
.wpcf7-welcome-panel .welcome-panel-column-container {
clear: both;
position: relative;
}
.wpcf7-welcome-panel .welcome-panel-column {
display: block;
width: 48%;
min-width: 200px;
float: left;
padding: 0 2% 0 0;
margin: 0 0 1em 0;
}
@media screen and (max-width: 870px) {
.wpcf7-welcome-panel .welcome-panel-column {
display: block;
float: none;
width: 100%;
}
}
.wpcf7-welcome-panel .welcome-panel-column p {
margin-top: 7px;
color: #3c434a;
}
/*
* Integration
*/
.card {
background: #fff none repeat scroll 0 0;
border: 1px solid #e5e5e5;
border-left: 4px solid #e5e5e5;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.04);
margin-top: 20px;
max-width: 520px;
min-width: 255px;
padding: 0.7em 2em 1em;
position: relative;
}
.card.active {
border-color: #00a0d2;
}
#constant_contact.card.active {
border-color: #dc3232;
}
.card img.icon {
float: left;
margin: 8px 8px 8px -8px;
}
.card h2.title {
float: left;
max-width: 240px;
font-size: 1.3em;
font-weight: 600;
}
.card .infobox {
float: right;
font-size: 13px;
color: #666;
margin: 1em;
line-height: 1.5;
max-width: 240px;
}
.card .inside .form-table th {
padding: 15px 10px 15px 0;
width: 160px;
}
.card .inside .form-table td {
padding: 10px 10px;
}
.card .checkboxes li {
margin: 0;
}

View File

@ -0,0 +1,556 @@
<?php
class WPCF7_Editor {
private $contact_form;
private $panels = array();
public function __construct( WPCF7_ContactForm $contact_form ) {
$this->contact_form = $contact_form;
}
public function add_panel( $panel_id, $title, $callback ) {
if ( wpcf7_is_name( $panel_id ) ) {
$this->panels[$panel_id] = array(
'title' => $title,
'callback' => $callback,
);
}
}
public function display() {
if ( empty( $this->panels ) ) {
return;
}
$active_panel_id = wpcf7_superglobal_get( 'active-tab' );
if ( ! array_key_exists( $active_panel_id, $this->panels ) ) {
$active_panel_id = array_key_first( $this->panels );
}
$formatter = new WPCF7_HTMLFormatter();
$formatter->append_start_tag( 'nav', array(
'id' => 'contact-form-editor-tabs',
'role' => 'tablist',
'aria-label' => __( 'Contact form editor tabs', 'contact-form-7' ),
'data-active-tab' => absint( array_search(
$active_panel_id, array_keys( $this->panels ), true
) ),
) );
foreach ( $this->panels as $panel_id => $panel ) {
$active = $panel_id === $active_panel_id;
$formatter->append_start_tag( 'button', array(
'type' => 'button',
'role' => 'tab',
'aria-selected' => $active ? 'true' : 'false',
'aria-controls' => $panel_id,
'id' => sprintf( '%s-tab', $panel_id ),
'tabindex' => $active ? '0' : '-1',
) );
$formatter->append_preformatted( esc_html( $panel['title'] ) );
}
$formatter->end_tag( 'nav' );
foreach ( $this->panels as $panel_id => $panel ) {
$active = $panel_id === $active_panel_id;
$formatter->append_start_tag( 'section', array(
'role' => 'tabpanel',
'aria-labelledby' => sprintf( '%s-tab', $panel_id ),
'id' => $panel_id,
'class' => 'contact-form-editor-panel',
'tabindex' => '0',
'hidden' => ! $active,
) );
if ( is_callable( $panel['callback'] ) ) {
$formatter->call_user_func( $panel['callback'], $this->contact_form );
}
$formatter->end_tag( 'section' );
}
$formatter->print();
}
}
function wpcf7_editor_panel_form( $post ) {
$description = sprintf(
/* translators: %s: URL to support page about the form template */
__( 'You can edit the form template here. For details, see <a href="%s">Editing form template</a>.', 'contact-form-7' ),
__( 'https://contactform7.com/editing-form-template/', 'contact-form-7' )
);
$formatter = new WPCF7_HTMLFormatter();
$formatter->append_start_tag( 'h2' );
$formatter->append_preformatted( esc_html( __( 'Form', 'contact-form-7' ) ) );
$formatter->end_tag( 'h2' );
$formatter->append_start_tag( 'fieldset' );
$formatter->append_start_tag( 'legend' );
$formatter->append_preformatted( $description );
$formatter->end_tag( 'legend' );
$formatter->call_user_func( static function () {
$tag_generator = WPCF7_TagGenerator::get_instance();
$tag_generator->print_buttons();
} );
$formatter->append_start_tag( 'textarea', array(
'id' => 'wpcf7-form',
'name' => 'wpcf7-form',
'cols' => 100,
'rows' => 24,
'class' => 'large-text code',
'data-config-field' => 'form.body',
) );
$formatter->append_preformatted( esc_textarea( $post->prop( 'form' ) ) );
$formatter->end_tag( 'textarea' );
$formatter->print();
}
function wpcf7_editor_panel_mail( $post ) {
wpcf7_editor_box_mail( $post );
echo '<br class="clear" />';
wpcf7_editor_box_mail( $post, array(
'id' => 'wpcf7-mail-2',
'name' => 'mail_2',
'title' => __( 'Mail (2)', 'contact-form-7' ),
'use' => __( 'Use Mail (2)', 'contact-form-7' ),
) );
}
function wpcf7_editor_box_mail( $post, $options = '' ) {
$options = wp_parse_args( $options, array(
'id' => 'wpcf7-mail',
'name' => 'mail',
'title' => __( 'Mail', 'contact-form-7' ),
'use' => null,
) );
$id = esc_attr( $options['id'] );
$mail = wp_parse_args( $post->prop( $options['name'] ), array(
'active' => false,
'recipient' => '',
'sender' => '',
'subject' => '',
'body' => '',
'additional_headers' => '',
'attachments' => '',
'use_html' => false,
'exclude_blank' => false,
) );
$formatter = new WPCF7_HTMLFormatter();
$formatter->append_start_tag( 'div', array(
'class' => 'contact-form-editor-box-mail',
'id' => $id,
) );
$formatter->append_start_tag( 'h2' );
$formatter->append_preformatted( esc_html( $options['title'] ) );
$formatter->end_tag( 'h2' );
if ( ! empty( $options['use'] ) ) {
$formatter->append_start_tag( 'label', array(
'for' => sprintf( '%s-active', $id ),
) );
$formatter->append_start_tag( 'input', array(
'type' => 'checkbox',
'id' => sprintf( '%s-active', $id ),
'name' => sprintf( '%s[active]', $id ),
'data-config-field' => '',
'data-toggle' => sprintf( '%s-fieldset', $id ),
'value' => '1',
'checked' => $mail['active'],
) );
$formatter->append_whitespace();
$formatter->append_preformatted( esc_html( $options['use'] ) );
$formatter->end_tag( 'label' );
$formatter->append_start_tag( 'p', array(
'class' => 'description',
) );
$formatter->append_preformatted(
esc_html( __( 'Mail (2) is an additional mail template often used as an autoresponder.', 'contact-form-7' ) )
);
$formatter->end_tag( 'p' );
}
$formatter->append_start_tag( 'fieldset', array(
'id' => sprintf( '%s-fieldset', $id ),
) );
$formatter->append_start_tag( 'legend' );
$description = sprintf(
/* translators: %s: URL to support page about the email template */
__( 'You can edit the email template here. For details, see <a href="%s">Setting up mail</a>.', 'contact-form-7' ),
__( 'https://contactform7.com/setting-up-mail/', 'contact-form-7' )
);
$formatter->append_preformatted( $description );
$formatter->append_start_tag( 'br' );
$formatter->append_preformatted(
esc_html( __( 'In the following fields, you can use these mail-tags:', 'contact-form-7' ) )
);
$formatter->append_start_tag( 'br' );
$formatter->call_user_func( static function () use ( $post, $options ) {
$post->suggest_mail_tags( $options['name'] );
} );
$formatter->end_tag( 'legend' );
$formatter->append_start_tag( 'table', array(
'class' => 'form-table',
) );
$formatter->append_start_tag( 'tbody' );
$formatter->append_start_tag( 'tr' );
$formatter->append_start_tag( 'th', array(
'scope' => 'row',
) );
$formatter->append_start_tag( 'label', array(
'for' => sprintf( '%s-recipient', $id ),
) );
$formatter->append_preformatted(
esc_html( __( 'To', 'contact-form-7' ) )
);
$formatter->append_start_tag( 'td' );
$formatter->append_start_tag( 'input', array(
'type' => 'text',
'id' => sprintf( '%s-recipient', $id ),
'name' => sprintf( '%s[recipient]', $id ),
'class' => 'large-text code',
'size' => 70,
'value' => $mail['recipient'],
'data-config-field' => sprintf( '%s.recipient', $options['name'] ),
) );
$formatter->end_tag( 'tr' );
$formatter->append_start_tag( 'tr' );
$formatter->append_start_tag( 'th', array(
'scope' => 'row',
) );
$formatter->append_start_tag( 'label', array(
'for' => sprintf( '%s-sender', $id ),
) );
$formatter->append_preformatted(
esc_html( __( 'From', 'contact-form-7' ) )
);
$formatter->append_start_tag( 'td' );
$formatter->append_start_tag( 'input', array(
'type' => 'text',
'id' => sprintf( '%s-sender', $id ),
'name' => sprintf( '%s[sender]', $id ),
'class' => 'large-text code',
'size' => 70,
'value' => $mail['sender'],
'data-config-field' => sprintf( '%s.sender', $options['name'] ),
) );
$formatter->end_tag( 'tr' );
$formatter->append_start_tag( 'tr' );
$formatter->append_start_tag( 'th', array(
'scope' => 'row',
) );
$formatter->append_start_tag( 'label', array(
'for' => sprintf( '%s-subject', $id ),
) );
$formatter->append_preformatted(
esc_html( __( 'Subject', 'contact-form-7' ) )
);
$formatter->append_start_tag( 'td' );
$formatter->append_start_tag( 'input', array(
'type' => 'text',
'id' => sprintf( '%s-subject', $id ),
'name' => sprintf( '%s[subject]', $id ),
'class' => 'large-text code',
'size' => 70,
'value' => $mail['subject'],
'data-config-field' => sprintf( '%s.subject', $options['name'] ),
) );
$formatter->end_tag( 'tr' );
$formatter->append_start_tag( 'tr' );
$formatter->append_start_tag( 'th', array(
'scope' => 'row',
) );
$formatter->append_start_tag( 'label', array(
'for' => sprintf( '%s-additional-headers', $id ),
) );
$formatter->append_preformatted(
esc_html( __( 'Additional headers', 'contact-form-7' ) )
);
$formatter->append_start_tag( 'td' );
$formatter->append_start_tag( 'textarea', array(
'id' => sprintf( '%s-additional-headers', $id ),
'name' => sprintf( '%s[additional_headers]', $id ),
'cols' => 100,
'rows' => 4,
'class' => 'large-text code',
'data-config-field' => sprintf( '%s.additional_headers', $options['name'] ),
) );
$formatter->append_preformatted(
esc_textarea( $mail['additional_headers'] )
);
$formatter->end_tag( 'tr' );
$formatter->append_start_tag( 'tr' );
$formatter->append_start_tag( 'th', array(
'scope' => 'row',
) );
$formatter->append_start_tag( 'label', array(
'for' => sprintf( '%s-body', $id ),
) );
$formatter->append_preformatted(
esc_html( __( 'Message body', 'contact-form-7' ) )
);
$formatter->append_start_tag( 'td' );
$formatter->append_start_tag( 'textarea', array(
'id' => sprintf( '%s-body', $id ),
'name' => sprintf( '%s[body]', $id ),
'cols' => 100,
'rows' => 18,
'class' => 'large-text code',
'data-config-field' => sprintf( '%s.body', $options['name'] ),
) );
$formatter->append_preformatted(
esc_textarea( $mail['body'] )
);
$formatter->end_tag( 'textarea' );
$formatter->append_start_tag( 'p' );
$formatter->append_start_tag( 'label', array(
'for' => sprintf( '%s-exclude-blank', $id ),
) );
$formatter->append_start_tag( 'input', array(
'type' => 'checkbox',
'id' => sprintf( '%s-exclude-blank', $id ),
'name' => sprintf( '%s[exclude_blank]', $id ),
'value' => '1',
'checked' => $mail['exclude_blank'],
) );
$formatter->append_whitespace();
$formatter->append_preformatted(
esc_html( __( 'Exclude a line from output if all of its mail-tags are blank', 'contact-form-7' ) )
);
$formatter->append_start_tag( 'p' );
$formatter->append_start_tag( 'label', array(
'for' => sprintf( '%s-use-html', $id ),
) );
$formatter->append_start_tag( 'input', array(
'type' => 'checkbox',
'id' => sprintf( '%s-use-html', $id ),
'name' => sprintf( '%s[use_html]', $id ),
'value' => '1',
'checked' => $mail['use_html'],
) );
$formatter->append_whitespace();
$formatter->append_preformatted(
esc_html( __( 'Use HTML content type', 'contact-form-7' ) )
);
$formatter->end_tag( 'tr' );
$formatter->append_start_tag( 'tr' );
$formatter->append_start_tag( 'th', array(
'scope' => 'row',
) );
$formatter->append_start_tag( 'label', array(
'for' => sprintf( '%s-attachments', $id ),
) );
$formatter->append_preformatted(
esc_html( __( 'File attachments', 'contact-form-7' ) )
);
$formatter->append_start_tag( 'td' );
$formatter->append_start_tag( 'textarea', array(
'id' => sprintf( '%s-attachments', $id ),
'name' => sprintf( '%s[attachments]', $id ),
'cols' => 100,
'rows' => 4,
'class' => 'large-text code',
'data-config-field' => sprintf( '%s.attachments', $options['name'] ),
) );
$formatter->append_preformatted(
esc_textarea( $mail['attachments'] )
);
$formatter->end_tag( 'textarea' );
$formatter->end_tag( 'tr' );
$formatter->print();
}
function wpcf7_editor_panel_messages( $post ) {
$description = sprintf(
/* translators: %s: URL to support page about the messages editor */
__( 'You can edit messages used in various situations here. For details, see <a href="%s">Editing messages</a>.', 'contact-form-7' ),
__( 'https://contactform7.com/editing-messages/', 'contact-form-7' )
);
$messages = wpcf7_messages();
if (
isset( $messages['captcha_not_match'] ) and
! wpcf7_use_really_simple_captcha()
) {
unset( $messages['captcha_not_match'] );
}
$formatter = new WPCF7_HTMLFormatter();
$formatter->append_start_tag( 'h2' );
$formatter->append_preformatted(
esc_html( __( 'Messages', 'contact-form-7' ) )
);
$formatter->end_tag( 'h2' );
$formatter->append_start_tag( 'fieldset' );
$formatter->append_start_tag( 'legend' );
$formatter->append_preformatted( $description );
$formatter->end_tag( 'legend' );
foreach ( $messages as $key => $arr ) {
$field_id = sprintf( 'wpcf7-message-%s', strtr( $key, '_', '-' ) );
$field_name = sprintf( 'wpcf7-messages[%s]', $key );
$formatter->append_start_tag( 'p', array(
'class' => 'description',
) );
$formatter->append_start_tag( 'label', array(
'for' => $field_id,
) );
$formatter->append_preformatted( esc_html( $arr['description'] ) );
$formatter->append_start_tag( 'br' );
$formatter->append_start_tag( 'input', array(
'type' => 'text',
'id' => $field_id,
'name' => $field_name,
'class' => 'large-text',
'size' => 70,
'value' => $post->message( $key, false ),
'data-config-field' => sprintf( 'messages.%s', $key ),
) );
}
$formatter->print();
}
function wpcf7_editor_panel_additional_settings( $post ) {
$description = sprintf(
/* translators: %s: URL to support page about the additional settings editor */
__( 'You can add customization code snippets here. For details, see <a href="%s">Additional settings</a>.', 'contact-form-7' ),
__( 'https://contactform7.com/additional-settings/', 'contact-form-7' )
);
$formatter = new WPCF7_HTMLFormatter();
$formatter->append_start_tag( 'h2' );
$formatter->append_preformatted(
esc_html( __( 'Additional Settings', 'contact-form-7' ) )
);
$formatter->end_tag( 'h2' );
$formatter->append_start_tag( 'fieldset' );
$formatter->append_start_tag( 'legend' );
$formatter->append_preformatted( $description );
$formatter->end_tag( 'legend' );
$formatter->append_start_tag( 'textarea', array(
'id' => 'wpcf7-additional-settings',
'name' => 'wpcf7-additional-settings',
'cols' => 100,
'rows' => 24,
'class' => 'large-text',
'data-config-field' => 'additional_settings.body',
) );
$formatter->append_preformatted(
esc_textarea( $post->prop( 'additional_settings' ) )
);
$formatter->end_tag( 'textarea' );
$formatter->print();
}

View File

@ -0,0 +1,104 @@
<?php
class WPCF7_Help_Tabs {
private $screen;
public function __construct( WP_Screen $screen ) {
$this->screen = $screen;
}
public function set_help_tabs( $screen_type ) {
switch ( $screen_type ) {
case 'list':
$this->screen->add_help_tab( array(
'id' => 'list_overview',
'title' => __( 'Overview', 'contact-form-7' ),
'content' => $this->content( 'list_overview' ),
) );
$this->screen->add_help_tab( array(
'id' => 'list_available_actions',
'title' => __( 'Available Actions', 'contact-form-7' ),
'content' => $this->content( 'list_available_actions' ),
) );
$this->sidebar();
return;
case 'edit':
$this->screen->add_help_tab( array(
'id' => 'edit_overview',
'title' => __( 'Overview', 'contact-form-7' ),
'content' => $this->content( 'edit_overview' ),
) );
$this->screen->add_help_tab( array(
'id' => 'edit_form_tags',
'title' => __( 'Form-tags', 'contact-form-7' ),
'content' => $this->content( 'edit_form_tags' ),
) );
$this->screen->add_help_tab( array(
'id' => 'edit_mail_tags',
'title' => __( 'Mail-tags', 'contact-form-7' ),
'content' => $this->content( 'edit_mail_tags' ),
) );
$this->sidebar();
return;
case 'integration':
$this->screen->add_help_tab( array(
'id' => 'integration_overview',
'title' => __( 'Overview', 'contact-form-7' ),
'content' => $this->content( 'integration_overview' ),
) );
$this->sidebar();
return;
}
}
private function content( $name ) {
$content = array();
$content['list_overview'] = '<p>' . __( 'On this screen, you can manage contact forms provided by Contact Form 7. You can manage an unlimited number of contact forms. Each contact form has a unique ID and Contact Form 7 shortcode ([contact-form-7 ...]). To insert a contact form into a post or a text widget, insert the shortcode into the target.', 'contact-form-7' ) . '</p>';
$content['list_available_actions'] = '<p>' . __( 'Hovering over a row in the contact forms list will display action links that allow you to manage your contact form. You can perform the following actions:', 'contact-form-7' ) . '</p>';
$content['list_available_actions'] .= '<p>' . __( '<strong>Edit</strong> - Navigates to the editing screen for that contact form. You can also reach that screen by clicking on the contact form title.', 'contact-form-7' ) . '</p>';
$content['list_available_actions'] .= '<p>' . __( '<strong>Duplicate</strong> - Clones that contact form. A cloned contact form inherits all content from the original, but has a different ID.', 'contact-form-7' ) . '</p>';
$content['edit_overview'] = '<p>' . __( 'On this screen, you can edit a contact form. A contact form is comprised of the following components:', 'contact-form-7' ) . '</p>';
$content['edit_overview'] .= '<p>' . __( '<strong>Title</strong> is the title of a contact form. This title is only used for labeling a contact form, and can be edited.', 'contact-form-7' ) . '</p>';
$content['edit_overview'] .= '<p>' . __( '<strong>Form</strong> is a content of HTML form. You can use arbitrary HTML, which is allowed inside a form element. You can also use Contact Form 7&#8217;s form-tags here.', 'contact-form-7' ) . '</p>';
$content['edit_overview'] .= '<p>' . __( '<strong>Mail</strong> manages a mail template (headers and message body) that this contact form will send when users submit it. You can use Contact Form 7&#8217;s mail-tags here.', 'contact-form-7' ) . '</p>';
$content['edit_overview'] .= '<p>' . __( '<strong>Mail (2)</strong> is an additional mail template that works similar to Mail. Mail (2) is different in that it is sent only when Mail has been sent successfully.', 'contact-form-7' ) . '</p>';
$content['edit_overview'] .= '<p>' . __( 'In <strong>Messages</strong>, you can edit various types of messages used for this contact form. These messages are relatively short messages, like a validation error message you see when you leave a required field blank.', 'contact-form-7' ) . '</p>';
$content['edit_overview'] .= '<p>' . __( '<strong>Additional Settings</strong> provides a place where you can customize the behavior of this contact form by adding code snippets.', 'contact-form-7' ) . '</p>';
$content['edit_form_tags'] = '<p>' . __( 'A form-tag is a short code enclosed in square brackets used in a form content. A form-tag generally represents an input field, and its components can be separated into four parts: type, name, options, and values. Contact Form 7 supports several types of form-tags including text fields, number fields, date fields, checkboxes, radio buttons, menus, file-uploading fields, CAPTCHAs, and quiz fields.', 'contact-form-7' ) . '</p>';
$content['edit_form_tags'] .= '<p>' . __( 'While form-tags have a comparatively complex syntax, you do not need to know the syntax to add form-tags because you can use the straightforward tag generator (<strong>Generate Tag</strong> button on this screen).', 'contact-form-7' ) . '</p>';
$content['edit_mail_tags'] = '<p>' . __( 'A mail-tag is also a short code enclosed in square brackets that you can use in every Mail and Mail (2) field. A mail-tag represents a user input value through an input field of a corresponding form-tag.', 'contact-form-7' ) . '</p>';
$content['edit_mail_tags'] .= '<p>' . __( 'There are also special mail-tags that have specific names, but do not have corresponding form-tags. They are used to represent meta information of form submissions like the submitter&#8217;s IP address or the URL of the page.', 'contact-form-7' ) . '</p>';
$content['integration_overview'] = '<p>' . __( 'On this screen, you can manage services that are available through Contact Form 7. Using API will allow you to collaborate with any services that are available.', 'contact-form-7' ) . '</p>';
$content['integration_overview'] .= '<p>' . __( 'You may need to first sign up for an account with the service that you plan to use. When you do so, you would need to authorize Contact Form 7 to access the service with your account.', 'contact-form-7' ) . '</p>';
$content['integration_overview'] .= '<p>' . __( 'Any information you provide will not be shared with service providers without your authorization.', 'contact-form-7' ) . '</p>';
if ( ! empty( $content[$name] ) ) {
return $content[$name];
}
}
public function sidebar() {
$content = '<p><strong>' . __( 'For more information:', 'contact-form-7' ) . '</strong></p>';
$content .= '<p>' . wpcf7_link( __( 'https://contactform7.com/docs/', 'contact-form-7' ), __( 'Docs', 'contact-form-7' ) ) . '</p>';
$content .= '<p>' . wpcf7_link( __( 'https://contactform7.com/faq/', 'contact-form-7' ), __( 'FAQ', 'contact-form-7' ) ) . '</p>';
$content .= '<p>' . wpcf7_link( __( 'https://contactform7.com/support/', 'contact-form-7' ), __( 'Support', 'contact-form-7' ) ) . '</p>';
$this->screen->set_help_sidebar( $content );
}
}

View File

@ -0,0 +1,9 @@
<?php
return array(
'dependencies' => array(
'wp-api-fetch',
'wp-i18n',
),
'version' => WPCF7_VERSION,
);

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,627 @@
<?php
/**
* The base class for form-tag generators management.
*/
class WPCF7_TagGenerator {
private static $instance;
private $panels = array();
private function __construct() {}
/**
* Returns the singleton instance of this class.
*/
public static function get_instance() {
if ( empty( self::$instance ) ) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Adds a form-tag generator instance.
*/
public function add( $id, $title, $callback, $options = '' ) {
$id = trim( $id );
if (
'' === $id or
! wpcf7_is_name( $id ) or
! is_callable( $callback )
) {
return false;
}
$options = wp_parse_args( $options, array(
'version' => '1',
) );
$this->panels[$id] = array(
'title' => $title,
'content' => 'tag-generator-panel-' . $id,
'options' => $options,
'callback' => $callback,
);
if ( version_compare( $options['version'], '2', '<' ) ) {
$message = sprintf(
/* translators: 1: version, 2: tag generator title */
__( 'Use of tag generator instances older than version 2 is deprecated. Version %1$s instance (%2$s) detected.', 'contact-form-7' ),
$options['version'],
$title
);
wp_trigger_error( __METHOD__, $message, E_USER_DEPRECATED );
}
return true;
}
/**
* Renders form-tag generator calling buttons.
*/
public function print_buttons() {
$formatter = new WPCF7_HTMLFormatter();
$formatter->append_start_tag( 'span', array(
'id' => 'tag-generator-list',
'class' => 'hide-if-no-js',
) );
foreach ( (array) $this->panels as $panel ) {
$formatter->append_start_tag( 'button', array(
'type' => 'button',
'data-taggen' => 'open-dialog',
'data-target' => $panel['content'],
'title' => sprintf(
/* translators: %s: title of form-tag */
__( 'Form-tag Generator: %s', 'contact-form-7' ),
$panel['title']
),
) );
$formatter->append_preformatted( esc_html( $panel['title'] ) );
}
$formatter->print();
}
/**
* Renders form-tag generator dialog panels (hidden until called).
*/
public function print_panels( WPCF7_ContactForm $contact_form ) {
$formatter = new WPCF7_HTMLFormatter( array(
'allowed_html' => array_merge( wpcf7_kses_allowed_html(), array(
'dialog' => array(
'id' => true,
'class' => true,
),
'form' => array(
'method' => true,
'class' => true,
'data-*' => true,
),
) ),
) );
foreach ( (array) $this->panels as $id => $panel ) {
$callback = $panel['callback'];
$options = array_merge( $panel['options'], array(
'id' => $id,
'title' => $panel['title'],
'content' => $panel['content'],
) );
if ( is_callable( $callback ) ) {
$formatter->append_start_tag( 'dialog', array(
'id' => $options['content'],
'class' => 'tag-generator-dialog',
) );
$formatter->append_start_tag( 'button', array(
'class' => 'close-button',
'title' => __( 'Close this dialog box', 'contact-form-7' ),
'data-taggen' => 'close-dialog',
) );
$formatter->append_preformatted(
esc_html( __( 'Close', 'contact-form-7' ) )
);
$formatter->end_tag( 'button' );
$formatter->append_start_tag( 'form', array(
'method' => 'dialog',
'class' => 'tag-generator-panel',
'data-id' => $options['id'],
'data-version' => $options['version'],
) );
$formatter->call_user_func( $callback, $contact_form, $options );
$formatter->close_all_tags();
}
}
$formatter->print();
}
}
/**
* Class helps to implement a form-tag generator content.
*/
class WPCF7_TagGeneratorGenerator {
private $key = '';
/**
* The constructor.
*/
public function __construct( $key ) {
$this->key = $key;
}
/**
* Returns a unique reference ID.
*/
public function ref( $suffix = '' ) {
$ref = sprintf( '%s-%s', $this->key, $suffix );
$ref = strtolower( $ref );
$ref = preg_replace( '/[^0-9a-z-]/', '', $ref );
$ref = preg_replace( '/[-]+/', '-', $ref );
$ref = trim( $ref, '-' );
return $ref;
}
/**
* Calls one of the template methods.
*/
public function print( $part, $options = '' ) {
if ( is_callable( array( $this, $part ) ) ) {
call_user_func( array( $this, $part ), $options );
}
}
/**
* Template method for field type field.
*/
private function field_type( $options = '' ) {
$options = wp_parse_args( $options, array(
'with_required' => false,
'with_optional' => false,
'select_options' => array(),
) );
$formatter = new WPCF7_HTMLFormatter();
$formatter->append_start_tag( 'fieldset' );
$formatter->append_start_tag( 'legend', array(
'id' => $this->ref( 'type-legend' ),
) );
$formatter->append_preformatted(
esc_html( __( 'Field type', 'contact-form-7' ) )
);
$formatter->end_tag( 'legend' );
$formatter->append_start_tag( 'select', array(
'data-tag-part' => 'basetype',
'aria-labelledby' => $this->ref( 'type-legend' ),
) );
foreach ( (array) $options['select_options'] as $basetype => $title ) {
$formatter->append_start_tag( 'option', array(
'value' => $basetype,
) );
$formatter->append_preformatted( esc_html( $title ) );
}
$formatter->end_tag( 'select' );
if ( $options['with_required'] ) {
$formatter->append_start_tag( 'br' );
$formatter->append_start_tag( 'label' );
$formatter->append_start_tag( 'input', array(
'type' => 'checkbox',
'data-tag-part' => 'type-suffix',
'value' => '*',
) );
$formatter->append_whitespace();
$formatter->append_preformatted(
esc_html( __( 'This is a required field.', 'contact-form-7' ) )
);
}
if ( $options['with_optional'] ) {
$formatter->append_start_tag( 'br' );
$formatter->append_start_tag( 'label' );
$formatter->append_start_tag( 'input', array(
'type' => 'checkbox',
'data-tag-part' => 'option',
'data-tag-option' => 'optional',
'checked' => true,
) );
$formatter->append_whitespace();
$formatter->append_preformatted(
esc_html( __( 'This checkbox is optional.', 'contact-form-7' ) )
);
}
$formatter->print();
}
/**
* Template method for field name field.
*/
private function field_name( $options = '' ) {
$options = wp_parse_args( $options, array(
'ask_if' => '',
) );
?>
<fieldset>
<legend id="<?php echo esc_attr( $this->ref( 'name-legend' ) ); ?>"><?php
echo esc_html( __( 'Field name', 'contact-form-7' ) );
?></legend>
<input type="text" data-tag-part="name" pattern="[A-Za-z][A-Za-z0-9_\-]*" aria-labelledby="<?php echo esc_attr( $this->ref( 'name-legend' ) ); ?>" />
<?php
$tag_option = $label = '';
if ( 'author_name' === $options['ask_if'] ) {
$tag_option = 'autocomplete:name';
if ( wpcf7_akismet_is_available() ) {
$tag_option .= ' akismet:author';
}
$label = __( "This field expects the submitter name.", 'contact-form-7' );
} elseif ( 'author_email' === $options['ask_if'] ) {
$tag_option = 'autocomplete:email';
if ( wpcf7_akismet_is_available() ) {
$tag_option .= ' akismet:author_email';
}
$label = __( "This field expects the submitter email.", 'contact-form-7' );
} elseif ( 'author_url' === $options['ask_if'] ) {
$tag_option = 'autocomplete:url';
if ( wpcf7_akismet_is_available() ) {
$tag_option .= ' akismet:author_url';
}
$label = __( "This field expects the submitter URL.", 'contact-form-7' );
} elseif ( 'author_tel' === $options['ask_if'] ) {
$tag_option = 'autocomplete:tel';
$label = __( "This field expects the submitter telephone number.", 'contact-form-7' );
}
if ( $tag_option ) {
?>
<br />
<label>
<input type="checkbox" data-tag-part="option" data-tag-option="<?php echo esc_attr( $tag_option ); ?>" />
<?php echo esc_html( $label ); ?>
</label>
<?php
}
?>
</fieldset>
<?php
}
/**
* Template method for ID attribute option field.
*/
private function id_attr( $options = '' ) {
?>
<fieldset>
<legend id="<?php echo esc_attr( $this->ref( 'id-legend' ) ); ?>"><?php
echo esc_html( __( 'ID attribute', 'contact-form-7' ) );
?></legend>
<input type="text" data-tag-part="option" data-tag-option="id:" pattern="[A-Za-z][A-Za-z0-9_\-]*" aria-labelledby="<?php echo esc_attr( $this->ref( 'id-legend' ) ); ?>" />
</fieldset>
<?php
}
/**
* Template method for class attribute option field.
*/
private function class_attr( $options = '' ) {
?>
<fieldset>
<legend id="<?php echo esc_attr( $this->ref( 'class-legend' ) ); ?>"><?php
echo esc_html( __( 'Class attribute', 'contact-form-7' ) );
?></legend>
<input type="text" data-tag-part="option" data-tag-option="class:" pattern="[A-Za-z0-9_\-\s]*" aria-labelledby="<?php echo esc_attr( $this->ref( 'class-legend' ) ); ?>" />
</fieldset>
<?php
}
/**
* Template method for min/max options.
*/
private function min_max( $options = '' ) {
$options = wp_parse_args( $options, array(
'type' => 'number',
'title' => __( 'Length', 'contact-form-7' ),
'min_option' => 'minlength:',
'max_option' => 'maxlength:',
'accept_minus' => false,
) );
$formatter = new WPCF7_HTMLFormatter();
$formatter->append_start_tag( 'fieldset' );
$formatter->append_start_tag( 'legend' );
$formatter->append_preformatted( esc_html( $options['title'] ) );
$formatter->end_tag( 'legend' );
$formatter->append_start_tag( 'label' );
$formatter->append_preformatted(
esc_html( __( 'Min', 'contact-form-7' ) )
);
$formatter->append_whitespace();
$formatter->append_start_tag( 'input', array(
'type' => $options['type'],
'data-tag-part' => 'option',
'data-tag-option' => $options['min_option'],
'min' => $options['accept_minus'] ? null : 0,
) );
$formatter->end_tag( 'label' );
$formatter->append_preformatted( ' &#8660; ' );
$formatter->append_start_tag( 'label' );
$formatter->append_preformatted(
esc_html( __( 'Max', 'contact-form-7' ) )
);
$formatter->append_whitespace();
$formatter->append_start_tag( 'input', array(
'type' => $options['type'],
'data-tag-part' => 'option',
'data-tag-option' => $options['max_option'],
'min' => $options['accept_minus'] ? null : 0,
) );
$formatter->end_tag( 'label' );
$formatter->print();
}
/**
* Template method for default value field.
*/
private function default_value( $options = '' ) {
$options = wp_parse_args( $options, array(
'type' => 'text',
'title' => __( 'Default value', 'contact-form-7' ),
'with_placeholder' => false,
'use_content' => false,
) );
$formatter = new WPCF7_HTMLFormatter();
$formatter->append_start_tag( 'fieldset' );
$formatter->append_start_tag( 'legend', array(
'id' => $this->ref( 'value-legend' ),
) );
$formatter->append_preformatted( esc_html( $options['title'] ) );
$formatter->end_tag( 'legend' );
$formatter->append_start_tag( 'input', array(
'type' => $options['type'],
'data-tag-part' => $options['use_content'] ? 'content' : 'value',
'aria-labelledby' => $this->ref( 'value-legend' ),
) );
if ( $options['with_placeholder'] ) {
$formatter->append_start_tag( 'br' );
$formatter->append_start_tag( 'label' );
$formatter->append_start_tag( 'input', array(
'type' => 'checkbox',
'data-tag-part' => 'option',
'data-tag-option' => 'placeholder',
) );
$formatter->append_whitespace();
$formatter->append_preformatted(
esc_html( __( 'Use this text as the placeholder.', 'contact-form-7' ) )
);
}
$formatter->print();
}
/**
* Template method for selectable values useful for checkboxes or a menu.
*/
private function selectable_values( $options = '' ) {
$options = wp_parse_args( $options, array(
'first_as_label' => false,
'use_label_element' => false,
) );
$formatter = new WPCF7_HTMLFormatter();
$formatter->append_start_tag( 'fieldset' );
$formatter->append_start_tag( 'legend', array(
'id' => $this->ref( 'selectable-values-legend' ),
) );
$formatter->append_preformatted(
esc_html( __( 'Selectable values', 'contact-form-7' ) )
);
$formatter->end_tag( 'legend' );
$formatter->append_start_tag( 'span', array(
'id' => $this->ref( 'selectable-values-description' ),
) );
$formatter->append_preformatted(
esc_html( __( 'One item per line.', 'contact-form-7' ) )
);
$formatter->end_tag( 'span' );
$formatter->append_start_tag( 'br' );
$formatter->append_start_tag( 'textarea', array(
'required' => true,
'data-tag-part' => 'value',
'aria-labelledby' => $this->ref( 'selectable-values-legend' ),
'aria-describedby' => $this->ref( 'selectable-values-description' ),
) );
$formatter->append_preformatted(
esc_html( __( "Option 1\nOption 2\nOption 3", 'contact-form-7' ) )
);
$formatter->end_tag( 'textarea' );
if ( $options['first_as_label'] ) {
$formatter->append_start_tag( 'br' );
$formatter->append_start_tag( 'label' );
$formatter->append_start_tag( 'input', array(
'type' => 'checkbox',
'checked' => 'checked' === $options['first_as_label'],
'data-tag-part' => 'option',
'data-tag-option' => 'first_as_label',
) );
$formatter->append_whitespace();
$formatter->append_preformatted(
esc_html( __( 'Use the first item as a label.', 'contact-form-7' ) )
);
$formatter->end_tag( 'label' );
}
if ( $options['use_label_element'] ) {
$formatter->append_start_tag( 'br' );
$formatter->append_start_tag( 'label' );
$formatter->append_start_tag( 'input', array(
'type' => 'checkbox',
'checked' => 'checked' === $options['use_label_element'],
'data-tag-part' => 'option',
'data-tag-option' => 'use_label_element',
) );
$formatter->append_whitespace();
$formatter->append_preformatted(
esc_html( __( 'Wrap each item with a label element.', 'contact-form-7' ) )
);
$formatter->end_tag( 'label' );
}
$formatter->print();
}
/**
* Template method for insert-box content including the result form-tag.
*/
private function insert_box_content( $options = '' ) {
$formatter = new WPCF7_HTMLFormatter();
$formatter->append_start_tag( 'div', array(
'class' => 'flex-container',
) );
$formatter->append_start_tag( 'input', array(
'type' => 'text',
'class' => 'code selectable',
'readonly' => true,
'data-tag-part' => 'tag',
'aria-label' => __( 'The form-tag to be inserted into the form template', 'contact-form-7' ),
) );
$formatter->append_whitespace();
$formatter->append_start_tag( 'button', array(
'type' => 'button',
'class' => 'button button-primary',
'data-taggen' => 'insert-tag',
) );
$formatter->append_preformatted(
esc_html( __( 'Insert Tag', 'contact-form-7' ) )
);
$formatter->end_tag( 'button' );
$formatter->print();
}
/**
* Template method for a tip message about mail-tag.
*/
private function mail_tag_tip( $options = '' ) {
$formatter = new WPCF7_HTMLFormatter();
$formatter->append_start_tag( 'p', array(
'class' => 'mail-tag-tip',
) );
$formatter->append_preformatted( sprintf(
/* translators: %s: mail-tag corresponding to the form-tag */
esc_html( __( 'To use the user input in the email, insert the corresponding mail-tag %s into the email template.', 'contact-form-7' ) ),
'<strong data-tag-part="mail-tag"></strong>'
) );
$formatter->print();
}
}

View File

@ -0,0 +1,280 @@
<?php
abstract class WPCF7_WelcomePanelColumn {
abstract protected function icon();
abstract protected function title();
abstract protected function content();
public function print_content() {
$content = $this->content();
if ( is_array( $content ) ) {
$content = implode( "\n\n", $content );
}
$content = wp_kses_post( $content );
$content = wptexturize( $content );
$content = convert_chars( $content );
$content = wpautop( $content );
$formatter = new WPCF7_HTMLFormatter();
$formatter->append_start_tag( 'div', array(
'class' => 'welcome-panel-column',
) );
$formatter->append_start_tag( 'h3' );
$formatter->append_start_tag( 'span', array(
'class' => sprintf( 'dashicons dashicons-%s', $this->icon() ),
'aria-hidden' => 'true',
) );
$formatter->end_tag( 'span' );
$formatter->append_whitespace();
$formatter->append_preformatted( $this->title() );
$formatter->end_tag( 'h3' );
$formatter->append_preformatted( $content );
$formatter->print();
}
}
class WPCF7_WelcomePanelColumn_AntiSpam extends WPCF7_WelcomePanelColumn {
protected function icon() {
return 'shield';
}
protected function title() {
return __( 'Getting spammed? You have protection.', 'contact-form-7' );
}
protected function content() {
return array(
__( 'Spammers target everything; your contact forms are not an exception. Before you get spammed, protect your contact forms with the powerful anti-spam features Contact Form 7 provides.', 'contact-form-7' ),
sprintf(
/* translators: 1: URL to support page about Akismet, 2: Cloudflare Turnstile, 3: Disallowed list */
__( 'Contact Form 7 supports spam-filtering with <a href="%1$s">Akismet</a>. <a href="%2$s">Cloudflare Turnstile</a> blocks annoying spambots. Plus, using <a href="%3$s">disallowed list</a>, you can block messages containing specified keywords or those sent from specified IP addresses.', 'contact-form-7' ),
__( 'https://contactform7.com/spam-filtering-with-akismet/', 'contact-form-7' ),
__( 'https://contactform7.com/turnstile-integration/', 'contact-form-7' ),
__( 'https://contactform7.com/comment-blacklist/', 'contact-form-7' )
),
);
}
}
class WPCF7_WelcomePanelColumn_Donation extends WPCF7_WelcomePanelColumn {
protected function icon() {
return 'megaphone';
}
protected function title() {
return __( 'Contact Form 7 needs your support.', 'contact-form-7' );
}
protected function content() {
return array(
__( 'It is hard to continue to maintain this plugin without support from users like you.', 'contact-form-7' ),
sprintf(
/* translators: %s: URL to support page about ways to contribute */
__( 'There are several ways for you to <a href="%s">contribute to the project</a>: testing, coding, translating it into your local languages, helping other users, financial donations, etc, etc. We equally welcome you regardless of the way you contribute.', 'contact-form-7' ),
__( 'https://contactform7.com/contributing/', 'contact-form-7' )
),
);
}
}
class WPCF7_WelcomePanelColumn_Flamingo extends WPCF7_WelcomePanelColumn {
protected function icon() {
return 'editor-help';
}
protected function title() {
return __( 'Before you cry over spilt mail&#8230;', 'contact-form-7' );
}
protected function content() {
return array(
__( 'Contact Form 7 does not store submitted messages anywhere. Therefore, you may lose important messages forever if your mail server has issues or you make a mistake in mail configuration.', 'contact-form-7' ),
sprintf(
/* translators: %s: URL to support page about the Flamingo plugin */
__( 'Install a message storage plugin before this happens to you. <a href="%s">Flamingo</a> saves all messages through contact forms into the database. Flamingo is a free WordPress plugin created by the same author as Contact Form 7.', 'contact-form-7' ),
__( 'https://contactform7.com/save-submitted-messages-with-flamingo/', 'contact-form-7' )
),
);
}
}
class WPCF7_WelcomePanelColumn_Integration extends WPCF7_WelcomePanelColumn {
protected function icon() {
return 'superhero-alt';
}
protected function title() {
return __( 'You have strong allies to back you up.', 'contact-form-7' );
}
protected function content() {
return array(
sprintf(
/* translators: %s: URL to support page about the Brevo integration */
__( 'Your contact forms will become more powerful and versatile by integrating them with external APIs. With CRM and email marketing services, you can build your own contact lists (<a href="%s">Brevo</a>).', 'contact-form-7' ),
__( 'https://contactform7.com/sendinblue-integration/', 'contact-form-7' )
),
sprintf(
/* translators: 1: URL to support page about Cloudflare Turnstile, 2: Stripe */
__( 'With help from cloud-based machine learning, anti-spam services will protect your forms (<a href="%1$s">Cloudflare Turnstile</a>). Even payment services are natively supported (<a href="%2$s">Stripe</a>).', 'contact-form-7' ),
__( 'https://contactform7.com/turnstile-integration/', 'contact-form-7' ),
__( 'https://contactform7.com/stripe-integration/', 'contact-form-7' )
),
);
}
}
function wpcf7_welcome_panel() {
$columns = array();
$flamingo_is_active = defined( 'FLAMINGO_VERSION' );
$sendinblue_is_active = false;
if (
class_exists( 'WPCF7_Sendinblue' ) and
$sendinblue = WPCF7_Sendinblue::get_instance()
) {
$sendinblue_is_active = $sendinblue->is_active();
}
if ( $flamingo_is_active and $sendinblue_is_active ) {
$columns[] = new WPCF7_WelcomePanelColumn_AntiSpam();
$columns[] = new WPCF7_WelcomePanelColumn_Donation();
} elseif ( $flamingo_is_active ) {
$columns[] = new WPCF7_WelcomePanelColumn_Integration();
$columns[] = new WPCF7_WelcomePanelColumn_AntiSpam();
} elseif ( $sendinblue_is_active ) {
$columns[] = new WPCF7_WelcomePanelColumn_Flamingo();
$columns[] = new WPCF7_WelcomePanelColumn_AntiSpam();
} else {
$columns[] = new WPCF7_WelcomePanelColumn_Flamingo();
$columns[] = new WPCF7_WelcomePanelColumn_Integration();
}
$classes = 'wpcf7-welcome-panel';
$vers = (array) get_user_meta( get_current_user_id(),
'wpcf7_hide_welcome_panel_on', true
);
if ( wpcf7_version_grep( wpcf7_version( 'only_major=1' ), $vers ) ) {
$classes .= ' hidden';
}
?>
<div id="wpcf7-welcome-panel" class="<?php echo esc_attr( $classes ); ?>">
<?php wp_nonce_field( 'wpcf7-welcome-panel-nonce', 'welcomepanelnonce', false ); ?>
<a class="welcome-panel-close" href="<?php echo esc_url( menu_page_url( 'wpcf7', false ) ); ?>"><?php echo esc_html( __( 'Dismiss', 'contact-form-7' ) ); ?></a>
<div class="welcome-panel-content">
<div class="welcome-panel-column-container">
<?php
foreach ( $columns as $column ) {
$column->print_content();
}
?>
</div>
</div>
</div>
<?php
}
add_action(
'wp_ajax_wpcf7-update-welcome-panel',
'wpcf7_admin_ajax_welcome_panel',
10, 0
);
function wpcf7_admin_ajax_welcome_panel() {
check_ajax_referer( 'wpcf7-welcome-panel-nonce', 'welcomepanelnonce' );
$vers = get_user_meta( get_current_user_id(),
'wpcf7_hide_welcome_panel_on', true
);
if ( empty( $vers ) or ! is_array( $vers ) ) {
$vers = array();
}
if ( empty( $_POST['visible'] ) ) {
$vers[] = wpcf7_version( 'only_major=1' );
} else {
$vers = array_diff( $vers, array( wpcf7_version( 'only_major=1' ) ) );
}
$vers = array_unique( $vers );
update_user_meta( get_current_user_id(),
'wpcf7_hide_welcome_panel_on', $vers
);
wp_die( 1 );
}
add_filter(
'screen_settings',
'wpcf7_welcome_panel_screen_settings',
10, 2
);
function wpcf7_welcome_panel_screen_settings( $screen_settings, $screen ) {
if ( 'toplevel_page_wpcf7' !== $screen->id ) {
return $screen_settings;
}
$vers = (array) get_user_meta( get_current_user_id(),
'wpcf7_hide_welcome_panel_on', true
);
$checkbox_id = 'wpcf7-welcome-panel-show';
$checked = ! in_array( wpcf7_version( 'only_major=1' ), $vers, true );
$checkbox = sprintf(
'<input %s />',
wpcf7_format_atts( array(
'id' => $checkbox_id,
'type' => 'checkbox',
'checked' => $checked,
) )
);
$screen_settings .= sprintf( '
<fieldset class="wpcf7-welcome-panel-options">
<legend>%1$s</legend>
<label for="%2$s">%3$s %4$s</label>
</fieldset>',
esc_html( __( 'Welcome panel', 'contact-form-7' ) ),
esc_attr( $checkbox_id ),
$checkbox,
esc_html( __( 'Show welcome panel', 'contact-form-7' ) )
);
return $screen_settings;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 242.5 239.46"><defs><style>.cls-1,.cls-6{fill:none;}.cls-2{clip-path:url(#clip-path);}.cls-3{fill:#33c6f4;}.cls-4{fill:#1b447e;}.cls-5{fill:#fff;}.cls-6{stroke:#221e1f;stroke-miterlimit:10;stroke-width:7.16px;}</style><clipPath id="clip-path" transform="translate(1.72)"><circle class="cls-1" cx="119.73" cy="119.73" r="116.15"/></clipPath></defs><g id="Layer_2" data-name="Layer 2"><g id="Layer_1" data-name="Layer 1"><g class="cls-2"><circle class="cls-3" cx="121.45" cy="119.73" r="116.15"/><path class="cls-4" d="M239.32,167.79c-53.41-24-108.37-91.46-113-94.55s-10.84.77-10.84.77c-3.87-6.19-10.06.77-10.06.77C76.77,123.55.14,170.11.14,170.11S36.94,237.79,122,237.79C208.48,237.79,239.32,167.79,239.32,167.79Z" transform="translate(1.72)"/><path class="cls-5" d="M67.48,116.58s15.48-7,12.38,4.65-15.48,28.64-11.61,29.41S83,140.58,86.06,142.12s5.42.78,3.87,6.2-3.1,9.29,0,9.29,5.42-7,9.29-13.94,10.06-3.87,12.38-1.55,9.29,15.49,14.71,13.94,8.51-8.52,6.19-24,1.55-20.12,1.55-20.12,4.64-2.32,13.16,8.51,24,27.09,26.31,26.32-10.83-17.8-7.74-19.35,15.48,2.32,21.68,7.74c0,0,2.12,8.87,2.12.36L126.31,73.24,115.47,74l-10.06.77S80.64,111.94,67.48,116.58Z" transform="translate(1.72)"/><path class="cls-6" d="M239.32,170.11c-53.41-24-108.37-93.78-113-96.87s-10.84.77-10.84.77c-3.87-6.19-10.06.77-10.06.77C76.77,123.55.14,170.11.14,170.11" transform="translate(1.72)"/></g><circle class="cls-6" cx="121.45" cy="119.73" r="116.15"/></g></g></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,13 @@
<?php
add_action(
'init',
'wpcf7_init_block_editor_assets',
10, 0
);
function wpcf7_init_block_editor_assets() {
register_block_type(
wpcf7_plugin_path( 'includes/block-editor' )
);
}

View File

@ -0,0 +1,38 @@
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "contact-form-7/contact-form-selector",
"title": "Contact Form 7",
"category": "widgets",
"description": "Insert a contact form you have created with Contact Form 7.",
"keywords": [ "form" ],
"textdomain": "contact-form-7",
"attributes": {
"id": {
"type": "integer"
},
"hash": {
"type": "string"
},
"title": {
"type": "string"
},
"htmlId": {
"type": "string"
},
"htmlName": {
"type": "string"
},
"htmlTitle": {
"type": "string"
},
"htmlClass": {
"type": "string"
},
"output": {
"enum": [ "form", "raw_form" ],
"default": "form"
}
},
"editorScript": [ "file:./index.js", "contact-form-7-block-editor" ]
}

View File

@ -0,0 +1,15 @@
<?php
return array(
'dependencies' => array(
'react-jsx-runtime',
'wp-api-fetch',
'wp-block-editor',
'wp-blocks',
'wp-components',
'wp-element',
'wp-i18n',
'wp-url',
),
'version' => WPCF7_VERSION,
);

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,26 @@
<?php
add_filter( 'map_meta_cap', 'wpcf7_map_meta_cap', 10, 4 );
function wpcf7_map_meta_cap( $caps, $cap, $user_id, $args ) {
$meta_caps = array(
'wpcf7_edit_contact_form' => WPCF7_ADMIN_READ_WRITE_CAPABILITY,
'wpcf7_edit_contact_forms' => WPCF7_ADMIN_READ_WRITE_CAPABILITY,
'wpcf7_read_contact_form' => WPCF7_ADMIN_READ_CAPABILITY,
'wpcf7_read_contact_forms' => WPCF7_ADMIN_READ_CAPABILITY,
'wpcf7_delete_contact_form' => WPCF7_ADMIN_READ_WRITE_CAPABILITY,
'wpcf7_delete_contact_forms' => WPCF7_ADMIN_READ_WRITE_CAPABILITY,
'wpcf7_manage_integration' => 'manage_options',
'wpcf7_submit' => 'read',
);
$meta_caps = apply_filters( 'wpcf7_map_meta_cap', $meta_caps );
$caps = array_diff( $caps, array_keys( $meta_caps ) );
if ( isset( $meta_caps[$cap] ) ) {
$caps[] = $meta_caps[$cap];
}
return $caps;
}

View File

@ -0,0 +1,27 @@
<?php
add_action(
'wpcf7_update_option',
'wpcf7_config_validator_update_option',
10, 3
);
/**
* Runs bulk validation after the reCAPTCHA integration option is updated.
*/
function wpcf7_config_validator_update_option( $name, $value, $old_option ) {
if ( 'recaptcha' === $name ) {
$contact_forms = WPCF7_ContactForm::find();
$options = array(
'include' => 'unsafe_email_without_protection',
);
foreach ( $contact_forms as $contact_form ) {
$config_validator = new WPCF7_ConfigValidator( $contact_form, $options );
$config_validator->restore();
$config_validator->validate();
$config_validator->save();
}
}
}

View File

@ -0,0 +1,28 @@
<?php
trait WPCF7_ConfigValidator_AdditionalSettings {
/**
* Runs error detection for the additional settings section.
*/
public function validate_additional_settings() {
$section = 'additional_settings.body';
if ( $this->supports( 'deprecated_settings' ) ) {
$deprecated_settings_used =
$this->contact_form->additional_setting( 'on_sent_ok' ) ||
$this->contact_form->additional_setting( 'on_submit' );
if ( $deprecated_settings_used ) {
$this->add_error( $section, 'deprecated_settings',
array(
'message' => __( 'Deprecated settings are used.', 'contact-form-7' ),
)
);
} else {
$this->remove_error( $section, 'deprecated_settings' );
}
}
}
}

View File

@ -0,0 +1,278 @@
<?php
trait WPCF7_ConfigValidator_Form {
/**
* Runs error detection for the form section.
*/
public function validate_form() {
$section = 'form.body';
$form = $this->contact_form->prop( 'form' );
if ( $this->supports( 'multiple_controls_in_label' ) ) {
if ( $this->detect_multiple_controls_in_label( $section, $form ) ) {
$this->add_error( $section, 'multiple_controls_in_label',
array(
'message' => __( 'Multiple form controls are in a single label element.', 'contact-form-7' ),
)
);
} else {
$this->remove_error( $section, 'multiple_controls_in_label' );
}
}
if ( $this->supports( 'unavailable_names' ) ) {
$ng_names = $this->detect_unavailable_names( $section, $form );
if ( $ng_names ) {
$this->add_error( $section, 'unavailable_names',
array(
'message' =>
/* translators: %names%: a list of form control names */
__( 'Unavailable names (%names%) are used for form controls.', 'contact-form-7' ),
'params' => array( 'names' => implode( ', ', $ng_names ) ),
)
);
} else {
$this->remove_error( $section, 'unavailable_names' );
}
}
if ( $this->supports( 'unavailable_html_elements' ) ) {
if ( $this->detect_unavailable_html_elements( $section, $form ) ) {
$this->add_error( $section, 'unavailable_html_elements',
array(
'message' => __( 'Unavailable HTML elements are used in the form template.', 'contact-form-7' ),
)
);
} else {
$this->remove_error( $section, 'unavailable_html_elements' );
}
}
if ( $this->supports( 'dots_in_names' ) ) {
if ( $this->detect_dots_in_names( $section, $form ) ) {
$this->add_error( $section, 'dots_in_names',
array(
'message' => __( 'Dots are used in form-tag names.', 'contact-form-7' ),
)
);
} else {
$this->remove_error( $section, 'dots_in_names' );
}
}
if ( $this->supports( 'colons_in_names' ) ) {
if ( $this->detect_colons_in_names( $section, $form ) ) {
$this->add_error( $section, 'colons_in_names',
array(
'message' => __( 'Colons are used in form-tag names.', 'contact-form-7' ),
)
);
} else {
$this->remove_error( $section, 'colons_in_names' );
}
}
if ( $this->supports( 'upload_filesize_overlimit' ) ) {
if ( $this->detect_upload_filesize_overlimit( $section, $form ) ) {
$this->add_error( $section, 'upload_filesize_overlimit',
array(
'message' => __( 'Uploadable file size exceeds PHP&#8217;s maximum acceptable size.', 'contact-form-7' ),
)
);
} else {
$this->remove_error( $section, 'upload_filesize_overlimit' );
}
}
}
/**
* Detects errors of multiple form controls in a single label.
*
* @link https://contactform7.com/configuration-errors/multiple-controls-in-label/
*/
public function detect_multiple_controls_in_label( $section, $content ) {
$pattern = '%<label(?:[ \t\n]+.*?)?>(.+?)</label>%s';
if ( preg_match_all( $pattern, $content, $matches ) ) {
$form_tags_manager = WPCF7_FormTagsManager::get_instance();
foreach ( $matches[1] as $insidelabel ) {
$tags = $form_tags_manager->scan( $insidelabel );
$fields_count = 0;
foreach ( $tags as $tag ) {
$is_multiple_controls_container = wpcf7_form_tag_supports(
$tag->type, 'multiple-controls-container'
);
$is_zero_controls_container = wpcf7_form_tag_supports(
$tag->type, 'zero-controls-container'
);
if ( $is_multiple_controls_container ) {
$fields_count += count( $tag->values );
if ( $tag->has_option( 'free_text' ) ) {
$fields_count += 1;
}
} elseif ( $is_zero_controls_container ) {
$fields_count += 0;
} elseif ( ! empty( $tag->name ) ) {
$fields_count += 1;
}
if ( 1 < $fields_count ) {
return true;
}
}
}
}
return false;
}
/**
* Detects errors of unavailable form-tag names.
*
* @link https://contactform7.com/configuration-errors/unavailable-names/
*/
public function detect_unavailable_names( $section, $content ) {
$public_query_vars = array( 'm', 'p', 'posts', 'w', 'cat',
'withcomments', 'withoutcomments', 's', 'search', 'exact', 'sentence',
'calendar', 'page', 'paged', 'more', 'tb', 'pb', 'author', 'order',
'orderby', 'year', 'monthnum', 'day', 'hour', 'minute', 'second',
'name', 'category_name', 'tag', 'feed', 'author_name', 'static',
'pagename', 'page_id', 'error', 'attachment', 'attachment_id',
'subpost', 'subpost_id', 'preview', 'robots', 'taxonomy', 'term',
'cpage', 'post_type', 'embed',
);
$form_tags_manager = WPCF7_FormTagsManager::get_instance();
$ng_named_tags = $form_tags_manager->filter( $content, array(
'name' => $public_query_vars,
) );
$ng_names = array();
foreach ( $ng_named_tags as $tag ) {
$ng_names[] = sprintf( '"%s"', $tag->name );
}
if ( $ng_names ) {
return array_unique( $ng_names );
}
return false;
}
/**
* Detects errors of unavailable HTML elements.
*
* @link https://contactform7.com/configuration-errors/unavailable-html-elements/
*/
public function detect_unavailable_html_elements( $section, $content ) {
$pattern = '%(?:<form[\s\t>]|</form>)%i';
if ( preg_match( $pattern, $content ) ) {
return true;
}
return false;
}
/**
* Detects errors of dots in form-tag names.
*
* @link https://contactform7.com/configuration-errors/dots-in-names/
*/
public function detect_dots_in_names( $section, $content ) {
$form_tags_manager = WPCF7_FormTagsManager::get_instance();
$tags = $form_tags_manager->filter( $content, array(
'feature' => 'name-attr',
) );
foreach ( $tags as $tag ) {
if ( str_contains( $tag->raw_name, '.' ) ) {
return true;
}
}
return false;
}
/**
* Detects errors of colons in form-tag names.
*
* @link https://contactform7.com/configuration-errors/colons-in-names/
*/
public function detect_colons_in_names( $section, $content ) {
$form_tags_manager = WPCF7_FormTagsManager::get_instance();
$tags = $form_tags_manager->filter( $content, array(
'feature' => 'name-attr',
) );
foreach ( $tags as $tag ) {
if ( str_contains( $tag->raw_name, ':' ) ) {
return true;
}
}
return false;
}
/**
* Detects errors of uploadable file size overlimit.
*
* @link https://contactform7.com/configuration-errors/upload-filesize-overlimit
*/
public function detect_upload_filesize_overlimit( $section, $content ) {
$upload_max_filesize = ini_get( 'upload_max_filesize' );
if ( ! $upload_max_filesize ) {
return false;
}
$upload_max_filesize = strtolower( $upload_max_filesize );
$upload_max_filesize = trim( $upload_max_filesize );
if ( ! preg_match( '/^(\d+)([kmg]?)$/', $upload_max_filesize, $matches ) ) {
return false;
}
if ( 'k' === $matches[2] ) {
$upload_max_filesize = (int) $matches[1] * KB_IN_BYTES;
} elseif ( 'm' === $matches[2] ) {
$upload_max_filesize = (int) $matches[1] * MB_IN_BYTES;
} elseif ( 'g' === $matches[2] ) {
$upload_max_filesize = (int) $matches[1] * GB_IN_BYTES;
} else {
$upload_max_filesize = (int) $matches[1];
}
$form_tags_manager = WPCF7_FormTagsManager::get_instance();
$tags = $form_tags_manager->filter( $content, array(
'basetype' => 'file',
) );
foreach ( $tags as $tag ) {
if ( $upload_max_filesize < $tag->get_limit_option() ) {
return true;
}
}
return false;
}
}

View File

@ -0,0 +1,583 @@
<?php
trait WPCF7_ConfigValidator_Mail {
/**
* Replaces all mail-tags in the given content.
*/
public function replace_mail_tags( $content, $options = '' ) {
$options = wp_parse_args( $options, array(
'html' => false,
'callback' =>
array( $this, 'replace_mail_tags_with_minimum_input_callback' ),
) );
$content = new WPCF7_MailTaggedText( $content, $options );
return $content->replace_tags();
}
/**
* Callback function for WPCF7_MailTaggedText. Replaces mail-tags with
* the most conservative inputs.
*/
public function replace_mail_tags_with_minimum_input_callback( $matches ) {
// allow [[foo]] syntax for escaping a tag
if ( '[' === $matches[1] and ']' === $matches[4] ) {
return substr( $matches[0], 1, -1 );
}
$tag = $matches[0];
$tagname = $matches[2];
$values = $matches[3];
$mail_tag = new WPCF7_MailTag( $tag, $tagname, $values );
$field_name = $mail_tag->field_name();
$example_email = 'example@example.com';
$example_text = 'example';
$example_blank = '';
// for back-compat
$field_name = preg_replace( '/^wpcf7\./', '_', $field_name );
if ( '_site_admin_email' === $field_name ) {
return get_bloginfo( 'admin_email', 'raw' );
} elseif ( '_user_agent' === $field_name ) {
return $example_text;
} elseif ( '_user_email' === $field_name ) {
return $this->contact_form->is_true( 'subscribers_only' )
? $example_email
: $example_blank;
} elseif ( str_starts_with( $field_name, '_user_' ) ) {
return $this->contact_form->is_true( 'subscribers_only' )
? $example_text
: $example_blank;
} elseif ( str_starts_with( $field_name, '_' ) ) {
return str_ends_with( $field_name, '_email' )
? $example_email
: $example_text;
}
static $opcalcset = array();
if ( ! isset( $opcalcset[$this->contact_form->id()] ) ) {
$opcalcset[$this->contact_form->id()] =
new WPCF7_MailTag_OutputCalculator( $this->contact_form );
}
$opcalc = $opcalcset[$this->contact_form->id()];
$op = $opcalc->calc_output( $mail_tag );
if ( WPCF7_MailTag_OutputCalculator::email === $op ) {
return $example_email;
} elseif ( ! ( WPCF7_MailTag_OutputCalculator::blank & $op ) ) {
return $example_text;
} else {
return $example_blank;
}
}
/**
* Runs error detection for the mail sections.
*/
public function validate_mail( $template = 'mail' ) {
if (
$this->contact_form->is_true( 'demo_mode' ) or
$this->contact_form->is_true( 'skip_mail' )
) {
return;
}
$components = (array) $this->contact_form->prop( $template );
if ( ! $components ) {
return;
}
if ( 'mail' !== $template and empty( $components['active'] ) ) {
return;
}
$components = wp_parse_args( $components, array(
'subject' => '',
'sender' => '',
'recipient' => '',
'additional_headers' => '',
'body' => '',
'attachments' => '',
) );
$this->validate_mail_subject(
$template,
$components['subject']
);
$this->validate_mail_sender(
$template,
$components['sender']
);
$this->validate_mail_recipient(
$template,
$components['recipient']
);
$this->validate_mail_additional_headers(
$template,
$components['additional_headers']
);
$this->validate_mail_body(
$template,
$components['body']
);
$this->validate_mail_attachments(
$template,
$components['attachments']
);
}
/**
* Runs error detection for the mail subject section.
*/
public function validate_mail_subject( $template, $content ) {
$section = sprintf( '%s.subject', $template );
if ( $this->supports( 'maybe_empty' ) ) {
if ( $this->detect_maybe_empty( $section, $content ) ) {
$this->add_error( $section, 'maybe_empty',
array(
'message' => __( 'There is a possible empty field.', 'contact-form-7' ),
)
);
} else {
$this->remove_error( $section, 'maybe_empty' );
}
}
}
/**
* Runs error detection for the mail sender section.
*/
public function validate_mail_sender( $template, $content ) {
$section = sprintf( '%s.sender', $template );
if ( $this->supports( 'invalid_mailbox_syntax' ) ) {
if ( $this->detect_invalid_mailbox_syntax( $section, $content ) ) {
$this->add_error( $section, 'invalid_mailbox_syntax',
array(
'message' => __( 'Invalid mailbox syntax is used.', 'contact-form-7' ),
)
);
} else {
$this->remove_error( $section, 'invalid_mailbox_syntax' );
}
}
if ( $this->supports( 'email_not_in_site_domain' ) ) {
$this->remove_error( $section, 'email_not_in_site_domain' );
if ( ! $this->has_error( $section, 'invalid_mailbox_syntax' ) ) {
$sender = $this->replace_mail_tags( $content );
$sender = wpcf7_strip_newline( $sender );
if ( ! wpcf7_is_email_in_site_domain( $sender ) ) {
$this->add_error( $section, 'email_not_in_site_domain',
array(
'message' => __( 'Sender email address does not belong to the site domain.', 'contact-form-7' ),
)
);
}
}
}
}
/**
* Runs error detection for the mail recipient section.
*/
public function validate_mail_recipient( $template, $content ) {
$section = sprintf( '%s.recipient', $template );
if ( $this->supports( 'invalid_mailbox_syntax' ) ) {
if ( $this->detect_invalid_mailbox_syntax( $section, $content ) ) {
$this->add_error( $section, 'invalid_mailbox_syntax',
array(
'message' => __( 'Invalid mailbox syntax is used.', 'contact-form-7' ),
)
);
} else {
$this->remove_error( $section, 'invalid_mailbox_syntax' );
}
}
if ( $this->supports( 'unsafe_email_without_protection' ) ) {
$this->remove_error( $section, 'unsafe_email_without_protection' );
if ( ! $this->has_error( $section, 'invalid_mailbox_syntax' ) ) {
if (
$this->detect_unsafe_email_without_protection( $section, $content )
) {
$this->add_error( $section, 'unsafe_email_without_protection',
array(
'message' => __( 'Unsafe email config is used without sufficient protection.', 'contact-form-7' ),
)
);
}
}
}
}
/**
* Runs error detection for the mail additional headers section.
*/
public function validate_mail_additional_headers( $template, $content ) {
$section = sprintf( '%s.additional_headers', $template );
$invalid_mail_headers = array();
$invalid_mailbox_fields = array();
$unsafe_email_fields = array();
foreach ( explode( "\n", $content ) as $header ) {
$header = trim( $header );
if ( '' === $header ) {
continue;
}
$is_valid_header = preg_match(
'/^([0-9A-Za-z-]+):(.*)$/',
$header,
$matches
);
if ( ! $is_valid_header ) {
$invalid_mail_headers[] = $header;
continue;
}
$header_name = $matches[1];
$header_value = trim( $matches[2] );
if (
in_array(
strtolower( $header_name ), array( 'reply-to', 'cc', 'bcc' ), true
) and
'' !== $header_value and
$this->detect_invalid_mailbox_syntax( $section, $header_value )
) {
$invalid_mailbox_fields[] = $header_name;
continue;
}
if (
in_array( strtolower( $header_name ), array( 'cc', 'bcc' ), true ) and
$this->detect_unsafe_email_without_protection( $section, $header_value )
) {
$unsafe_email_fields[] = $header_name;
}
}
if ( $this->supports( 'invalid_mail_header' ) ) {
if ( ! empty( $invalid_mail_headers ) ) {
$this->add_error( $section, 'invalid_mail_header',
array(
'message' => __( 'There are invalid mail header fields.', 'contact-form-7' ),
)
);
} else {
$this->remove_error( $section, 'invalid_mail_header' );
}
}
if ( $this->supports( 'invalid_mailbox_syntax' ) ) {
if ( ! empty( $invalid_mailbox_fields ) ) {
foreach ( $invalid_mailbox_fields as $header_name ) {
$this->add_error( $section, 'invalid_mailbox_syntax',
array(
'message' => __( 'Invalid mailbox syntax is used in the %name% field.', 'contact-form-7' ),
'params' => array( 'name' => $header_name ),
)
);
}
} else {
$this->remove_error( $section, 'invalid_mailbox_syntax' );
}
}
if ( $this->supports( 'unsafe_email_without_protection' ) ) {
if ( ! empty( $unsafe_email_fields ) ) {
$this->add_error( $section, 'unsafe_email_without_protection',
array(
'message' => __( 'Unsafe email config is used without sufficient protection.', 'contact-form-7' ),
)
);
} else {
$this->remove_error( $section, 'unsafe_email_without_protection' );
}
}
}
/**
* Runs error detection for the mail body section.
*/
public function validate_mail_body( $template, $content ) {
$section = sprintf( '%s.body', $template );
if ( $this->supports( 'maybe_empty' ) ) {
if ( $this->detect_maybe_empty( $section, $content ) ) {
$this->add_error( $section, 'maybe_empty',
array(
'message' => __( 'There is a possible empty field.', 'contact-form-7' ),
)
);
} else {
$this->remove_error( $section, 'maybe_empty' );
}
}
}
/**
* Runs error detection for the mail attachments section.
*/
public function validate_mail_attachments( $template, $content ) {
$section = sprintf( '%s.attachments', $template );
$total_size = 0;
$files_not_found = array();
$files_out_of_content = array();
if ( '' !== $content ) {
$attachables = array();
$tags = $this->contact_form->scan_form_tags(
array( 'type' => array( 'file', 'file*' ) )
);
foreach ( $tags as $tag ) {
$name = $tag->name;
if ( ! str_contains( $content, "[{$name}]" ) ) {
continue;
}
$limit = (int) $tag->get_limit_option();
if ( empty( $attachables[$name] ) or $attachables[$name] < $limit ) {
$attachables[$name] = $limit;
}
}
$total_size = array_sum( $attachables );
foreach ( explode( "\n", $content ) as $line ) {
$line = trim( $line );
if ( '' === $line or str_starts_with( $line, '[' ) ) {
continue;
}
if ( $this->detect_file_not_found( $section, $line ) ) {
$files_not_found[] = $line;
} elseif ( $this->detect_file_not_in_content_dir( $section, $line ) ) {
$files_out_of_content[] = $line;
} else {
$total_size += (int) @filesize( path_join( WP_CONTENT_DIR, $line ) );
}
}
}
if ( $this->supports( 'file_not_found' ) ) {
if ( ! empty( $files_not_found ) ) {
foreach ( $files_not_found as $line ) {
$this->add_error( $section, 'file_not_found',
array(
'message' => __( 'Attachment file does not exist at %path%.', 'contact-form-7' ),
'params' => array( 'path' => $line ),
)
);
}
} else {
$this->remove_error( $section, 'file_not_found' );
}
}
if ( $this->supports( 'file_not_in_content_dir' ) ) {
if ( ! empty( $files_out_of_content ) ) {
$this->add_error( $section, 'file_not_in_content_dir',
array(
'message' => __( 'It is not allowed to use files outside the wp-content directory.', 'contact-form-7' ),
)
);
} else {
$this->remove_error( $section, 'file_not_in_content_dir' );
}
}
if ( $this->supports( 'attachments_overweight' ) ) {
$max = 25 * MB_IN_BYTES; // 25 MB
if ( $max < $total_size ) {
$this->add_error( $section, 'attachments_overweight',
array(
'message' => __( 'The total size of attachment files is too large.', 'contact-form-7' ),
)
);
} else {
$this->remove_error( $section, 'attachments_overweight' );
}
}
}
/**
* Detects errors of invalid mailbox syntax.
*
* @link https://contactform7.com/configuration-errors/invalid-mailbox-syntax/
*/
public function detect_invalid_mailbox_syntax( $section, $content ) {
$content = $this->replace_mail_tags( $content );
$content = wpcf7_strip_newline( $content );
if ( ! wpcf7_is_mailbox_list( $content ) ) {
return true;
}
return false;
}
/**
* Detects errors of empty message fields.
*
* @link https://contactform7.com/configuration-errors/maybe-empty/
*/
public function detect_maybe_empty( $section, $content ) {
$content = $this->replace_mail_tags( $content );
$content = wpcf7_strip_newline( $content );
if ( '' === $content ) {
return true;
}
return false;
}
/**
* Detects errors of nonexistent attachment files.
*
* @link https://contactform7.com/configuration-errors/file-not-found/
*/
public function detect_file_not_found( $section, $content ) {
$path = path_join( WP_CONTENT_DIR, $content );
if ( ! is_readable( $path ) or ! is_file( $path ) ) {
return true;
}
return false;
}
/**
* Detects errors of attachment files out of the content directory.
*
* @link https://contactform7.com/configuration-errors/file-not-in-content-dir/
*/
public function detect_file_not_in_content_dir( $section, $content ) {
$path = path_join( WP_CONTENT_DIR, $content );
if ( ! wpcf7_is_file_path_in_content_dir( $path ) ) {
return true;
}
return false;
}
/**
* Detects errors of that unsafe email config is used without
* sufficient protection.
*
* @link https://contactform7.com/configuration-errors/unsafe-email-without-protection/
*/
public function detect_unsafe_email_without_protection( $section, $content ) {
if ( $this->contact_form->is_true( 'subscribers_only' ) ) {
return false;
}
static $is_captcha_active = null;
if ( null === $is_captcha_active ) {
$is_captcha_active = call_user_func( static function () {
$recaptcha = WPCF7_RECAPTCHA::get_instance();
$turnstile = WPCF7_Turnstile::get_instance();
return $recaptcha->is_active() || $turnstile->is_active();
} );
}
if ( $is_captcha_active ) {
return false;
}
$example_email = 'user-specified@example.com';
// Replace mail-tags connected to an email type form-tag first.
$content = $this->replace_mail_tags( $content, array(
'callback' => function ( $matches ) use ( $example_email ) {
// allow [[foo]] syntax for escaping a tag
if ( '[' === $matches[1] and ']' === $matches[4] ) {
return substr( $matches[0], 1, -1 );
}
$tag = $matches[0];
$tagname = $matches[2];
$values = $matches[3];
$mail_tag = new WPCF7_MailTag( $tag, $tagname, $values );
$field_name = $mail_tag->field_name();
$form_tags = $this->contact_form->scan_form_tags(
array( 'name' => $field_name )
);
if ( $form_tags ) {
$form_tag = new WPCF7_FormTag( $form_tags[0] );
if ( 'email' === $form_tag->basetype ) {
return $example_email;
}
}
return $tag;
},
) );
// Replace remaining mail-tags.
$content = $this->replace_mail_tags( $content );
$content = wpcf7_strip_newline( $content );
if ( str_contains( $content, $example_email ) ) {
return true;
}
return false;
}
}

View File

@ -0,0 +1,55 @@
<?php
trait WPCF7_ConfigValidator_Messages {
/**
* Runs error detection for the messages section.
*/
public function validate_messages() {
$messages = (array) $this->contact_form->prop( 'messages' );
if ( ! $messages ) {
return;
}
if (
isset( $messages['captcha_not_match'] ) and
! wpcf7_use_really_simple_captcha()
) {
unset( $messages['captcha_not_match'] );
}
foreach ( $messages as $key => $message ) {
$section = sprintf( 'messages.%s', $key );
if ( $this->supports( 'html_in_message' ) ) {
if ( $this->detect_html_in_message( $section, $message ) ) {
$this->add_error( $section, 'html_in_message',
array(
'message' => __( 'HTML tags are used in a message.', 'contact-form-7' ),
)
);
} else {
$this->remove_error( $section, 'html_in_message' );
}
}
}
}
/**
* Detects errors of HTML uses in a message.
*
* @link https://contactform7.com/configuration-errors/html-in-message/
*/
public function detect_html_in_message( $section, $content ) {
$stripped = wp_strip_all_tags( $content );
if ( $stripped !== $content ) {
return true;
}
return false;
}
}

View File

@ -0,0 +1,386 @@
<?php
require_once path_join( __DIR__, 'form.php' );
require_once path_join( __DIR__, 'mail.php' );
require_once path_join( __DIR__, 'messages.php' );
require_once path_join( __DIR__, 'additional-settings.php' );
require_once path_join( __DIR__, 'actions.php' );
/**
* Configuration validator.
*
* @link https://contactform7.com/configuration-errors/
*/
class WPCF7_ConfigValidator {
/**
* The plugin version in which important updates happened last time.
*/
const last_important_update = '5.8.1';
const error_codes = array(
'maybe_empty',
'invalid_mailbox_syntax',
'email_not_in_site_domain',
'html_in_message',
'multiple_controls_in_label',
'file_not_found',
'unavailable_names',
'invalid_mail_header',
'deprecated_settings',
'file_not_in_content_dir',
'unavailable_html_elements',
'attachments_overweight',
'dots_in_names',
'colons_in_names',
'upload_filesize_overlimit',
'unsafe_email_without_protection',
);
use WPCF7_ConfigValidator_Form;
use WPCF7_ConfigValidator_Mail;
use WPCF7_ConfigValidator_Messages;
use WPCF7_ConfigValidator_AdditionalSettings;
private $contact_form;
private $errors = array();
private $include;
private $exclude;
/**
* Returns a URL linking to the documentation page for the error type.
*/
public static function get_doc_link( $child_page = '' ) {
$url = __( 'https://contactform7.com/configuration-errors/',
'contact-form-7'
);
if ( '' !== $child_page ) {
$child_page = strtr( $child_page, '_', '-' );
$url = sprintf( '%s/%s', untrailingslashit( $url ), $child_page );
}
return esc_url( $url );
}
/**
* Constructor.
*/
public function __construct( WPCF7_ContactForm $contact_form, $options = '' ) {
$options = wp_parse_args( $options, array(
'include' => null,
'exclude' => null,
) );
$this->contact_form = $contact_form;
if ( isset( $options['include'] ) ) {
$this->include = (array) $options['include'];
}
if ( isset( $options['exclude'] ) ) {
$this->exclude = (array) $options['exclude'];
}
}
/**
* Returns the contact form object that is tied to this validator.
*/
public function contact_form() {
return $this->contact_form;
}
/**
* Returns true if no error has been detected.
*/
public function is_valid() {
return ! $this->count_errors();
}
/**
* Returns true if the given error code is supported by this instance.
*/
public function supports( $error_code ) {
if ( isset( $this->include ) ) {
$supported_codes = array_intersect( self::error_codes, $this->include );
} else {
$supported_codes = self::error_codes;
}
if ( isset( $this->exclude ) ) {
$supported_codes = array_diff( $supported_codes, $this->exclude );
}
return in_array( $error_code, $supported_codes, true );
}
/**
* Counts detected errors.
*/
public function count_errors( $options = '' ) {
$options = wp_parse_args( $options, array(
'section' => '',
'code' => '',
) );
$count = 0;
foreach ( $this->errors as $key => $errors ) {
if ( preg_match( '/^mail_[0-9]+\.(.*)$/', $key, $matches ) ) {
$key = sprintf( 'mail.%s', $matches[1] );
}
if (
$options['section'] and
$key !== $options['section'] and
preg_replace( '/\..*$/', '', $key, 1 ) !== $options['section']
) {
continue;
}
foreach ( $errors as $error ) {
if ( empty( $error ) ) {
continue;
}
if ( $options['code'] and $error['code'] !== $options['code'] ) {
continue;
}
$count += 1;
}
}
return $count;
}
/**
* Collects messages for detected errors.
*/
public function collect_error_messages( $options = '' ) {
$options = wp_parse_args( $options, array(
'decodes_html_entities' => false,
) );
$error_messages = array();
foreach ( $this->errors as $section => $errors ) {
$error_messages[$section] = array();
foreach ( $errors as $error ) {
if ( empty( $error['args']['message'] ) ) {
$message = $this->get_default_message( $error['code'] );
} elseif ( empty( $error['args']['params'] ) ) {
$message = $error['args']['message'];
} else {
$message = $this->build_message(
$error['args']['message'],
$error['args']['params']
);
}
if ( $options['decodes_html_entities'] ) {
$message = html_entity_decode( $message, ENT_HTML5 );
}
$link = '';
if ( ! empty( $error['args']['link'] ) ) {
$link = $error['args']['link'];
}
$error_messages[$section][] = array(
'message' => $message,
'link' => esc_url( $link ),
);
}
}
return $error_messages;
}
/**
* Builds an error message by replacing placeholders.
*/
public function build_message( $message, $params = '' ) {
$params = wp_parse_args( $params, array() );
foreach ( $params as $key => $val ) {
if ( ! preg_match( '/^[0-9A-Za-z_]+$/', $key ) ) { // invalid key
continue;
}
$placeholder = '%' . $key . '%';
if ( false !== stripos( $message, $placeholder ) ) {
$message = str_ireplace( $placeholder, $val, $message );
}
}
return $message;
}
/**
* Returns a default message that is used when the message for the error
* is not specified.
*/
public function get_default_message( $code = '' ) {
return __( 'Configuration error is detected.', 'contact-form-7' );
}
/**
* Returns true if the specified section has the specified error.
*
* @param string $section The section where the error detected.
* @param string $code The unique code of the error.
*/
public function has_error( $section, $code ) {
if ( empty( $this->errors[$section] ) ) {
return false;
}
foreach ( (array) $this->errors[$section] as $error ) {
if ( isset( $error['code'] ) and $error['code'] === $code ) {
return true;
}
}
return false;
}
/**
* Adds a validation error.
*
* @param string $section The section where the error detected.
* @param string $code The unique code of the error.
* @param string|array $args Optional options for the error.
*/
public function add_error( $section, $code, $args = '' ) {
$args = wp_parse_args( $args, array(
'message' => '',
'params' => array(),
) );
$available_error_codes = (array) apply_filters(
'wpcf7_config_validator_available_error_codes',
self::error_codes,
$this->contact_form
);
if ( ! in_array( $code, $available_error_codes, true ) ) {
return false;
}
if ( ! isset( $args['link'] ) ) {
$args['link'] = self::get_doc_link( $code );
}
if ( ! isset( $this->errors[$section] ) ) {
$this->errors[$section] = array();
}
$this->errors[$section][] = array(
'code' => $code,
'args' => $args,
);
return true;
}
/**
* Removes an error.
*
* @param string $section The section where the error detected.
* @param string $code The unique code of the error.
*/
public function remove_error( $section, $code ) {
if ( empty( $this->errors[$section] ) ) {
return;
}
foreach ( (array) $this->errors[$section] as $key => $error ) {
if ( isset( $error['code'] ) and $error['code'] === $code ) {
unset( $this->errors[$section][$key] );
}
}
if ( empty( $this->errors[$section] ) ) {
unset( $this->errors[$section] );
}
}
/**
* The main validation runner.
*
* @return bool True if there is no error detected.
*/
public function validate() {
$this->validate_form();
$this->validate_mail( 'mail' );
$this->validate_mail( 'mail_2' );
$this->validate_messages();
$this->validate_additional_settings();
do_action( 'wpcf7_config_validator_validate', $this );
return $this->is_valid();
}
/**
* Saves detected errors as a post meta data.
*/
public function save() {
if ( $this->contact_form->initial() ) {
return;
}
delete_post_meta( $this->contact_form->id(), '_config_validation' );
if ( $this->errors ) {
update_post_meta(
$this->contact_form->id(), '_config_validation', $this->errors
);
}
}
/**
* Restore errors from the database.
*/
public function restore() {
$config_errors = get_post_meta(
$this->contact_form->id(), '_config_validation', true
);
foreach ( (array) $config_errors as $section => $errors ) {
if ( empty( $errors ) ) {
continue;
}
foreach ( (array) $errors as $error ) {
if ( ! empty( $error['code'] ) ) {
$code = $error['code'];
$args = isset( $error['args'] ) ? $error['args'] : '';
$this->add_error( $section, $code, $args );
}
}
}
}
}

View File

@ -0,0 +1,476 @@
<?php
/**
* Contact form helper functions
*/
/**
* Wrapper function of WPCF7_ContactForm::get_instance().
*
* @param WPCF7_ContactForm|WP_Post|int $post Object or post ID.
* @return WPCF7_ContactForm|null Contact form object. Null if unset.
*/
function wpcf7_contact_form( $post ) {
return WPCF7_ContactForm::get_instance( $post );
}
/**
* Searches for a contact form by an old unit ID.
*
* @param int $old_id Old unit ID.
* @return WPCF7_ContactForm Contact form object.
*/
function wpcf7_get_contact_form_by_old_id( $old_id ) {
$contact_forms = WPCF7_ContactForm::find( array(
'meta_query' => array(
array(
'key' => '_old_cf7_unit_id',
'type' => 'DECIMAL',
'value' => $old_id,
),
),
'posts_per_page' => 1,
) );
if ( $contact_forms ) {
return wpcf7_contact_form( $contact_forms[0] );
}
}
/**
* Searches for a contact form by a hash string.
*
* @param string $hash Part of a hash string.
* @return WPCF7_ContactForm Contact form object.
*/
function wpcf7_get_contact_form_by_hash( $hash ) {
if ( ! preg_match( '/^[0-9a-f]{7,}$/', $hash ) ) {
return null;
}
$contact_forms = WPCF7_ContactForm::find( array(
'meta_query' => array(
array(
'key' => '_hash',
'compare' => 'REGEXP',
'value' => '^' . $hash,
),
),
'posts_per_page' => 1,
) );
if ( $contact_forms ) {
return wpcf7_contact_form( $contact_forms[0] );
}
}
/**
* Searches for a contact form by title.
*
* @param string $title Title of contact form.
* @return WPCF7_ContactForm|null Contact form object if found, null otherwise.
*/
function wpcf7_get_contact_form_by_title( $title ) {
if ( ! is_string( $title ) or '' === $title ) {
return null;
}
$contact_forms = WPCF7_ContactForm::find( array(
'title' => $title,
'posts_per_page' => 1,
) );
if ( $contact_forms ) {
return wpcf7_contact_form( $contact_forms[0] );
}
}
/**
* Wrapper function of WPCF7_ContactForm::get_current().
*
* @return WPCF7_ContactForm Contact form object.
*/
function wpcf7_get_current_contact_form() {
if ( $current = WPCF7_ContactForm::get_current() ) {
return $current;
}
}
/**
* Returns true if it is in the state that a non-Ajax submission is accepted.
*/
function wpcf7_is_posted() {
if ( ! $contact_form = wpcf7_get_current_contact_form() ) {
return false;
}
return $contact_form->is_posted();
}
/**
* Retrieves the user input value through a non-Ajax submission.
*
* @param string $name Name of form control.
* @param string $default_value Optional default value.
* @return string The user input value through the form-control.
*/
function wpcf7_get_hangover( $name, $default_value = null ) {
if ( ! wpcf7_is_posted() ) {
return $default_value;
}
$submission = WPCF7_Submission::get_instance();
if ( ! $submission or $submission->is( 'mail_sent' ) ) {
return $default_value;
}
return wpcf7_superglobal_post( $name, $default_value );
}
/**
* Retrieves an HTML snippet of validation error on the given form control.
*
* @param string $name Name of form control.
* @return string Validation error message in a form of HTML snippet.
*/
function wpcf7_get_validation_error( $name ) {
if ( ! $contact_form = wpcf7_get_current_contact_form() ) {
return '';
}
return $contact_form->validation_error( $name );
}
/**
* Returns a reference key to a validation error message.
*
* @param string $name Name of form control.
* @param string $unit_tag Optional. Unit tag of the contact form.
* @return string Reference key code.
*/
function wpcf7_get_validation_error_reference( $name, $unit_tag = '' ) {
if ( '' === $unit_tag ) {
$contact_form = wpcf7_get_current_contact_form();
if ( $contact_form and $contact_form->validation_error( $name ) ) {
$unit_tag = $contact_form->unit_tag();
} else {
return null;
}
}
return preg_replace( '/[^0-9a-z_-]+/i', '',
sprintf(
'%1$s-ve-%2$s',
$unit_tag,
$name
)
);
}
/**
* Retrieves a message for the given status.
*/
function wpcf7_get_message( $status ) {
if ( ! $contact_form = wpcf7_get_current_contact_form() ) {
return '';
}
return $contact_form->message( $status );
}
/**
* Returns a class names list for a form-tag of the specified type.
*
* @param string $type Form-tag type.
* @param string $default_classes Optional default classes.
* @return string Whitespace-separated list of class names.
*/
function wpcf7_form_controls_class( $type, $default_classes = '' ) {
$type = trim( $type );
if ( is_string( $default_classes ) ) {
$default_classes = explode( ' ', $default_classes );
}
$classes = array(
'wpcf7-form-control',
sprintf( 'wpcf7-%s', rtrim( $type, '*' ) ),
);
if ( str_ends_with( $type, '*' ) ) {
$classes[] = 'wpcf7-validates-as-required';
}
$classes = array_merge( $classes, $default_classes );
$classes = array_filter( array_unique( $classes ) );
return implode( ' ', $classes );
}
/**
* Callback function for the contact-form-7 shortcode.
*/
function wpcf7_contact_form_tag_func( $atts, $content = null, $code = '' ) {
if ( is_feed() ) {
return '[contact-form-7]';
}
if ( 'contact-form-7' === $code ) {
$atts = shortcode_atts(
array(
'id' => '',
'title' => '',
'html_id' => '',
'html_name' => '',
'html_title' => '',
'html_class' => '',
'output' => 'form',
),
$atts, 'wpcf7'
);
$id = trim( $atts['id'] );
$title = trim( $atts['title'] );
$contact_form = wpcf7_get_contact_form_by_hash( $id );
if ( ! $contact_form ) {
$contact_form = wpcf7_contact_form( $id );
}
if ( ! $contact_form ) {
$contact_form = wpcf7_get_contact_form_by_title( $title );
}
} else {
if ( is_string( $atts ) ) {
$atts = explode( ' ', $atts, 2 );
}
$id = (int) array_shift( $atts );
$contact_form = wpcf7_get_contact_form_by_old_id( $id );
}
if ( ! $contact_form ) {
return sprintf(
'<p class="wpcf7-contact-form-not-found"><strong>%1$s</strong> %2$s</p>',
esc_html( __( 'Error:', 'contact-form-7' ) ),
esc_html( __( "Contact form not found.", 'contact-form-7' ) )
);
}
$callback = static function ( $contact_form, $atts ) {
return $contact_form->form_html( $atts );
};
$output = wpcf7_switch_locale(
$contact_form->locale(),
$callback,
$contact_form, $atts
);
do_action( 'wpcf7_shortcode_callback', $contact_form, $atts );
return $output;
}
/**
* Saves the contact form data.
*/
function wpcf7_save_contact_form( $data = '', $context = 'save' ) {
$data = wp_parse_args( $data, array(
'id' => -1,
'title' => null,
'locale' => null,
'form' => null,
'mail' => null,
'mail_2' => null,
'messages' => null,
'additional_settings' => null,
) );
$data['id'] = (int) $data['id'];
if ( -1 === $data['id'] ) {
$contact_form = WPCF7_ContactForm::get_template();
} else {
$contact_form = wpcf7_contact_form( $data['id'] );
}
if ( empty( $contact_form ) ) {
return false;
}
if ( null !== $data['title'] ) {
$contact_form->set_title( $data['title'] );
}
if ( null !== $data['locale'] ) {
$contact_form->set_locale( $data['locale'] );
}
$properties = array();
if ( null !== $data['form'] ) {
$properties['form'] = wpcf7_sanitize_form( $data['form'] );
}
if ( null !== $data['mail'] ) {
$properties['mail'] = wpcf7_sanitize_mail( $data['mail'] );
$properties['mail']['active'] = true;
}
if ( null !== $data['mail_2'] ) {
$properties['mail_2'] = wpcf7_sanitize_mail( $data['mail_2'] );
}
if ( null !== $data['messages'] ) {
$properties['messages'] = wpcf7_sanitize_messages( $data['messages'] );
}
if ( null !== $data['additional_settings'] ) {
$properties['additional_settings'] = wpcf7_sanitize_additional_settings(
$data['additional_settings']
);
}
$contact_form->set_properties( $properties );
do_action( 'wpcf7_save_contact_form', $contact_form, $data, $context );
if ( 'save' === $context ) {
$contact_form->save();
}
return $contact_form;
}
/**
* Sanitizes the form property data.
*/
function wpcf7_sanitize_form( $input, $default_template = '' ) {
if ( null === $input ) {
return $default_template;
}
$output = trim( $input );
if ( ! current_user_can( 'unfiltered_html' ) ) {
$output = wpcf7_kses( $output, 'form' );
}
return $output;
}
/**
* Sanitizes the mail property data.
*/
function wpcf7_sanitize_mail( $input, $defaults = array() ) {
$input = wp_parse_args( $input, array(
'active' => false,
'subject' => '',
'sender' => '',
'recipient' => '',
'body' => '',
'additional_headers' => '',
'attachments' => '',
'use_html' => false,
'exclude_blank' => false,
) );
$input = wp_parse_args( $input, $defaults );
$output = array();
$output['active'] = (bool) $input['active'];
$output['subject'] = trim( $input['subject'] );
$output['sender'] = trim( $input['sender'] );
$output['recipient'] = trim( $input['recipient'] );
$output['body'] = trim( $input['body'] );
if ( ! current_user_can( 'unfiltered_html' ) ) {
$output['body'] = wpcf7_kses( $output['body'], 'mail' );
}
$output['additional_headers'] = '';
$headers = str_replace( "\r\n", "\n", $input['additional_headers'] );
$headers = explode( "\n", $headers );
foreach ( $headers as $header ) {
$header = trim( $header );
if ( '' !== $header ) {
$output['additional_headers'] .= $header . "\n";
}
}
$output['additional_headers'] = trim( $output['additional_headers'] );
$output['attachments'] = trim( $input['attachments'] );
$output['use_html'] = (bool) $input['use_html'];
$output['exclude_blank'] = (bool) $input['exclude_blank'];
return $output;
}
/**
* Sanitizes the messages property data.
*/
function wpcf7_sanitize_messages( $input, $defaults = array() ) {
$output = array();
foreach ( wpcf7_messages() as $key => $val ) {
if ( isset( $input[$key] ) ) {
$output[$key] = trim( $input[$key] );
} elseif ( isset( $defaults[$key] ) ) {
$output[$key] = $defaults[$key];
}
}
return $output;
}
/**
* Sanitizes the additional settings property data.
*/
function wpcf7_sanitize_additional_settings( $input, $default_template = '' ) {
if ( null === $input ) {
return $default_template;
}
$output = trim( $input );
return $output;
}
/**
* Generates a random hash string for a contact form.
*
* @param int $post_id Post ID.
* @return string SHA-1 hash.
*/
function wpcf7_generate_contact_form_hash( $post_id ) {
return hash( 'sha256', implode( '|', array(
get_current_user_id(),
$post_id,
time(),
home_url(),
) ) );
}

View File

@ -0,0 +1,204 @@
<?php
class WPCF7_ContactFormTemplate {
public static function get_default( $prop = 'form' ) {
if ( 'form' === $prop ) {
$template = self::form();
} elseif ( 'mail' === $prop ) {
$template = self::mail();
} elseif ( 'mail_2' === $prop ) {
$template = self::mail_2();
} elseif ( 'messages' === $prop ) {
$template = self::messages();
} else {
$template = null;
}
return apply_filters( 'wpcf7_default_template', $template, $prop );
}
public static function form() {
$template = sprintf(
'
<label> %2$s
[text* your-name autocomplete:name] </label>
<label> %3$s
[email* your-email autocomplete:email] </label>
<label> %4$s
[text* your-subject] </label>
<label> %5$s %1$s
[textarea your-message] </label>
[submit "%6$s"]',
__( '(optional)', 'contact-form-7' ),
__( 'Your name', 'contact-form-7' ),
__( 'Your email', 'contact-form-7' ),
__( 'Subject', 'contact-form-7' ),
__( 'Your message', 'contact-form-7' ),
__( 'Submit', 'contact-form-7' )
);
return trim( $template );
}
public static function mail() {
$template = array(
'subject' => sprintf(
/* translators: 1: blog name, 2: [your-subject] */
_x( '%1$s "%2$s"', 'mail subject', 'contact-form-7' ),
'[_site_title]',
'[your-subject]'
),
'sender' => sprintf(
'%s <%s>',
'[_site_title]',
self::from_email()
),
'body' =>
sprintf(
/* translators: %s: [your-name] [your-email] */
__( 'From: %s', 'contact-form-7' ),
'[your-name] [your-email]'
) . "\n"
. sprintf(
/* translators: %s: [your-subject] */
__( 'Subject: %s', 'contact-form-7' ),
'[your-subject]'
) . "\n\n"
. __( 'Message Body:', 'contact-form-7' )
. "\n" . '[your-message]' . "\n\n"
. '-- ' . "\n"
. sprintf(
/* translators: 1: blog name, 2: blog URL */
__( 'This is a notification that a contact form was submitted on your website (%1$s %2$s).', 'contact-form-7' ),
'[_site_title]',
'[_site_url]'
),
'recipient' => '[_site_admin_email]',
'additional_headers' => 'Reply-To: [your-email]',
'attachments' => '',
'use_html' => 0,
'exclude_blank' => 0,
);
return $template;
}
public static function mail_2() {
$template = array(
'active' => false,
'subject' => sprintf(
/* translators: 1: blog name, 2: [your-subject] */
_x( '%1$s "%2$s"', 'mail subject', 'contact-form-7' ),
'[_site_title]',
'[your-subject]'
),
'sender' => sprintf(
'%s <%s>',
'[_site_title]',
self::from_email()
),
'body' =>
__( 'Message Body:', 'contact-form-7' )
. "\n" . '[your-message]' . "\n\n"
. '-- ' . "\n"
. sprintf(
/* translators: 1: blog name, 2: blog URL */
__( 'This email is a receipt for your contact form submission on our website (%1$s %2$s) in which your email address was used. If that was not you, please ignore this message.', 'contact-form-7' ),
'[_site_title]',
'[_site_url]'
),
'recipient' => '[your-email]',
'additional_headers' => sprintf(
'Reply-To: %s',
'[_site_admin_email]'
),
'attachments' => '',
'use_html' => 0,
'exclude_blank' => 0,
);
return $template;
}
public static function from_email() {
$admin_email = get_option( 'admin_email' );
if ( wpcf7_is_localhost() ) {
return $admin_email;
}
$sitename = wp_parse_url( network_home_url(), PHP_URL_HOST );
$sitename = strtolower( $sitename );
if ( 'www.' === substr( $sitename, 0, 4 ) ) {
$sitename = substr( $sitename, 4 );
}
if ( strpbrk( $admin_email, '@' ) === '@' . $sitename ) {
return $admin_email;
}
return 'wordpress@' . $sitename;
}
public static function messages() {
$messages = array();
foreach ( wpcf7_messages() as $key => $arr ) {
$messages[$key] = $arr['default'];
}
return $messages;
}
}
function wpcf7_messages() {
$messages = array(
'mail_sent_ok' => array(
'description' => __( 'Sender&#8217;s message was sent successfully', 'contact-form-7' ),
'default' => __( 'Thank you for your message. It has been sent.', 'contact-form-7' ),
),
'mail_sent_ng' => array(
'description' => __( 'Sender&#8217;s message failed to send', 'contact-form-7' ),
'default' => __( 'There was an error trying to send your message. Please try again later.', 'contact-form-7' ),
),
'validation_error' => array(
'description' => __( 'Validation errors occurred', 'contact-form-7' ),
'default' => __( 'One or more fields have an error. Please check and try again.', 'contact-form-7' ),
),
'spam' => array(
'description' => __( 'Submission was referred to as spam', 'contact-form-7' ),
'default' => __( 'There was an error trying to send your message. Please try again later.', 'contact-form-7' ),
),
'accept_terms' => array(
'description' => __( 'There are terms that the sender must accept', 'contact-form-7' ),
'default' => __( 'You must accept the terms and conditions before sending your message.', 'contact-form-7' ),
),
'invalid_required' => array(
'description' => __( 'There is a field that the sender must fill in', 'contact-form-7' ),
'default' => __( 'Please fill out this field.', 'contact-form-7' ),
),
'invalid_too_long' => array(
'description' => __( 'There is a field with input that is longer than the maximum allowed length', 'contact-form-7' ),
'default' => __( 'This field has a too long input.', 'contact-form-7' ),
),
'invalid_too_short' => array(
'description' => __( 'There is a field with input that is shorter than the minimum allowed length', 'contact-form-7' ),
'default' => __( 'This field has a too short input.', 'contact-form-7' ),
),
);
return apply_filters( 'wpcf7_messages', $messages );
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,184 @@
<?php
/**
* Controller for front-end requests, scripts, and styles
*/
add_action(
'parse_request',
'wpcf7_control_init',
20, 0
);
/**
* Handles a submission in non-Ajax mode.
*/
function wpcf7_control_init() {
if ( WPCF7_Submission::is_restful() ) {
return;
}
if (
$id = (int) wpcf7_superglobal_post( '_wpcf7' ) and
$contact_form = wpcf7_contact_form( $id )
) {
$contact_form->submit();
}
}
/**
* Registers main scripts and styles.
*/
add_action(
'wp_enqueue_scripts',
static function () {
$assets = include wpcf7_plugin_path( 'includes/js/index.asset.php' );
$assets = wp_parse_args( $assets, array(
'dependencies' => array(),
'version' => WPCF7_VERSION,
) );
wp_register_script(
'contact-form-7',
wpcf7_plugin_url( 'includes/js/index.js' ),
array_merge(
$assets['dependencies'],
array( 'swv' )
),
$assets['version'],
array( 'in_footer' => true )
);
wp_set_script_translations( 'contact-form-7', 'contact-form-7' );
wp_register_script(
'contact-form-7-html5-fallback',
wpcf7_plugin_url( 'includes/js/html5-fallback.js' ),
array( 'jquery-ui-datepicker' ),
WPCF7_VERSION,
array( 'in_footer' => true )
);
if ( wpcf7_load_js() ) {
wpcf7_enqueue_scripts();
}
wp_register_style(
'contact-form-7',
wpcf7_plugin_url( 'includes/css/styles.css' ),
array(),
WPCF7_VERSION,
'all'
);
wp_register_style(
'contact-form-7-rtl',
wpcf7_plugin_url( 'includes/css/styles-rtl.css' ),
array( 'contact-form-7' ),
WPCF7_VERSION,
'all'
);
wp_register_style(
'jquery-ui-smoothness',
wpcf7_plugin_url(
'includes/js/jquery-ui/themes/smoothness/jquery-ui.min.css'
),
array(),
'1.12.1',
'screen'
);
if ( wpcf7_load_css() ) {
wpcf7_enqueue_styles();
}
},
10, 0
);
/**
* Enqueues scripts.
*/
function wpcf7_enqueue_scripts() {
wp_enqueue_script( 'contact-form-7' );
$wpcf7_obj = array(
'api' => array(
'root' => sanitize_url( get_rest_url() ),
'namespace' => 'contact-form-7/v1',
),
);
if ( defined( 'WP_CACHE' ) and WP_CACHE ) {
$wpcf7_obj = array_merge( $wpcf7_obj, array(
'cached' => 1,
) );
}
wp_add_inline_script( 'contact-form-7',
sprintf(
'var wpcf7 = %s;',
wp_json_encode( $wpcf7_obj, JSON_PRETTY_PRINT )
),
'before'
);
do_action( 'wpcf7_enqueue_scripts' );
}
/**
* Returns true if the main script is enqueued.
*/
function wpcf7_script_is() {
return wp_script_is( 'contact-form-7' );
}
/**
* Enqueues styles.
*/
function wpcf7_enqueue_styles() {
wp_enqueue_style( 'contact-form-7' );
if ( wpcf7_is_rtl() ) {
wp_enqueue_style( 'contact-form-7-rtl' );
}
do_action( 'wpcf7_enqueue_styles' );
}
/**
* Returns true if the main stylesheet is enqueued.
*/
function wpcf7_style_is() {
return wp_style_is( 'contact-form-7' );
}
add_action(
'wp_enqueue_scripts',
'wpcf7_html5_fallback',
20, 0
);
/**
* Enqueues scripts and styles for the HTML5 fallback.
*/
function wpcf7_html5_fallback() {
if ( ! wpcf7_support_html5_fallback() ) {
return;
}
if ( wpcf7_script_is() ) {
wp_enqueue_script( 'contact-form-7-html5-fallback' );
}
if ( wpcf7_style_is() ) {
wp_enqueue_style( 'jquery-ui-smoothness' );
}
}

View File

@ -0,0 +1,11 @@
.wpcf7-not-valid-tip {
direction: rtl;
}
.use-floating-validation-tip .wpcf7-not-valid-tip {
right: 1em;
}
.wpcf7-list-item {
margin: 0 1em 0 0;
}

View File

@ -0,0 +1,176 @@
.wpcf7 .screen-reader-response {
position: absolute;
overflow: hidden;
clip: rect(1px, 1px, 1px, 1px);
clip-path: inset(50%);
height: 1px;
width: 1px;
margin: -1px;
padding: 0;
border: 0;
word-wrap: normal !important;
}
.wpcf7 .hidden-fields-container {
display: none;
}
.wpcf7 form .wpcf7-response-output {
margin: 2em 0.5em 1em;
padding: 0.2em 1em;
border: 2px solid #00a0d2; /* Blue */
}
.wpcf7 form.init .wpcf7-response-output,
.wpcf7 form.resetting .wpcf7-response-output,
.wpcf7 form.submitting .wpcf7-response-output {
display: none;
}
.wpcf7 form.sent .wpcf7-response-output {
border-color: #46b450; /* Green */
}
.wpcf7 form.failed .wpcf7-response-output,
.wpcf7 form.aborted .wpcf7-response-output {
border-color: #dc3232; /* Red */
}
.wpcf7 form.spam .wpcf7-response-output {
border-color: #f56e28; /* Orange */
}
.wpcf7 form.invalid .wpcf7-response-output,
.wpcf7 form.unaccepted .wpcf7-response-output,
.wpcf7 form.payment-required .wpcf7-response-output {
border-color: #ffb900; /* Yellow */
}
.wpcf7-form-control-wrap {
position: relative;
}
.wpcf7-not-valid-tip {
color: #dc3232; /* Red */
font-size: 1em;
font-weight: normal;
display: block;
}
.use-floating-validation-tip .wpcf7-not-valid-tip {
position: relative;
top: -2ex;
left: 1em;
z-index: 100;
border: 1px solid #dc3232;
background: #fff;
padding: .2em .8em;
width: 24em;
}
.wpcf7-list-item {
display: inline-block;
margin: 0 0 0 1em;
}
.wpcf7-list-item-label::before,
.wpcf7-list-item-label::after {
content: " ";
}
.wpcf7-spinner {
visibility: hidden;
display: inline-block;
background-color: #23282d; /* Dark Gray 800 */
opacity: 0.75;
width: 24px;
height: 24px;
border: none;
border-radius: 100%;
padding: 0;
margin: 0 24px;
position: relative;
}
form.submitting .wpcf7-spinner {
visibility: visible;
}
.wpcf7-spinner::before {
content: '';
position: absolute;
background-color: #fbfbfc; /* Light Gray 100 */
top: 4px;
left: 4px;
width: 6px;
height: 6px;
border: none;
border-radius: 100%;
transform-origin: 8px 8px;
animation-name: spin;
animation-duration: 1000ms;
animation-timing-function: linear;
animation-iteration-count: infinite;
}
@media (prefers-reduced-motion: reduce) {
.wpcf7-spinner::before {
animation-name: blink;
animation-duration: 2000ms;
}
}
@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
@keyframes blink {
from {
opacity: 0;
}
50% {
opacity: 1;
}
to {
opacity: 0;
}
}
.wpcf7 [inert] {
opacity: 0.5;
}
.wpcf7 input[type="file"] {
cursor: pointer;
}
.wpcf7 input[type="file"]:disabled {
cursor: default;
}
.wpcf7 .wpcf7-submit:disabled {
cursor: not-allowed;
}
.wpcf7 input[type="url"],
.wpcf7 input[type="email"],
.wpcf7 input[type="tel"] {
direction: ltr;
}
.wpcf7-reflection > output {
display: list-item;
list-style: none;
}
.wpcf7-reflection > output[hidden] {
display: none;
}

View File

@ -0,0 +1,440 @@
<?php
/**
* Validates uploaded files and moves them to the temporary directory.
*
* @param array $file An item of `$_FILES`.
* @param string|array $options Optional. Options to control behavior.
* @return array|WP_Error Array of file paths, or WP_Error if validation fails.
*/
function wpcf7_unship_uploaded_file( $file, $options = '' ) {
$filesystem = WPCF7_Filesystem::get_instance();
$options = wp_parse_args( $options, array(
'required' => false,
'filetypes' => '',
'limit' => MB_IN_BYTES,
) );
foreach ( array( 'name', 'size', 'tmp_name', 'error' ) as $key ) {
if ( ! isset( $file[$key] ) ) {
$file[$key] = array();
}
}
$names = wpcf7_array_flatten( $file['name'] );
$sizes = wpcf7_array_flatten( $file['size'] );
$tmp_names = wpcf7_array_flatten( $file['tmp_name'] );
$errors = wpcf7_array_flatten( $file['error'] );
foreach ( $errors as $error ) {
if ( ! empty( $error ) and UPLOAD_ERR_NO_FILE !== $error ) {
return new WP_Error( 'wpcf7_upload_failed_php_error',
wpcf7_get_message( 'upload_failed_php_error' )
);
}
}
if ( isset( $options['schema'] ) and isset( $options['name'] ) ) {
$context = array(
'file' => true,
'field' => $options['name'],
);
foreach ( $options['schema']->validate( $context ) as $result ) {
if ( is_wp_error( $result ) ) {
return $result;
}
}
}
// Move uploaded file to tmp dir
$uploads_dir = wpcf7_upload_tmp_dir();
$uploads_dir = wpcf7_maybe_add_random_dir( $uploads_dir );
$uploaded_files = array();
foreach ( $names as $key => $name ) {
$tmp_name = $tmp_names[$key];
if ( empty( $tmp_name ) or ! is_uploaded_file( $tmp_name ) ) {
continue;
}
$filename = $name;
$filename = wpcf7_canonicalize( $filename, array( 'strto' => 'as-is' ) );
$filename = wpcf7_antiscript_file_name( $filename );
$filename = apply_filters( 'wpcf7_upload_file_name',
$filename, $name, $options
);
$filename = wp_unique_filename( $uploads_dir, $filename );
$new_file = path_join( $uploads_dir, $filename );
// phpcs:ignore Generic.PHP.ForbiddenFunctions.Found
if ( false === @move_uploaded_file( $tmp_name, $new_file ) ) {
return new WP_Error( 'wpcf7_upload_failed',
wpcf7_get_message( 'upload_failed' )
);
}
// Make sure the uploaded file is only readable for the owner process.
$filesystem->chmod( $new_file, 0400 );
$uploaded_files[] = $new_file;
}
return $uploaded_files;
}
add_filter(
'wpcf7_messages',
'wpcf7_file_messages',
10, 1
);
/**
* A wpcf7_messages filter callback that adds messages for
* file-uploading fields.
*/
function wpcf7_file_messages( $messages ) {
return array_merge( $messages, array(
'upload_failed' => array(
'description' => __( 'Uploading a file fails for any reason', 'contact-form-7' ),
'default' => __( 'There was an unknown error uploading the file.', 'contact-form-7' ),
),
'upload_file_type_invalid' => array(
'description' => __( 'Uploaded file is not allowed for file type', 'contact-form-7' ),
'default' => __( 'You are not allowed to upload files of this type.', 'contact-form-7' ),
),
'upload_file_too_large' => array(
'description' => __( 'Uploaded file is too large', 'contact-form-7' ),
'default' => __( 'The uploaded file is too large.', 'contact-form-7' ),
),
'upload_failed_php_error' => array(
'description' => __( 'Uploading a file fails for PHP error', 'contact-form-7' ),
'default' => __( 'There was an error uploading the file.', 'contact-form-7' ),
),
) );
}
add_filter(
'wpcf7_form_enctype',
'wpcf7_file_form_enctype_filter',
10, 1
);
/**
* A wpcf7_form_enctype filter callback that sets the enctype attribute
* to multipart/form-data if the form has file-uploading fields.
*/
function wpcf7_file_form_enctype_filter( $enctype ) {
$multipart = (bool) wpcf7_scan_form_tags( array(
'feature' => 'file-uploading',
) );
if ( $multipart ) {
$enctype = 'multipart/form-data';
}
return $enctype;
}
/**
* Converts a MIME type string to an array of corresponding file extensions.
*
* @param string $mime MIME type.
* Wildcard (*) is available for the subtype part.
* @return array Corresponding file extensions.
*/
function wpcf7_convert_mime_to_ext( $mime ) {
static $mime_types = array();
$mime_types = wp_get_mime_types();
$results = array();
if ( preg_match( '%^([a-z]+)/([*]|[a-z0-9.+-]+)$%i', $mime, $matches ) ) {
foreach ( $mime_types as $key => $val ) {
if (
'*' === $matches[2] and str_starts_with( $val, $matches[1] . '/' ) or
$val === $matches[0]
) {
$results = array_merge( $results, explode( '|', $key ) );
}
}
}
$results = array_unique( $results );
$results = array_filter( $results );
$results = array_values( $results );
return $results;
}
/**
* Returns a formatted list of acceptable filetypes.
*
* @param string|array $types Optional. Array of filetypes.
* @param string $format Optional. Pre-defined format designator.
* @return string Formatted list of acceptable filetypes.
*/
function wpcf7_acceptable_filetypes( $types = 'default', $format = 'regex' ) {
if ( 'default' === $types or empty( $types ) ) {
$types = array(
'audio/*',
'video/*',
'image/*',
);
} else {
$types = array_map(
static function ( $type ) {
if ( is_string( $type ) ) {
return preg_split( '/[\s|,]+/', strtolower( $type ) );
}
},
(array) $types
);
$types = wpcf7_array_flatten( $types );
$types = array_filter( array_unique( $types ) );
}
if ( 'attr' === $format or 'attribute' === $format ) {
$types = array_map(
static function ( $type ) {
if ( false === strpos( $type, '/' ) ) {
return sprintf( '.%s', trim( $type, '.' ) );
} elseif ( preg_match( '%^([a-z]+)/[*]$%i', $type, $matches ) ) {
if (
in_array( $matches[1], array( 'audio', 'video', 'image' ), true )
) {
return $type;
} else {
return '';
}
} elseif ( wpcf7_convert_mime_to_ext( $type ) ) {
return $type;
}
},
$types
);
$types = array_filter( $types );
return implode( ',', $types );
} elseif ( 'regex' === $format ) {
$types = array_map(
static function ( $type ) {
if ( false === strpos( $type, '/' ) ) {
return preg_quote( trim( $type, '.' ) );
} elseif ( $type = wpcf7_convert_mime_to_ext( $type ) ) {
return $type;
}
},
$types
);
$types = wpcf7_array_flatten( $types );
$types = array_filter( array_unique( $types ) );
return implode( '|', $types );
}
return '';
}
add_action(
'wpcf7_init',
'wpcf7_init_uploads',
10, 0
);
/**
* Initializes the temporary directory for uploaded files.
*/
function wpcf7_init_uploads() {
$dir = wpcf7_upload_tmp_dir();
if ( ! is_dir( $dir ) or ! wp_is_writable( $dir ) ) {
return;
}
$htaccess_file = path_join( $dir, '.htaccess' );
if ( file_exists( $htaccess_file ) ) {
list( $first_line_comment ) = (array) file(
$htaccess_file,
FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES
);
if ( '# Apache 2.4+' === $first_line_comment ) {
return;
}
}
$filesystem = WPCF7_Filesystem::get_instance();
$htaccess_body = '
# Apache 2.4+
<IfModule authz_core_module>
Require all denied
</IfModule>
# Apache 2.2
<IfModule !authz_core_module>
Deny from all
</IfModule>
';
$filesystem->put_contents( $htaccess_file, ltrim( $htaccess_body ) );
}
/**
* Creates a child directory with a randomly generated name.
*
* @param string $dir The parent directory path.
* @return string The child directory path if created, otherwise the parent.
*/
function wpcf7_maybe_add_random_dir( $dir ) {
do {
$dir_new = path_join( $dir, zeroise( wp_rand(), 10 ) );
} while ( file_exists( $dir_new ) );
if ( wp_mkdir_p( $dir_new ) ) {
return $dir_new;
}
return $dir;
}
/**
* Returns the directory path for uploaded files.
*
* @return string Directory path.
*/
function wpcf7_upload_tmp_dir() {
static $output = '';
if ( $output ) {
return $output;
}
if ( defined( 'WPCF7_UPLOADS_TMP_DIR' ) ) {
$dir = path_join( WP_CONTENT_DIR, WPCF7_UPLOADS_TMP_DIR );
wp_mkdir_p( $dir );
if ( wpcf7_is_file_path_in_content_dir( $dir ) ) {
return $output = $dir;
}
}
$dir = path_join( wpcf7_upload_dir( 'dir' ), 'wpcf7_uploads' );
wp_mkdir_p( $dir );
return $output = $dir;
}
add_action(
'shutdown',
'wpcf7_cleanup_upload_files',
20, 0
);
/**
* Cleans up files in the temporary directory for uploaded files.
*
* @param int $seconds Files older than this are removed. Default 60.
* @param int $max Maximum number of files to be removed in a function call.
* Default 100.
*/
function wpcf7_cleanup_upload_files( $seconds = 60, $max = 100 ) {
$dir = trailingslashit( wpcf7_upload_tmp_dir() );
if (
! is_dir( $dir ) or
! is_readable( $dir ) or
! wp_is_writable( $dir )
) {
return;
}
$seconds = absint( $seconds );
$max = absint( $max );
$count = 0;
if ( $handle = opendir( $dir ) ) {
while ( false !== ( $file = readdir( $handle ) ) ) {
if ( '.' === $file or '..' === $file or '.htaccess' === $file ) {
continue;
}
$mtime = @filemtime( path_join( $dir, $file ) );
if ( $mtime and time() < $mtime + $seconds ) { // less than $seconds old
continue;
}
wpcf7_rmdir_p( path_join( $dir, $file ) );
$count += 1;
if ( $max <= $count ) {
break;
}
}
closedir( $handle );
}
}
add_action(
'wpcf7_admin_warnings',
'wpcf7_file_display_warning_message',
10, 3
);
/**
* Displays warning messages about file-uploading fields.
*/
function wpcf7_file_display_warning_message( $page, $action, $object ) {
if ( $object instanceof WPCF7_ContactForm ) {
$contact_form = $object;
} else {
return;
}
$has_tags = (bool) $contact_form->scan_form_tags( array(
'feature' => 'file-uploading',
) );
if ( ! $has_tags ) {
return;
}
$uploads_dir = wpcf7_upload_tmp_dir();
if ( ! is_dir( $uploads_dir ) or ! wp_is_writable( $uploads_dir ) ) {
wp_admin_notice(
sprintf(
/* translators: %s: the path of the temporary folder */
__( 'This contact form has file uploading fields, but the temporary folder for the files (%s) does not exist or is not writable. You can create the folder or change its permission manually.', 'contact-form-7' ),
$uploads_dir
),
array( 'type' => 'warning' )
);
}
}

View File

@ -0,0 +1,127 @@
<?php
/**
* Class for filesystem operations.
*/
class WPCF7_Filesystem {
/**
* The singleton instance.
*
* @var WPCF7_Filesystem
*/
private static $instance;
/**
* Filesystem object.
*
* @var WP_Filesystem_Base
*/
private $filesystem;
/**
* Retrieves the singleton instance.
*/
public static function get_instance() {
if ( empty( self::$instance ) ) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Constructor.
*/
private function __construct() {
$this->connect();
}
/**
* Connects to the filesystem.
*
* @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass.
*/
private function connect() {
global $wp_filesystem;
if ( $this->filesystem ) {
return false;
}
require_once ABSPATH . 'wp-admin/includes/file.php';
require_once ABSPATH . 'wp-admin/includes/class-wp-filesystem-base.php';
require_once ABSPATH . 'wp-admin/includes/class-wp-filesystem-direct.php';
ob_start();
$credentials = request_filesystem_credentials( '' );
ob_end_clean();
if ( false === $credentials or ! WP_Filesystem( $credentials ) ) {
wp_trigger_error(
__FUNCTION__,
__( 'Could not access filesystem.', 'contact-form-7' )
);
}
if ( $wp_filesystem instanceof WP_Filesystem_Base ) {
$this->filesystem = $wp_filesystem;
} else {
$this->filesystem = new WP_Filesystem_Direct( 1 );
}
if ( ! defined( 'FS_CHMOD_DIR' ) ) {
define( 'FS_CHMOD_DIR', fileperms( ABSPATH ) & 0777 | 0755 );
}
if ( ! defined( 'FS_CHMOD_FILE' ) ) {
define( 'FS_CHMOD_FILE', fileperms( ABSPATH . 'index.php' ) & 0777 | 0644 );
}
}
/**
* Changes filesystem permissions.
*
* @param string $file Path to the file.
* @param int|false $mode Optional. The permissions as octal number.
* @param bool $recursive Optional. If set to true,
* changes file permissions recursively. Default false.
* @return bool True on success, false on failure.
*/
public function chmod( $file, $mode = false, $recursive = false ) {
return $this->filesystem->chmod( $file, $mode, $recursive );
}
/**
* Deletes a file or directory.
*
* @param string $file Path to the file or directory.
* @param bool $recursive Optional. If set to true, deletes
* files and folders recursively. Default false.
* @param string|false $type Type of resource.
* 'f' for file, 'd' for directory. Default false.
* @return bool True on success, false on failure.
*/
public function delete( $file, $recursive = false, $type = false ) {
return $this->filesystem->delete( $file, $recursive, $type );
}
/**
* Writes a string to a file.
*
* @param string $file Path to the file where to write the data.
* @param string $contents The data to write.
* @param int $mode The file permissions as octal number.
* @return bool True on success, false on failure.
*/
public function put_contents( $file, $contents, $mode = false ) {
return $this->filesystem->put_contents( $file, $contents, $mode );
}
}

View File

@ -0,0 +1,618 @@
<?php
/**
* A form-tag.
*
* @link https://contactform7.com/tag-syntax/#form_tag
*/
class WPCF7_FormTag implements ArrayAccess {
public $type;
public $basetype;
public $raw_name = '';
public $name = '';
public $options = array();
public $raw_values = array();
public $values = array();
public $pipes;
public $labels = array();
public $attr = '';
public $content = '';
public function __construct( $tag = array() ) {
if ( is_array( $tag ) or $tag instanceof self ) {
foreach ( $tag as $key => $value ) {
if ( property_exists( __CLASS__, $key ) ) {
$this->{$key} = $value;
}
}
}
}
/**
* Returns true if the type has a trailing asterisk.
*/
public function is_required() {
return str_ends_with( $this->type, '*' );
}
/**
* Returns true if the form-tag has a specified option.
*/
public function has_option( $option_name ) {
$pattern = sprintf( '/^%s(:.+)?$/i', preg_quote( $option_name, '/' ) );
return (bool) preg_grep( $pattern, $this->options );
}
/**
* Retrieves option values with the specified option name.
*
* @param string $option_name Option name.
* @param string $pattern Optional. A regular expression pattern or one of
* the keys of preset patterns. If specified, only options
* whose value part matches this pattern will be returned.
* @param bool $single Optional. If true, only the first matching option
* will be returned. Default false.
* @return string|array|bool The option value or an array of option values.
* False if there is no option matches the pattern.
*/
public function get_option( $option_name, $pattern = '', $single = false ) {
$preset_patterns = array(
'date' => '[0-9]{4}-[0-9]{2}-[0-9]{2}',
'int' => '[0-9]+',
'signed_int' => '[-]?[0-9]+',
'num' => '(?:[0-9]+|(?:[0-9]+)?[.][0-9]+)',
'signed_num' => '[-]?(?:[0-9]+|(?:[0-9]+)?[.][0-9]+)',
'class' => '[-0-9a-zA-Z_]+',
'id' => '[-0-9a-zA-Z_]+',
);
if ( isset( $preset_patterns[$pattern] ) ) {
$pattern = $preset_patterns[$pattern];
}
if ( '' === $pattern ) {
$pattern = '.+';
}
$pattern = sprintf(
'/^%s:%s$/i',
preg_quote( $option_name, '/' ),
$pattern
);
if ( $single ) {
$matches = $this->get_first_match_option( $pattern );
if ( ! $matches ) {
return false;
}
return substr( $matches[0], strlen( $option_name ) + 1 );
} else {
$matches_a = $this->get_all_match_options( $pattern );
if ( ! $matches_a ) {
return false;
}
$results = array();
foreach ( $matches_a as $matches ) {
$results[] = substr( $matches[0], strlen( $option_name ) + 1 );
}
return $results;
}
}
/**
* Retrieves the id option value from the form-tag.
*/
public function get_id_option() {
static $used = array();
$option = $this->get_option( 'id', 'id', true );
if (
! $option or
str_starts_with( $option, 'wpcf7' ) or
in_array( $option, $used, true )
) {
return false;
}
$used[] = $option;
return $option;
}
/**
* Retrieves the class option value from the form-tag.
*
* @param string|array $default_classes Optional. Preset classes as an array
* or a whitespace-separated list. Default empty string.
* @return string|bool A whitespace-separated list of classes.
* False if there is no class to return.
*/
public function get_class_option( $default_classes = '' ) {
if ( is_string( $default_classes ) ) {
$default_classes = explode( ' ', $default_classes );
}
$options = array_merge(
(array) $default_classes,
(array) $this->get_option( 'class' )
);
$options = array_map( 'sanitize_html_class', $options );
$options = array_filter( array_unique( $options ) );
if ( empty( $options ) ) {
return false;
}
return implode( ' ', $options );
}
/**
* Retrieves the autocomplete option value from the form-tag.
*
* @return string|bool A whitespace-separated list of tokens.
* False if there is no token to return.
*/
public function get_autocomplete_option() {
$options = (array) $this->get_option( 'autocomplete', '[-0-9a-zA-Z|]+' );
$options = array_reduce( $options, static function ( $carry, $item ) {
return array_merge( $carry,
array_map( 'strtolower', explode( '|', $item ) )
);
}, array() );
$options = array_filter( $options, static function ( $item ) {
return preg_match( '/^[a-z]+(?:-[0-9a-z]+)*$/', $item );
} );
$options = array_unique( $options );
if ( empty( $options ) ) {
return false;
} elseif ( in_array( 'off', $options, true ) ) {
return 'off';
} elseif ( in_array( 'on', $options, true ) ) {
return 'on';
} else {
return implode( ' ', $options );
}
}
/**
* Retrieves the size option value from the form-tag.
*
* @param string $default_value Optional default value.
* @return string The option value.
*/
public function get_size_option( $default_value = false ) {
$option = $this->get_option( 'size', 'int', true );
if ( $option ) {
return $option;
}
$matches_a = $this->get_all_match_options( '%^([0-9]*)/[0-9]*$%' );
foreach ( $matches_a as $matches ) {
if ( isset( $matches[1] ) and '' !== $matches[1] ) {
return $matches[1];
}
}
return $default_value;
}
/**
* Retrieves the maxlength option value from the form-tag.
*
* @param string $default_value Optional default value.
* @return string The option value.
*/
public function get_maxlength_option( $default_value = false ) {
$option = $this->get_option( 'maxlength', 'int', true );
if ( $option ) {
return $option;
}
$matches_a = $this->get_all_match_options(
'%^(?:[0-9]*x?[0-9]*)?/([0-9]+)$%'
);
foreach ( $matches_a as $matches ) {
if ( isset( $matches[1] ) and '' !== $matches[1] ) {
return $matches[1];
}
}
return $default_value;
}
/**
* Retrieves the minlength option value from the form-tag.
*
* @param string $default_value Optional default value.
* @return string The option value.
*/
public function get_minlength_option( $default_value = false ) {
$option = $this->get_option( 'minlength', 'int', true );
if ( $option ) {
return $option;
} else {
return $default_value;
}
}
/**
* Retrieves the cols option value from the form-tag.
*
* @param string $default_value Optional default value.
* @return string The option value.
*/
public function get_cols_option( $default_value = false ) {
$option = $this->get_option( 'cols', 'int', true );
if ( $option ) {
return $option;
}
$matches_a = $this->get_all_match_options(
'%^([0-9]*)x([0-9]*)(?:/[0-9]+)?$%'
);
foreach ( $matches_a as $matches ) {
if ( isset( $matches[1] ) and '' !== $matches[1] ) {
return $matches[1];
}
}
return $default_value;
}
/**
* Retrieves the rows option value from the form-tag.
*
* @param string $default_value Optional default value.
* @return string The option value.
*/
public function get_rows_option( $default_value = false ) {
$option = $this->get_option( 'rows', 'int', true );
if ( $option ) {
return $option;
}
$matches_a = $this->get_all_match_options(
'%^([0-9]*)x([0-9]*)(?:/[0-9]+)?$%'
);
foreach ( $matches_a as $matches ) {
if ( isset( $matches[2] ) and '' !== $matches[2] ) {
return $matches[2];
}
}
return $default_value;
}
/**
* Retrieves a date-type option value from the form-tag.
*
* @param string $option_name A date-type option name, such as 'min' or 'max'.
* @return string|bool The option value in YYYY-MM-DD format. False if the
* option does not exist or the date value is invalid.
*/
public function get_date_option( $option_name ) {
$option_value = $this->get_option( $option_name, '', true );
if ( empty( $option_value ) ) {
return false;
}
$date = apply_filters( 'wpcf7_form_tag_date_option',
null,
array( $option_name => $option_value )
);
if ( $date ) {
$date_pattern = '/^([0-9]{4})-([0-9]{2})-([0-9]{2})$/';
if (
preg_match( $date_pattern, $date, $matches ) and
checkdate( $matches[2], $matches[3], $matches[1] )
) {
return $date;
}
} else {
$datetime_obj = date_create_immutable(
preg_replace( '/[_]+/', ' ', $option_value ),
wp_timezone()
);
if ( $datetime_obj ) {
return $datetime_obj->format( 'Y-m-d' );
}
}
return false;
}
/**
* Retrieves the default option value from the form-tag.
*
* @param string|array $default_value Optional default value.
* @param string|array $args Optional options for the option value retrieval.
* @return string|array The option value. If the multiple option is enabled,
* an array of option values.
*/
public function get_default_option( $default_value = '', $args = '' ) {
$args = wp_parse_args( $args, array(
'multiple' => false,
'shifted' => false,
) );
$options = (array) $this->get_option( 'default' );
$values = array();
if ( empty( $options ) ) {
return $args['multiple'] ? $values : $default_value;
}
foreach ( $options as $opt ) {
$opt = sanitize_key( $opt );
if ( 'user_' === substr( $opt, 0, 5 ) and is_user_logged_in() ) {
$primary_props = array( 'user_login', 'user_email', 'user_url' );
$opt = in_array( $opt, $primary_props, true ) ? $opt : substr( $opt, 5 );
$user = wp_get_current_user();
$user_prop = $user->get( $opt );
if ( ! empty( $user_prop ) ) {
if ( $args['multiple'] ) {
$values[] = $user_prop;
} else {
return $user_prop;
}
}
} elseif ( 'post_meta' === $opt and in_the_loop() ) {
if ( $args['multiple'] ) {
$values = array_merge( $values,
get_post_meta( get_the_ID(), $this->name )
);
} else {
$val = (string) get_post_meta( get_the_ID(), $this->name, true );
if ( strlen( $val ) ) {
return $val;
}
}
} elseif (
'get' === $opt and
$vals = wpcf7_superglobal_get( $this->name )
) {
$vals = array_map( 'wpcf7_sanitize_query_var', (array) $vals );
if ( $args['multiple'] ) {
$values = array_merge( $values, $vals );
} else {
$val = isset( $vals[0] ) ? (string) $vals[0] : '';
if ( strlen( $val ) ) {
return $val;
}
}
} elseif (
'post' === $opt and
$vals = wpcf7_superglobal_post( $this->name )
) {
$vals = array_map( 'wpcf7_sanitize_query_var', (array) $vals );
if ( $args['multiple'] ) {
$values = array_merge( $values, $vals );
} else {
$val = isset( $vals[0] ) ? (string) $vals[0] : '';
if ( strlen( $val ) ) {
return $val;
}
}
} elseif ( 'shortcode_attr' === $opt ) {
if ( $contact_form = WPCF7_ContactForm::get_current() ) {
$val = $contact_form->shortcode_attr( $this->name );
if ( isset( $val ) and strlen( $val ) ) {
if ( $args['multiple'] ) {
$values[] = $val;
} else {
return $val;
}
}
}
} elseif ( preg_match( '/^[0-9_]+$/', $opt ) ) {
$nums = explode( '_', $opt );
foreach ( $nums as $num ) {
$num = absint( $num );
$num = $args['shifted'] ? $num : $num - 1;
if ( isset( $this->values[$num] ) ) {
if ( $args['multiple'] ) {
$values[] = $this->values[$num];
} else {
return $this->values[$num];
}
}
}
}
}
if ( $args['multiple'] ) {
$values = array_unique( $values );
return $values;
} else {
return $default_value;
}
}
/**
* Retrieves the data option value from the form-tag.
*
* @param string|array $args Optional options for the option value retrieval.
* @return mixed The option value.
*/
public function get_data_option( $args = '' ) {
$options = (array) $this->get_option( 'data' );
return apply_filters( 'wpcf7_form_tag_data_option', null, $options, $args );
}
/**
* Retrieves the limit option value from the form-tag.
*
* @param int $default_value Optional default value. Default 1048576.
* @return int The option value.
*/
public function get_limit_option( $default_value = MB_IN_BYTES ) {
$pattern = '/^limit:([1-9][0-9]*)([kKmM]?[bB])?$/';
$matches = $this->get_first_match_option( $pattern );
if ( $matches ) {
$size = (int) $matches[1];
if ( ! empty( $matches[2] ) ) {
$kbmb = strtolower( $matches[2] );
if ( 'kb' === $kbmb ) {
$size *= KB_IN_BYTES;
} elseif ( 'mb' === $kbmb ) {
$size *= MB_IN_BYTES;
}
}
return $size;
}
return (int) $default_value;
}
/**
* Retrieves the value of the first option matches the given
* regular expression pattern.
*
* @param string $pattern Regular expression pattern.
* @return array|bool Option value as an array of matched strings.
* False if there is no option matches the pattern.
*/
public function get_first_match_option( $pattern ) {
foreach ( (array) $this->options as $option ) {
if ( preg_match( $pattern, $option, $matches ) ) {
return $matches;
}
}
return false;
}
/**
* Retrieves values of options that match the given
* regular expression pattern.
*
* @param string $pattern Regular expression pattern.
* @return array Array of arrays of strings that match the pattern.
*/
public function get_all_match_options( $pattern ) {
$result = array();
foreach ( (array) $this->options as $option ) {
if ( preg_match( $pattern, $option, $matches ) ) {
$result[] = $matches;
}
}
return $result;
}
/**
* Assigns a value to the specified offset.
*
* @link https://www.php.net/manual/en/arrayaccess.offsetset.php
*/
#[ReturnTypeWillChange]
public function offsetSet( $offset, $value ) {
if ( property_exists( __CLASS__, $offset ) ) {
$this->{$offset} = $value;
}
}
/**
* Returns the value at specified offset.
*
* @link https://www.php.net/manual/en/arrayaccess.offsetget.php
*/
#[ReturnTypeWillChange]
public function offsetGet( $offset ) {
if ( property_exists( __CLASS__, $offset ) ) {
return $this->{$offset};
}
return null;
}
/**
* Returns true if the specified offset exists.
*
* @link https://www.php.net/manual/en/arrayaccess.offsetexists.php
*/
#[ReturnTypeWillChange]
public function offsetExists( $offset ) {
return property_exists( __CLASS__, $offset );
}
/**
* Unsets an offset.
*
* @link https://www.php.net/manual/en/arrayaccess.offsetunset.php
*/
#[ReturnTypeWillChange]
public function offsetUnset( $offset ) {
}
}

View File

@ -0,0 +1,615 @@
<?php
/**
* Wrapper function of WPCF7_FormTagsManager::add().
*/
function wpcf7_add_form_tag( $tag_types, $callback, $features = '' ) {
$manager = WPCF7_FormTagsManager::get_instance();
return $manager->add( $tag_types, $callback, $features );
}
/**
* Wrapper function of WPCF7_FormTagsManager::remove().
*/
function wpcf7_remove_form_tag( $tag_type ) {
$manager = WPCF7_FormTagsManager::get_instance();
return $manager->remove( $tag_type );
}
/**
* Wrapper function of WPCF7_FormTagsManager::replace_all().
*/
function wpcf7_replace_all_form_tags( $content ) {
$manager = WPCF7_FormTagsManager::get_instance();
return $manager->replace_all( $content );
}
/**
* Wrapper function of WPCF7_ContactForm::scan_form_tags().
*/
function wpcf7_scan_form_tags( $cond = null ) {
$contact_form = WPCF7_ContactForm::get_current();
if ( $contact_form ) {
return $contact_form->scan_form_tags( $cond );
}
return array();
}
/**
* Wrapper function of WPCF7_FormTagsManager::tag_type_supports().
*/
function wpcf7_form_tag_supports( $tag_type, $feature ) {
$manager = WPCF7_FormTagsManager::get_instance();
return $manager->tag_type_supports( $tag_type, $feature );
}
/**
* The singleton instance of this class manages the collection of form-tags.
*/
class WPCF7_FormTagsManager {
private static $instance;
private $tag_types = array();
private $scanned_tags = null; // Tags scanned at the last time of scan()
private $placeholders = array();
private function __construct() {}
/**
* Returns the singleton instance.
*
* @return WPCF7_FormTagsManager The singleton manager.
*/
public static function get_instance() {
if ( empty( self::$instance ) ) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Returns scanned form-tags.
*
* @return array Array of WPCF7_FormTag objects.
*/
public function get_scanned_tags() {
return $this->scanned_tags;
}
/**
* Registers form-tag types to the manager.
*
* @param string|array $tag_types The name of the form-tag type or
* an array of the names.
* @param callable $callback The callback to generates a form control HTML
* for a form-tag in this type.
* @param string|array $features Optional. Features a form-tag
* in this type supports.
*/
public function add( $tag_types, $callback, $features = '' ) {
if ( ! is_callable( $callback ) ) {
return;
}
if ( true === $features ) { // for back-compat
$features = array( 'name-attr' => true );
}
$features = wp_parse_args( $features, array() );
$tag_types = array_filter( array_unique( (array) $tag_types ) );
foreach ( $tag_types as $tag_type ) {
$tag_type = $this->sanitize_tag_type( $tag_type );
if ( ! $this->tag_type_exists( $tag_type ) ) {
$this->tag_types[$tag_type] = array(
'function' => $callback,
'features' => $features,
);
}
}
}
/**
* Returns true if the given tag type exists.
*/
public function tag_type_exists( $tag_type ) {
return isset( $this->tag_types[$tag_type] );
}
/**
* Returns true if the tag type supports the features.
*
* @param string $tag_type The name of the form-tag type.
* @param array|string $features The feature to check or an array of features.
* @return bool True if the form-tag type supports at least one of
* the given features, false otherwise.
*/
public function tag_type_supports( $tag_type, $features ) {
$features = array_filter( (array) $features );
if ( isset( $this->tag_types[$tag_type]['features'] ) ) {
return (bool) array_intersect(
array_keys( array_filter( $this->tag_types[$tag_type]['features'] ) ),
$features
);
}
return false;
}
/**
* Returns form-tag types that support the given features.
*
* @param array|string $features Optional. The feature to check or
* an array of features. Default empty array.
* @param bool $invert Optional. If this value is true, returns form-tag
* types that do not support the given features. Default false.
* @return array An array of form-tag types. If the $features param is empty,
* returns all form-tag types that have been registered.
*/
public function collect_tag_types( $features = array(), $invert = false ) {
$tag_types = array_keys( $this->tag_types );
if ( empty( $features ) ) {
return $tag_types;
}
$output = array();
foreach ( $tag_types as $tag_type ) {
if (
! $invert and $this->tag_type_supports( $tag_type, $features ) or
$invert and ! $this->tag_type_supports( $tag_type, $features )
) {
$output[] = $tag_type;
}
}
return $output;
}
/**
* Sanitizes the form-tag type name.
*/
private function sanitize_tag_type( $tag_type ) {
$tag_type = preg_replace( '/[^a-zA-Z0-9_*]+/', '_', $tag_type );
$tag_type = rtrim( $tag_type, '_' );
$tag_type = strtolower( $tag_type );
return $tag_type;
}
/**
* Deregisters the form-tag type.
*/
public function remove( $tag_type ) {
unset( $this->tag_types[$tag_type] );
}
/**
* Normalizes the text content that includes form-tags.
*/
public function normalize( $content ) {
if ( empty( $this->tag_types ) ) {
return $content;
}
$content = preg_replace_callback(
'/' . $this->tag_regex() . '/su',
array( $this, 'normalize_callback' ),
$content
);
return $content;
}
/**
* The callback function used within normalize().
*/
private function normalize_callback( $matches ) {
// allow [[foo]] syntax for escaping a tag
if ( '[' === $matches[1] and ']' === $matches[6] ) {
return $matches[0];
}
$tag = $matches[2];
$attr = trim( preg_replace( '/[\r\n\t ]+/', ' ', $matches[3] ) );
$attr = strtr( $attr, array( '<' => '&lt;', '>' => '&gt;' ) );
$content = trim( $matches[5] );
$content = str_replace( "\n", '<WPPreserveNewline />', $content );
$result = $matches[1] . '[' . $tag
. ( $attr ? ' ' . $attr : '' )
. ( $matches[4] ? ' ' . $matches[4] : '' )
. ']'
. ( $content ? $content . '[/' . $tag . ']' : '' )
. $matches[6];
return $result;
}
/**
* Replace all form-tags in the given text with placeholders.
*/
public function replace_with_placeholders( $content ) {
if ( empty( $this->tag_types ) ) {
return $content;
}
$this->placeholders = array();
$callback = function ( $matches ) {
// Allow [[foo]] syntax for escaping a tag.
if ( '[' === $matches[1] and ']' === $matches[6] ) {
return $matches[0];
}
$tag = $matches[0];
$tag_type = $matches[2];
$block_or_hidden = $this->tag_type_supports(
$tag_type,
array( 'display-block', 'display-hidden' )
);
if ( $block_or_hidden ) {
$placeholder_tag_name = WPCF7_HTMLFormatter::placeholder_block;
} else {
$placeholder_tag_name = WPCF7_HTMLFormatter::placeholder_inline;
}
$placeholder = sprintf(
'<%1$s id="%2$s" />',
$placeholder_tag_name,
hash( 'sha256', $tag )
);
list( $placeholder ) =
WPCF7_HTMLFormatter::normalize_start_tag( $placeholder );
$this->placeholders[$placeholder] = $tag;
return $placeholder;
};
return preg_replace_callback(
'/' . $this->tag_regex() . '/su',
$callback,
$content
);
}
/**
* Replace placeholders in the given text with original form-tags.
*/
public function restore_from_placeholders( $content ) {
return str_replace(
array_keys( $this->placeholders ),
array_values( $this->placeholders ),
$content
);
}
/**
* Replaces all form-tags in the text content.
*
* @param string $content The text content including form-tags.
* @return string The result of replacements.
*/
public function replace_all( $content ) {
return $this->scan( $content, true );
}
/**
* Scans form-tags in the text content.
*
* @param string $content The text content including form-tags.
* @param bool $replace Optional. Whether scanned form-tags will be
* replaced. Default false.
* @return array|string An array of scanned form-tags if $replace is false.
* Otherwise text that scanned form-tags are replaced.
*/
public function scan( $content, $replace = false ) {
$this->scanned_tags = array();
if ( empty( $this->tag_types ) ) {
if ( $replace ) {
return $content;
} else {
return $this->scanned_tags;
}
}
if ( $replace ) {
$content = preg_replace_callback(
'/' . $this->tag_regex() . '/su',
array( $this, 'replace_callback' ),
$content
);
return $content;
} else {
preg_replace_callback(
'/' . $this->tag_regex() . '/su',
array( $this, 'scan_callback' ),
$content
);
return $this->scanned_tags;
}
}
/**
* Filters form-tags based on a condition array argument.
*
* @param array|string $input The original form-tags collection.
* If it is a string, scans form-tags from it.
* @param array $cond The conditions that filtering will be based on.
* @return array The filtered form-tags collection.
*/
public function filter( $input, $cond ) {
if ( is_array( $input ) ) {
$tags = $input;
} elseif ( is_string( $input ) ) {
$tags = $this->scan( $input );
} else {
$tags = $this->scanned_tags;
}
$cond = wp_parse_args( $cond, array(
'type' => array(),
'basetype' => array(),
'name' => array(),
'feature' => array(),
) );
$cond = array_map( static function ( $c ) {
return array_filter( array_map( 'trim', (array) $c ) );
}, $cond );
$tags = array_filter(
(array) $tags,
function ( $tag ) use ( $cond ) {
$tag = new WPCF7_FormTag( $tag );
if (
$cond['type'] and
! in_array( $tag->type, $cond['type'], true )
) {
return false;
}
if (
$cond['basetype'] and
! in_array( $tag->basetype, $cond['basetype'], true )
) {
return false;
}
if (
$cond['name'] and
! in_array( $tag->name, $cond['name'], true )
) {
return false;
}
foreach ( $cond['feature'] as $feature ) {
if ( str_starts_with( $feature, '!' ) ) { // Negation
$feature = trim( substr( $feature, 1 ) );
if ( $this->tag_type_supports( $tag->type, $feature ) ) {
return false;
}
} else {
if ( ! $this->tag_type_supports( $tag->type, $feature ) ) {
return false;
}
}
}
return true;
}
);
return array_values( $tags );
}
/**
* Returns the regular expression for a form-tag.
*/
private function tag_regex() {
$tag_types = implode( '|',
array_map( 'preg_quote', array_keys( $this->tag_types ) )
);
$whitespaces = wpcf7_get_unicode_whitespaces();
return '(\[?)'
. '\[(' . $tag_types . ')'
. '(?:[' . $whitespaces . ']+(.*?))?'
. '(?:[' . $whitespaces . ']+(\/))?\]'
. '(?:([^[]*?)\[\/\2\])?'
. '(\]?)';
}
/**
* The callback function for the form-tag replacement.
*/
private function replace_callback( $matches ) {
return $this->scan_callback( $matches, true );
}
/**
* The callback function for the form-tag scanning.
*/
private function scan_callback( $matches, $replace = false ) {
// allow [[foo]] syntax for escaping a tag
if ( '[' === $matches[1] and ']' === $matches[6] ) {
return substr( $matches[0], 1, -1 );
}
$tag_type = $matches[2];
$tag_basetype = trim( $tag_type, '*' );
$attr = $this->parse_atts( $matches[3] );
$scanned_tag = array(
'type' => $tag_type,
'basetype' => $tag_basetype,
'raw_name' => '',
'name' => '',
'options' => array(),
'raw_values' => array(),
'values' => array(),
'pipes' => null,
'labels' => array(),
'attr' => '',
'content' => '',
);
if ( $this->tag_type_supports( $tag_type, 'singular' ) ) {
$tags_in_same_basetype = $this->filter(
$this->scanned_tags,
array( 'basetype' => $tag_basetype )
);
if ( $tags_in_same_basetype ) {
// Another tag in the same base type already exists. Ignore this one.
return $matches[0];
}
}
if ( $this->tag_type_supports( $tag_type, 'name-attr' ) ) {
if ( ! is_array( $attr ) ) {
return $matches[0]; // Invalid form-tag.
}
$scanned_tag['raw_name'] = (string) array_shift( $attr['options'] );
if ( ! wpcf7_is_name( $scanned_tag['raw_name'] ) ) {
return $matches[0]; // Invalid name is used. Ignore this tag.
}
$scanned_tag['name'] = strtr( $scanned_tag['raw_name'], '.', '_' );
}
if ( is_array( $attr ) ) {
$scanned_tag['options'] = (array) $attr['options'];
$scanned_tag['raw_values'] = (array) $attr['values'];
if ( WPCF7_USE_PIPE ) {
$pipes = new WPCF7_Pipes( $scanned_tag['raw_values'] );
$scanned_tag['values'] = $pipes->collect_befores();
$scanned_tag['pipes'] = $pipes;
} else {
$scanned_tag['values'] = $scanned_tag['raw_values'];
}
$scanned_tag['labels'] = $scanned_tag['values'];
} else {
$scanned_tag['attr'] = $attr;
}
$scanned_tag['values'] = array_map( 'trim', $scanned_tag['values'] );
$scanned_tag['labels'] = array_map( 'trim', $scanned_tag['labels'] );
$content = trim( $matches[5] );
$content = preg_replace( "/<br[\r\n\t ]*\/?>$/m", '', $content );
$scanned_tag['content'] = $content;
$scanned_tag = apply_filters( 'wpcf7_form_tag', $scanned_tag, $replace );
$scanned_tag = new WPCF7_FormTag( $scanned_tag );
$this->scanned_tags[] = $scanned_tag;
if ( $replace ) {
$callback = $this->tag_types[$tag_type]['function'];
return $matches[1] . call_user_func( $callback, $scanned_tag ) . $matches[6];
} else {
return $matches[0];
}
}
/**
* Parses the attributes of a form-tag to extract the name,
* options, and values.
*
* @param string $text Attributes of a form-tag.
* @return array|string An associative array of the options and values
* if the input is in the correct syntax,
* otherwise the input text itself.
*/
private function parse_atts( $text ) {
$atts = array(
'options' => array(),
'values' => array(),
);
$whitespaces = wpcf7_get_unicode_whitespaces();
$text = preg_replace( '/[\x{00a0}\x{200b}]+/u', ' ', $text );
$text = wpcf7_strip_whitespaces( $text );
$pattern = '%^([-+*=0-9a-zA-Z:.!?#$&@_/|\%' . $whitespaces . ']*?)'
. '((?:'
. '[' . $whitespaces . ']*"[^"]*"'
. '|'
. '[' . $whitespaces . ']*\'[^\']*\''
. ')*)$%u';
if ( preg_match( $pattern, $text, $matches ) ) {
if ( ! empty( $matches[1] ) ) {
$atts['options'] = preg_split(
sprintf( '/[%s]+/u', $whitespaces ),
wpcf7_strip_whitespaces( $matches[1] )
);
}
if ( ! empty( $matches[2] ) ) {
preg_match_all( '/"[^"]*"|\'[^\']*\'/', $matches[2], $matched_values );
$atts['values'] = wpcf7_strip_quote_deep( $matched_values[0] );
}
} else {
$atts = $text;
}
return $atts;
}
}

View File

@ -0,0 +1,653 @@
<?php
/**
* Replaces double line breaks with paragraph elements.
*
* @param string $input The text which has to be formatted.
* @param bool $br Optional. If set, this will convert all remaining
* line breaks after paragraphing. Default true.
* @return string Text which has been converted into correct paragraph tags.
*/
function wpcf7_autop( $input, $br = true ) {
$placeholders = array();
// Replace non-HTML embedded elements with placeholders.
$input = preg_replace_callback(
'/<(math|svg).*?<\/\1>/is',
static function ( $matches ) use ( &$placeholders ) {
$placeholder = sprintf(
'<%1$s id="%2$s" />',
WPCF7_HTMLFormatter::placeholder_inline,
hash( 'sha256', $matches[0] )
);
list( $placeholder ) =
WPCF7_HTMLFormatter::normalize_start_tag( $placeholder );
$placeholders[$placeholder] = $matches[0];
return $placeholder;
},
$input
);
$formatter = new WPCF7_HTMLFormatter( array(
'auto_br' => $br,
'allowed_html' => null,
) );
$chunks = $formatter->separate_into_chunks( $input );
$output = $formatter->format( $chunks );
// Restore from placeholders.
$output = str_replace(
array_keys( $placeholders ),
array_values( $placeholders ),
$output
);
return $output;
}
/**
* Newline preservation help function for wpcf7_autop().
*
* @deprecated 5.7 Unnecessary to use any more.
*
* @param array $matches preg_replace_callback() matches array.
* @return string Text including newline placeholders.
*/
function wpcf7_autop_preserve_newline_callback( $matches ) {
return str_replace( "\n", '<WPPreserveNewline />', $matches[0] );
}
/**
* Sanitizes the query variables.
*
* @param string $text Query variable.
* @return string Text sanitized.
*/
function wpcf7_sanitize_query_var( $text ) {
$text = wp_unslash( $text );
$text = wp_check_invalid_utf8( $text );
if ( false !== strpos( $text, '<' ) ) {
$text = wp_pre_kses_less_than( $text );
$text = wp_strip_all_tags( $text );
}
$text = preg_replace( '/%[a-f0-9]{2}/i', '', $text );
$text = preg_replace( '/ +/', ' ', $text );
$text = trim( $text, ' ' );
return $text;
}
/**
* Strips quote characters surrounding the input.
*
* @param string $text Input text.
* @return string Processed output.
*/
function wpcf7_strip_quote( $text ) {
$text = wpcf7_strip_whitespaces( $text );
if ( preg_match( '/^"(.*)"$/s', $text, $matches ) ) {
$text = $matches[1];
} elseif ( preg_match( "/^'(.*)'$/s", $text, $matches ) ) {
$text = $matches[1];
}
return $text;
}
/**
* Navigates through an array, object, or scalar, and
* strips quote characters surrounding the each value.
*
* @param mixed $input The array or string to be processed.
* @return mixed Processed value.
*/
function wpcf7_strip_quote_deep( $input ) {
if ( is_string( $input ) ) {
return wpcf7_strip_quote( $input );
}
if ( is_array( $input ) ) {
$result = array();
foreach ( $input as $key => $text ) {
$result[$key] = wpcf7_strip_quote_deep( $text );
}
return $result;
}
}
/**
* Normalizes newline characters.
*
* @param string $text Input text.
* @param string $to Optional. The newline character that is used in the output.
* @return string Normalized text.
*/
function wpcf7_normalize_newline( $text, $to = "\n" ) {
if ( ! is_string( $text ) ) {
return $text;
}
$nls = array( "\r\n", "\r", "\n" );
if ( ! in_array( $to, $nls, true ) ) {
return $text;
}
return str_replace( $nls, $to, $text );
}
/**
* Navigates through an array, object, or scalar, and
* normalizes newline characters in the each value.
*
* @param mixed $input The array or string to be processed.
* @param string $to Optional. The newline character that is used in the output.
* @return mixed Processed value.
*/
function wpcf7_normalize_newline_deep( $input, $to = "\n" ) {
if ( is_array( $input ) ) {
$result = array();
foreach ( $input as $key => $text ) {
$result[$key] = wpcf7_normalize_newline_deep( $text, $to );
}
return $result;
}
return wpcf7_normalize_newline( $input, $to );
}
/**
* Strips newline characters.
*
* @param string $text Input text.
* @return string Processed one-line text.
*/
function wpcf7_strip_newline( $text ) {
$text = (string) $text;
$text = str_replace( array( "\r", "\n" ), '', $text );
return wpcf7_strip_whitespaces( $text );
}
/**
* Canonicalizes text.
*
* @param string $text Input text.
* @param string|array|object $options Options.
* @return string Canonicalized text.
*/
function wpcf7_canonicalize( $text, $options = '' ) {
// for back-compat
if (
is_string( $options ) and
'' !== $options and
! str_contains( $options, '=' )
) {
$options = array(
'strto' => $options,
);
}
$options = wp_parse_args( $options, array(
'strto' => 'lower',
'strip_separators' => false,
) );
static $charset = null;
if ( ! isset( $charset ) ) {
$charset = get_option( 'blog_charset' );
$is_utf8 = in_array(
$charset,
array( 'utf8', 'utf-8', 'UTF8', 'UTF-8' ),
true
);
if ( $is_utf8 ) {
$charset = 'UTF-8';
}
}
$text = html_entity_decode( $text, ENT_QUOTES | ENT_HTML5, $charset );
if ( function_exists( 'mb_convert_kana' ) ) {
$text = mb_convert_kana( $text, 'asKV', $charset );
}
if ( $options['strip_separators'] ) {
$text = preg_replace( '/[\r\n\t ]+/', '', $text );
} else {
$text = preg_replace( '/[\r\n\t ]+/', ' ', $text );
}
if ( 'lower' === $options['strto'] ) {
if ( function_exists( 'mb_strtolower' ) ) {
$text = mb_strtolower( $text, $charset );
} else {
$text = strtolower( $text );
}
} elseif ( 'upper' === $options['strto'] ) {
if ( function_exists( 'mb_strtoupper' ) ) {
$text = mb_strtoupper( $text, $charset );
} else {
$text = strtoupper( $text );
}
}
return wpcf7_strip_whitespaces( $text );
}
/**
* Returns a canonical keyword usable for a name or an ID purposes.
*/
function wpcf7_canonicalize_name( $text ) {
return preg_replace( '/[^0-9a-z]+/i', '-', $text );
}
/**
* Sanitizes Contact Form 7's form unit-tag.
*
* @param string $tag Unit-tag.
* @return string Sanitized unit-tag.
*/
function wpcf7_sanitize_unit_tag( $tag ) {
$tag = preg_replace( '/[^A-Za-z0-9_-]/', '', (string) $tag );
return $tag;
}
/**
* Converts a file name to one that is not executable as a script.
*
* @param string $filename File name.
* @return string Converted file name.
*/
function wpcf7_antiscript_file_name( $filename ) {
$filename = wp_basename( $filename );
// Apply part of protection logic from sanitize_file_name().
$filename = str_replace(
array(
'?', '[', ']', '/', '\\', '=', '<', '>', ':', ';', ',', "'", '"',
'&', '$', '#', '*', '(', ')', '|', '~', '`', '!', '{', '}',
'%', '+', '', '«', '»', '”', '“', chr( 0 )
),
'',
$filename
);
$filename = preg_replace( '/[\r\n\t -]+/', '-', $filename );
$filename = preg_replace( '/[\pC\pZ]+/iu', '', $filename );
$parts = explode( '.', $filename );
if ( count( $parts ) < 2 ) {
return $filename;
}
$script_pattern = '/^(php|phtml|pl|py|rb|cgi|asp|aspx)\d?$/i';
$filename = array_shift( $parts );
$extension = array_pop( $parts );
foreach ( $parts as $part ) {
if ( preg_match( $script_pattern, $part ) ) {
$filename .= '.' . $part . '_';
} else {
$filename .= '.' . $part;
}
}
if ( preg_match( $script_pattern, $extension ) ) {
$filename .= '.' . $extension . '_.txt';
} else {
$filename .= '.' . $extension;
}
return $filename;
}
/**
* Masks a password with asterisks (*).
*
* @param int $right Length of right-hand unmasked text. Default 0.
* @param int $left Length of left-hand unmasked text. Default 0.
* @return string Text of masked password.
*/
function wpcf7_mask_password( $text, $right = 0, $left = 0 ) {
$length = strlen( $text );
$right = absint( $right );
$left = absint( $left );
if ( $length < $right + $left ) {
$right = $left = 0;
}
if ( $length <= 48 ) {
$masked = str_repeat( '*', $length - ( $right + $left ) );
} elseif ( $right + $left < 48 ) {
$masked = str_repeat( '*', 48 - ( $right + $left ) );
} else {
$masked = '****';
}
$left_unmasked = $left ? substr( $text, 0, $left ) : '';
$right_unmasked = $right ? substr( $text, -1 * $right ) : '';
$text = $left_unmasked . $masked . $right_unmasked;
return $text;
}
/**
* Returns an array of allowed HTML tags and attributes for a given context.
*
* @param string $context Context used to decide allowed tags and attributes.
* @return array Array of allowed HTML tags and their allowed attributes.
*/
function wpcf7_kses_allowed_html( $context = 'form' ) {
static $allowed_tags = array();
if ( isset( $allowed_tags[$context] ) ) {
return apply_filters(
'wpcf7_kses_allowed_html',
$allowed_tags[$context],
$context
);
}
$allowed_tags[$context] = wp_kses_allowed_html( 'post' );
if ( 'form' === $context ) {
$additional_tags_for_form = array(
'button' => array(
'disabled' => true,
'name' => true,
'type' => true,
'value' => true,
),
'datalist' => array(),
'fieldset' => array(
'disabled' => true,
'name' => true,
),
'input' => array(
'accept' => true,
'alt' => true,
'autocomplete' => true,
'capture' => true,
'checked' => true,
'disabled' => true,
'list' => true,
'max' => true,
'maxlength' => true,
'min' => true,
'minlength' => true,
'multiple' => true,
'name' => true,
'pattern' => true,
'placeholder' => true,
'readonly' => true,
'required' => true,
'size' => true,
'step' => true,
'type' => true,
'value' => true,
),
'label' => array(
'for' => true,
),
'legend' => array(),
'meter' => array(
'value' => true,
'min' => true,
'max' => true,
'low' => true,
'high' => true,
'optimum' => true,
),
'optgroup' => array(
'disabled' => true,
'label' => true,
),
'option' => array(
'disabled' => true,
'label' => true,
'selected' => true,
'value' => true,
),
'output' => array(
'for' => true,
'name' => true,
),
'progress' => array(
'max' => true,
'value' => true,
),
'select' => array(
'autocomplete' => true,
'disabled' => true,
'multiple' => true,
'name' => true,
'required' => true,
'size' => true,
),
'textarea' => array(
'autocomplete' => true,
'cols' => true,
'disabled' => true,
'maxlength' => true,
'minlength' => true,
'name' => true,
'placeholder' => true,
'readonly' => true,
'required' => true,
'rows' => true,
'wrap' => true,
),
);
$allowed_tags[$context] = array_merge(
$allowed_tags[$context],
$additional_tags_for_form
);
$allowed_tags[$context] = array_map(
static function ( $elm ) {
$global_attributes = array(
'aria-atomic' => true,
'aria-checked' => true,
'aria-controls' => true,
'aria-current' => true,
'aria-describedby' => true,
'aria-details' => true,
'aria-disabled' => true,
'aria-expanded' => true,
'aria-hidden' => true,
'aria-invalid' => true,
'aria-label' => true,
'aria-labelledby' => true,
'aria-live' => true,
'aria-relevant' => true,
'aria-required' => true,
'aria-selected' => true,
'class' => true,
'data-*' => true,
'dir' => true,
'hidden' => true,
'id' => true,
'inputmode' => true,
'lang' => true,
'role' => true,
'spellcheck' => true,
'style' => true,
'tabindex' => true,
'title' => true,
'xml:lang' => true,
);
return array_merge( $global_attributes, (array) $elm );
},
$allowed_tags[$context]
);
}
return apply_filters(
'wpcf7_kses_allowed_html',
$allowed_tags[$context],
$context
);
}
/**
* Sanitizes content for allowed HTML tags for the specified context.
*
* @param string $input Content to filter.
* @param string $context Context used to decide allowed tags and attributes.
* @return string Filtered text with allowed HTML tags and attributes intact.
*/
function wpcf7_kses( $input, $context = 'form' ) {
$output = wp_kses(
$input,
wpcf7_kses_allowed_html( $context )
);
return $output;
}
/**
* Returns a formatted string of HTML attributes.
*
* @param array $atts Associative array of attribute name and value pairs.
* @return string Formatted HTML attributes.
*/
function wpcf7_format_atts( $atts ) {
$atts_filtered = array();
foreach ( $atts as $name => $value ) {
$name = strtolower( trim( $name ) );
if ( ! preg_match( '/^[a-z_:][a-z_:.0-9-]*$/', $name ) ) {
continue;
}
static $boolean_attributes = array(
'checked',
'disabled',
'inert',
'multiple',
'readonly',
'required',
'selected',
);
if ( in_array( $name, $boolean_attributes, true ) and '' === $value ) {
$value = false;
}
if ( is_numeric( $value ) ) {
$value = (string) $value;
}
if ( null === $value or false === $value ) {
unset( $atts_filtered[$name] );
} elseif ( true === $value ) {
$atts_filtered[$name] = $name; // boolean attribute
} elseif ( is_string( $value ) ) {
$atts_filtered[$name] = trim( $value );
}
}
$output = '';
foreach ( $atts_filtered as $name => $value ) {
$output .= sprintf( ' %1$s="%2$s"', $name, esc_attr( $value ) );
}
return trim( $output );
}
/**
* Returns the regular expression pattern that represents
* whitespace characters Unicode defines.
*
* @link https://www.unicode.org/Public/UCD/latest/ucd/PropList.txt
*
* @return string Regular expression pattern.
*/
function wpcf7_get_unicode_whitespaces() {
return '\x09-\x0D\x20\x85\xA0\x{1680}\x{2000}-\x{200A}\x{2028}\x{2029}\x{202F}\x{205F}\x{3000}';
}
/**
* Strips surrounding whitespaces.
*
* @link https://contactform7.com/2024/07/13/consistent-handling-policy-of-surrounding-whitespaces/
*
* @param string|array $input Input text.
* @param string $side The side from which whitespaces are stripped.
* 'start', 'end', or 'both' (default).
* @return string|array Output text.
*/
function wpcf7_strip_whitespaces( $input, $side = 'both' ) {
if ( is_array( $input ) ) {
return array_map(
static function ( $i ) use ( $side ) {
return wpcf7_strip_whitespaces( $i, $side );
},
$input
);
}
// https://tc39.es/ecma262/multipage/ecmascript-language-lexical-grammar.html
$whitespaces = wpcf7_get_unicode_whitespaces() . '\x{FEFF}';
if ( 'end' !== $side ) {
// Strip leading whitespaces
$input = preg_replace(
sprintf( '/^[%s]+/u', $whitespaces ),
'',
$input
);
}
if ( 'start' !== $side ) {
// Strip trailing whitespaces
$input = preg_replace(
sprintf( '/[%s]+$/u', $whitespaces ),
'',
$input
);
}
return $input;
}

View File

@ -0,0 +1,749 @@
<?php
/**
* Returns path to a plugin file.
*
* @param string $path File path relative to the plugin root directory.
* @return string Absolute file path.
*/
function wpcf7_plugin_path( $path = '' ) {
return path_join( WPCF7_PLUGIN_DIR, trim( $path, '/' ) );
}
/**
* Returns the URL to a plugin file.
*
* @param string $path File path relative to the plugin root directory.
* @return string URL.
*/
function wpcf7_plugin_url( $path = '' ) {
$url = plugins_url( $path, WPCF7_PLUGIN );
if ( is_ssl() and 'http:' === substr( $url, 0, 5 ) ) {
$url = 'https:' . substr( $url, 5 );
}
return $url;
}
/**
* Include a file under WPCF7_PLUGIN_MODULES_DIR.
*
* @param string $path File path relative to the module dir.
* @return bool True on success, false on failure.
*/
function wpcf7_include_module_file( $path ) {
$dir = WPCF7_PLUGIN_MODULES_DIR;
if ( empty( $dir ) or ! is_dir( $dir ) ) {
return false;
}
$path = path_join( $dir, ltrim( $path, '/' ) );
if ( file_exists( $path ) ) {
include_once $path;
return true;
}
return false;
}
/**
* Retrieves uploads directory information.
*
* @param string|bool $type Optional. Type of output. Default false.
* @return array|string Information about the upload directory.
*/
function wpcf7_upload_dir( $type = false ) {
$uploads = wp_get_upload_dir();
$uploads = apply_filters( 'wpcf7_upload_dir', array(
'dir' => $uploads['basedir'],
'url' => $uploads['baseurl'],
) );
if ( 'dir' === $type ) {
return $uploads['dir'];
} if ( 'url' === $type ) {
return $uploads['url'];
}
return $uploads;
}
/**
* Verifies that a correct security nonce was used with time limit.
*
* @param string $nonce Nonce value that was used for verification.
* @param string $action Optional. Context to what is taking place.
* Default 'wp_rest'.
* @return int|bool 1 if the nonce is generated between 0-12 hours ago,
* 2 if the nonce is generated between 12-24 hours ago.
* False if the nonce is invalid.
*/
function wpcf7_verify_nonce( $nonce, $action = 'wp_rest' ) {
return wp_verify_nonce( $nonce, $action );
}
/**
* Creates a cryptographic token tied to a specific action, user, user session,
* and window of time.
*
* @param string $action Optional. Context to what is taking place.
* Default 'wp_rest'.
* @return string The token.
*/
function wpcf7_create_nonce( $action = 'wp_rest' ) {
return wp_create_nonce( $action );
}
/**
* Converts multi-dimensional array to a flat array.
*
* @param mixed $input Array or item of array.
* @return array Flatten array.
*/
function wpcf7_array_flatten( $input ) {
if ( ! is_array( $input ) ) {
return array( $input );
}
$output = array();
foreach ( $input as $value ) {
$output = array_merge( $output, wpcf7_array_flatten( $value ) );
}
return $output;
}
/**
* Excludes unset or blank text values from the given array.
*
* @param array $input The array.
* @return array Array without blank text values.
*/
function wpcf7_exclude_blank( $input ) {
$output = array_filter( $input,
static function ( $i ) {
return isset( $i ) && '' !== $i;
}
);
return array_values( $output );
}
/**
* Creates a comma-separated list from a multi-dimensional array.
*
* @param mixed $input Array or item of array.
* @param string|array $options Optional. Output options.
* @return string Comma-separated list.
*/
function wpcf7_flat_join( $input, $options = '' ) {
$options = wp_parse_args( $options, array(
'separator' => ', ',
) );
$input = wpcf7_array_flatten( $input );
$output = array();
foreach ( $input as $value ) {
if ( is_scalar( $value ) ) {
$output[] = trim( (string) $value );
}
}
return implode( $options['separator'], $output );
}
/**
* Returns true if HTML5 is supported.
*/
function wpcf7_support_html5() {
return (bool) wpcf7_apply_filters_deprecated(
'wpcf7_support_html5',
array( true ),
'5.6',
''
);
}
/**
* Returns true if HTML5 fallback is active.
*/
function wpcf7_support_html5_fallback() {
return (bool) apply_filters( 'wpcf7_support_html5_fallback', false );
}
/**
* Returns true if the Really Simple CAPTCHA plugin is used for contact forms.
*/
function wpcf7_use_really_simple_captcha() {
return apply_filters( 'wpcf7_use_really_simple_captcha',
WPCF7_USE_REALLY_SIMPLE_CAPTCHA
);
}
/**
* Returns true if config validation is active.
*/
function wpcf7_validate_configuration() {
return apply_filters( 'wpcf7_validate_configuration',
WPCF7_VALIDATE_CONFIGURATION
);
}
/**
* Returns true if wpcf7_autop() is applied.
*/
function wpcf7_autop_or_not( $options = '' ) {
$options = wp_parse_args( $options, array(
'for' => 'form',
) );
return (bool) apply_filters( 'wpcf7_autop_or_not', WPCF7_AUTOP, $options );
}
/**
* Returns true if JavaScript for this plugin is loaded.
*/
function wpcf7_load_js() {
return apply_filters( 'wpcf7_load_js', WPCF7_LOAD_JS );
}
/**
* Returns true if CSS for this plugin is loaded.
*/
function wpcf7_load_css() {
return apply_filters( 'wpcf7_load_css', WPCF7_LOAD_CSS );
}
/**
* Builds an HTML anchor element.
*
* @param string $url Link URL.
* @param string $anchor_text Anchor label text.
* @param string|array $atts Optional. HTML attributes.
* @return string Formatted anchor element.
*/
function wpcf7_link( $url, $anchor_text, $atts = '' ) {
$atts = wp_parse_args( $atts, array(
'id' => null,
'class' => null,
) );
$atts = array_merge( $atts, array(
'href' => esc_url( $url ),
) );
return sprintf(
'<a %1$s>%2$s</a>',
wpcf7_format_atts( $atts ),
esc_html( $anchor_text )
);
}
/**
* Returns the current request URL.
*/
function wpcf7_get_request_uri() {
static $request_uri = '';
if ( empty( $request_uri ) ) {
$request_uri = add_query_arg( array() );
$request_uri = '/' . ltrim( $request_uri, '/' );
}
return sanitize_url( $request_uri );
}
/**
* Registers post types used for this plugin.
*/
function wpcf7_register_post_types() {
if ( class_exists( 'WPCF7_ContactForm' ) ) {
WPCF7_ContactForm::register_post_type();
return true;
} else {
return false;
}
}
/**
* Returns the version string of this plugin.
*
* @param string|array $options Optional. Output options.
* @return string Version string.
*/
function wpcf7_version( $options = '' ) {
$options = wp_parse_args( $options, array(
'limit' => -1,
'only_major' => false,
) );
if ( $options['only_major'] ) {
$options['limit'] = 2;
}
$options['limit'] = (int) $options['limit'];
$ver = WPCF7_VERSION;
$ver = strtr( $ver, '_-+', '...' );
$ver = preg_replace( '/[^0-9.]+/', '.$0.', $ver );
$ver = preg_replace( '/[.]+/', '.', $ver );
$ver = trim( $ver, '.' );
$ver = explode( '.', $ver );
if ( -1 < $options['limit'] ) {
$ver = array_slice( $ver, 0, $options['limit'] );
}
$ver = implode( '.', $ver );
return $ver;
}
/**
* Returns array entries that match the given version.
*
* @param string $version The version to search for.
* @param array $input Search target array.
* @return array|bool Array of matched entries. False on failure.
*/
function wpcf7_version_grep( $version, array $input ) {
$pattern = '/^' . preg_quote( (string) $version, '/' ) . '(?:\.|$)/';
return preg_grep( $pattern, $input );
}
/**
* Returns an enctype attribute value.
*
* @param string $enctype Enctype value.
* @return string Enctype value. Empty if not a valid enctype.
*/
function wpcf7_enctype_value( $enctype ) {
$enctype = trim( $enctype );
if ( empty( $enctype ) ) {
return '';
}
$valid_enctypes = array(
'application/x-www-form-urlencoded',
'multipart/form-data',
'text/plain',
);
if ( in_array( $enctype, $valid_enctypes, true ) ) {
return $enctype;
}
$pattern = '%^enctype="(' . implode( '|', $valid_enctypes ) . ')"$%';
if ( preg_match( $pattern, $enctype, $matches ) ) {
return $matches[1]; // for back-compat
}
return '';
}
/**
* Removes directory recursively.
*
* @param string $dir Directory path.
* @return bool True on success, false on failure.
*/
function wpcf7_rmdir_p( $dir ) {
$filesystem = WPCF7_Filesystem::get_instance();
return $filesystem->delete( $dir, true );
}
/**
* Builds a URL-encoded query string.
*
* @link https://developer.wordpress.org/reference/functions/_http_build_query/
*
* @param array $data URL query parameters.
* @param string $key Optional. If specified, used to prefix key name.
* @return string Query string.
*/
function wpcf7_build_query( $data, $key = '' ) {
$sep = '&';
$ret = array();
foreach ( (array) $data as $k => $v ) {
$k = urlencode( $k );
if ( ! empty( $key ) ) {
$k = $key . '%5B' . $k . '%5D';
}
if ( null === $v ) {
continue;
} elseif ( false === $v ) {
$v = '0';
}
if ( is_array( $v ) or is_object( $v ) ) {
array_push( $ret, wpcf7_build_query( $v, $k ) );
} else {
array_push( $ret, $k . '=' . urlencode( $v ) );
}
}
return implode( $sep, $ret );
}
/**
* Returns the number of code units in a string.
*
* @link http://www.w3.org/TR/html5/infrastructure.html#code-unit-length
*
* @param string $text Input string.
* @return int|false The number of code units, or false if
* mb_convert_encoding is not available.
*/
function wpcf7_count_code_units( $text ) {
static $use_mb = null;
if ( is_null( $use_mb ) ) {
$use_mb = function_exists( 'mb_convert_encoding' );
}
if ( ! $use_mb ) {
return false;
}
$text = (string) $text;
if ( '' === $text ) {
return 0;
}
$text = str_replace( "\r\n", "\n", $text );
$text = mb_convert_encoding(
$text,
'UTF-16',
mb_detect_encoding( $text, mb_detect_order(), true ) ?: 'UTF-8'
);
return intdiv( mb_strlen( $text, '8bit' ), 2 );
}
/**
* Returns true if WordPress is running on the localhost.
*/
function wpcf7_is_localhost() {
$sitename = wp_parse_url( network_home_url(), PHP_URL_HOST );
return in_array(
strtolower( $sitename ),
array( 'localhost', '127.0.0.1' ),
true
);
}
/**
* Marks a function as deprecated and informs when it has been used.
*
* @param string $function_name The function that was called.
* @param string $version The version of Contact Form 7 that deprecated
* the function.
* @param string $replacement The function that should have been called.
*/
function wpcf7_deprecated_function( $function_name, $version, $replacement ) {
if ( ! WP_DEBUG ) {
return;
}
if ( function_exists( '__' ) ) {
/* translators: 1: PHP function name, 2: version number, 3: alternative function name */
$message = __( 'Function %1$s is <strong>deprecated</strong> since Contact Form 7 version %2$s! Use %3$s instead.', 'contact-form-7' );
} else {
$message = 'Function %1$s is <strong>deprecated</strong> since Contact Form 7 version %2$s! Use %3$s instead.';
}
$message = sprintf( $message, $function_name, $version, $replacement );
wp_trigger_error( '', $message, E_USER_DEPRECATED );
}
/**
* Fires functions attached to a deprecated filter hook.
*
* @param string $hook_name The name of the filter hook.
* @param array $args Array of additional function arguments to be
* passed to apply_filters().
* @param string $version The version of Contact Form 7 that deprecated
* the hook.
* @param string $replacement The hook that should have been used.
*/
function wpcf7_apply_filters_deprecated( $hook_name, $args, $version, $replacement = '' ) {
if ( ! has_filter( $hook_name ) ) {
return $args[0];
}
if ( WP_DEBUG and apply_filters( 'deprecated_hook_trigger_error', true ) ) {
if ( $replacement ) {
wp_trigger_error(
'',
sprintf(
/* translators: 1: WordPress hook name, 2: version number, 3: alternative hook name */
__( 'Hook %1$s is <strong>deprecated</strong> since Contact Form 7 version %2$s! Use %3$s instead.', 'contact-form-7' ),
$hook_name,
$version,
$replacement
),
E_USER_DEPRECATED
);
} else {
wp_trigger_error(
'',
sprintf(
/* translators: 1: WordPress hook name, 2: version number */
__( 'Hook %1$s is <strong>deprecated</strong> since Contact Form 7 version %2$s with no alternative available.', 'contact-form-7' ),
$hook_name,
$version
),
E_USER_DEPRECATED
);
}
}
return apply_filters_ref_array( $hook_name, $args );
}
/**
* Marks something as being incorrectly called.
*
* @param string $function_name The function that was called.
* @param string $message A message explaining what has been done incorrectly.
* @param string $version The version of Contact Form 7 where the message
* was added.
*/
function wpcf7_doing_it_wrong( $function_name, $message, $version ) {
if ( ! WP_DEBUG ) {
return;
}
if ( function_exists( '__' ) ) {
if ( $version ) {
$version = sprintf(
/* translators: %s: Contact Form 7 version number. */
__( '(This message was added in Contact Form 7 version %s.)', 'contact-form-7' ),
$version
);
}
wp_trigger_error(
'',
sprintf(
/* translators: Developer debugging message. 1: PHP function name, 2: Explanatory message, 3: Contact Form 7 version number. */
__( 'Function %1$s was called incorrectly. %2$s %3$s', 'contact-form-7' ),
$function_name,
$message,
$version
),
E_USER_NOTICE
);
} else {
if ( $version ) {
$version = sprintf(
'(This message was added in Contact Form 7 version %s.)',
$version
);
}
wp_trigger_error(
'',
sprintf(
'Function %1$s was called incorrectly. %2$s %3$s',
$function_name,
$message,
$version
),
E_USER_NOTICE
);
}
}
/**
* Triggers an error about a remote HTTP request and response.
*
* @param string $url The resource URL.
* @param array $request Request arguments.
* @param array|WP_Error $response The response or WP_Error on failure.
*/
function wpcf7_log_remote_request( $url, $request, $response ) {
if ( ! WP_DEBUG ) {
return;
}
$log = sprintf(
/* translators: 1: response code, 2: message, 3: body, 4: URL */
__( 'HTTP Response: %1$s %2$s %3$s from %4$s', 'contact-form-7' ),
(int) wp_remote_retrieve_response_code( $response ),
wp_remote_retrieve_response_message( $response ),
wp_remote_retrieve_body( $response ),
$url
);
$log = apply_filters( 'wpcf7_log_remote_request',
$log, $url, $request, $response
);
if ( $log ) {
wp_trigger_error( '', $log, E_USER_NOTICE );
}
}
/**
* Anonymizes an IP address by masking local part.
*
* @param string $ip_addr The original IP address.
* @return string|bool Anonymized IP address, or false on failure.
*/
function wpcf7_anonymize_ip_addr( $ip_addr ) {
if (
! function_exists( 'inet_ntop' ) or
! function_exists( 'inet_pton' )
) {
return $ip_addr;
}
$packed = inet_pton( $ip_addr );
if ( false === $packed ) {
return $ip_addr;
}
if ( 4 === strlen( $packed ) ) { // IPv4
$mask = '255.255.255.0';
} elseif ( 16 === strlen( $packed ) ) { // IPv6
$mask = 'ffff:ffff:ffff:0000:0000:0000:0000:0000';
} else {
return $ip_addr;
}
return inet_ntop( $packed & inet_pton( $mask ) );
}
/**
* Retrieves a sanitized value from the $_GET superglobal.
*
* @param string $key Array key.
* @param mixed $default The default value returned when
* the specified superglobal is not set.
* @return mixed Sanitized value.
*/
function wpcf7_superglobal_get( $key, $default = '' ) {
return wpcf7_superglobal( 'get', $key ) ?? $default;
}
/**
* Retrieves a sanitized value from the $_POST superglobal.
*
* @param string $key Array key.
* @param mixed $default The default value returned when
* the specified superglobal is not set.
* @return mixed Sanitized value.
*/
function wpcf7_superglobal_post( $key, $default = '' ) {
return wpcf7_superglobal( 'post', $key ) ?? $default;
}
/**
* Retrieves a sanitized value from the $_REQUEST superglobal.
*
* @param string $key Array key.
* @param mixed $default The default value returned when
* the specified superglobal is not set.
* @return mixed Sanitized value.
*/
function wpcf7_superglobal_request( $key, $default = '' ) {
return wpcf7_superglobal( 'request', $key ) ?? $default;
}
/**
* Retrieves a sanitized value from the $_SERVER superglobal.
*
* @param string $key Array key.
* @param mixed $default The default value returned when
* the specified superglobal is not set.
* @return mixed Sanitized value.
*/
function wpcf7_superglobal_server( $key, $default = '' ) {
return wpcf7_superglobal( 'server', $key ) ?? $default;
}
/**
* Retrieves a sanitized value from the specified superglobal.
*
* @param string $superglobal A superglobal type.
* @param string $key Array key.
* @return string|array|null Sanitized value.
*/
function wpcf7_superglobal( $superglobal, $key ) {
$superglobals = array(
'get' => $_GET,
'post' => $_POST,
'request' => $_REQUEST,
'server' => $_SERVER,
);
if ( isset( $superglobals[$superglobal][$key] ) ) {
return map_deep(
$superglobals[$superglobal][$key],
static function ( $val ) {
$val = wp_unslash( $val );
$val = wp_check_invalid_utf8( $val );
$val = wp_kses_no_null( $val );
$val = wpcf7_strip_whitespaces( $val );
return $val;
}
);
}
}

View File

@ -0,0 +1,868 @@
<?php
/**
* Contact Form 7's class used for formatting HTML fragments.
*/
class WPCF7_HTMLFormatter {
// HTML component types.
const text = 0;
const start_tag = 1;
const end_tag = 2;
const comment = 3;
/**
* Tag name reserved for a custom HTML element used as a block placeholder.
*/
const placeholder_block = 'placeholder:block';
/**
* Tag name reserved for a custom HTML element used as an inline placeholder.
*/
const placeholder_inline = 'placeholder:inline';
/**
* The void elements in HTML.
*
* @link https://developer.mozilla.org/en-US/docs/Glossary/Void_element
*/
const void_elements = array(
'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input',
'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr',
self::placeholder_block, self::placeholder_inline,
);
/**
* HTML elements that can be a direct child of the same element.
*/
const nestable_elements = array(
'article', 'aside', 'blockquote', 'div', 'fieldset', 'section', 'span',
);
/**
* HTML elements that can contain flow content.
*/
const p_parent_elements = array(
'address', 'article', 'aside', 'blockquote', 'body', 'caption',
'dd', 'details', 'dialog', 'div', 'dt', 'fieldset', 'figcaption',
'figure', 'footer', 'form', 'header', 'li', 'main', 'nav',
'section', 'td', 'th',
);
/**
* HTML elements that can be neither the parent nor a child of
* a paragraph element.
*/
const p_nonparent_elements = array(
'colgroup', 'dl', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head',
'hgroup', 'html', 'legend', 'menu', 'ol', 'pre', 'style', 'summary',
'table', 'tbody', 'template', 'tfoot', 'thead', 'title', 'tr', 'ul',
);
/**
* HTML elements in the phrasing content category, plus non-phrasing
* content elements that can be grandchildren of a paragraph element.
*/
const p_child_elements = array(
'a', 'abbr', 'area', 'audio', 'b', 'bdi', 'bdo', 'br', 'button',
'canvas', 'cite', 'code', 'data', 'datalist', 'del', 'dfn',
'em', 'embed', 'i', 'iframe', 'img', 'input', 'ins', 'kbd',
'keygen', 'label', 'link', 'map', 'mark', 'meta',
'meter', 'noscript', 'object', 'output', 'picture', 'progress',
'q', 'ruby', 's', 'samp', 'script', 'select', 'slot', 'small',
'span', 'strong', 'sub', 'sup', 'textarea',
'time', 'u', 'var', 'video', 'wbr',
'optgroup', 'option', 'rp', 'rt', // non-phrasing grandchildren
self::placeholder_inline,
);
/**
* HTML elements that can contain phrasing content.
*/
const br_parent_elements = array(
'a', 'abbr', 'address', 'article', 'aside', 'audio', 'b', 'bdi',
'bdo', 'blockquote', 'button', 'canvas', 'caption', 'cite', 'code',
'data', 'datalist', 'dd', 'del', 'details', 'dfn', 'dialog', 'div',
'dt', 'em', 'fieldset', 'figcaption', 'figure', 'footer', 'form',
'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'header', 'i', 'ins', 'kbd',
'label', 'legend', 'li', 'main', 'map', 'mark', 'meter', 'nav',
'noscript', 'object', 'output', 'p', 'progress', 'q', 'rt',
'ruby', 's', 'samp', 'section', 'slot', 'small', 'span', 'strong',
'sub', 'summary', 'sup', 'td', 'th', 'time', 'u', 'var',
'video',
);
// Properties.
private $options = array();
private $stacked_elements = array();
private $output = '';
/**
* Constructor.
*/
public function __construct( $options = '' ) {
$this->options = wp_parse_args( $options, array(
'auto_br' => true,
'auto_indent' => true,
'allowed_html' => wpcf7_kses_allowed_html(),
) );
}
/**
* Separates the given text into chunks of HTML. Each chunk must be an
* associative array that includes 'position', 'type', and 'content' keys.
*
* @param string $input Text to be separated into chunks.
* @return iterable Iterable of chunks.
*/
public function separate_into_chunks( $input ) {
$input_bytelength = strlen( $input );
$position = 0;
while ( $position < $input_bytelength ) {
$next_tag = preg_match(
'/(?:<!--.*?-->|<(?:\/?)[a-z].*?>)/is',
$input,
$matches,
PREG_OFFSET_CAPTURE,
$position
);
if ( ! $next_tag ) {
yield array(
'position' => $position,
'type' => self::text,
'content' => substr( $input, $position ),
);
break;
}
$next_tag = $matches[0][0];
$next_tag_position = $matches[0][1];
if ( $position < $next_tag_position ) {
yield array(
'position' => $position,
'type' => self::text,
'content' => substr(
$input,
$position,
$next_tag_position - $position
),
);
}
if ( '<!' === substr( $next_tag, 0, 2 ) ) {
$next_tag_type = self::comment;
} elseif ( '</' === substr( $next_tag, 0, 2 ) ) {
$next_tag_type = self::end_tag;
} else {
$next_tag_type = self::start_tag;
}
yield array(
'position' => $next_tag_position,
'type' => $next_tag_type,
'content' => substr(
$input,
$next_tag_position,
strlen( $next_tag )
),
);
$position = $next_tag_position + strlen( $next_tag );
}
}
/**
* Normalizes content in each chunk. This may change the type and position
* of the chunk.
*
* @param iterable $chunks The original chunks.
* @return iterable Normalized chunks.
*/
public function pre_format( $chunks ) {
$position = 0;
foreach ( $chunks as $chunk ) {
$chunk['position'] = $position;
// Standardize newline characters to "\n".
$chunk['content'] = str_replace(
array( "\r\n", "\r" ), "\n", $chunk['content']
);
if ( self::start_tag === $chunk['type'] ) {
list( $chunk['content'] ) =
self::normalize_start_tag( $chunk['content'] );
// Replace <br /> by a line break.
if (
$this->options['auto_br'] and
preg_match( '/^<br\s*\/?>$/i', $chunk['content'] )
) {
$chunk['type'] = self::text;
$chunk['content'] = "\n";
}
}
yield $chunk;
$position = self::calc_next_position( $chunk );
}
}
/**
* Concatenates neighboring text chunks to create a single chunk.
*
* @param iterable $chunks The original chunks.
* @return iterable Processed chunks.
*/
public function concatenate_texts( $chunks ) {
$position = 0;
$text_left = null;
foreach ( $chunks as $chunk ) {
$chunk['position'] = $position;
if ( self::text === $chunk['type'] ) {
if ( isset( $text_left ) ) {
$text_left['content'] .= $chunk['content'];
} else {
$text_left = $chunk;
}
continue;
}
if ( isset( $text_left ) ) {
yield $text_left;
$chunk['position'] = self::calc_next_position( $text_left );
$text_left = null;
}
yield $chunk;
$position = self::calc_next_position( $chunk );
}
if ( isset( $text_left ) ) {
yield $text_left;
}
}
/**
* Outputs formatted HTML based on the given chunks.
*
* @param iterable $chunks The original chunks.
* @return string Formatted HTML.
*/
public function format( $chunks ) {
$chunks = $this->pre_format( $chunks );
$chunks = $this->concatenate_texts( $chunks );
$this->output = '';
$this->stacked_elements = array();
foreach ( $chunks as $chunk ) {
if ( self::text === $chunk['type'] ) {
$this->append_text( $chunk['content'] );
}
if ( self::start_tag === $chunk['type'] ) {
$this->start_tag( $chunk['content'] );
}
if ( self::end_tag === $chunk['type'] ) {
$this->end_tag( $chunk['content'] );
}
if ( self::comment === $chunk['type'] ) {
$this->append_comment( $chunk['content'] );
}
}
return $this->output();
}
/**
* Appends preformatted text to the output property.
*/
public function append_preformatted( $content ) {
$this->output .= $content;
}
/**
* Appends whitespace to the output property.
*/
public function append_whitespace() {
$this->append_preformatted( ' ' );
}
/**
* Appends a text node content to the output property.
*
* @param string $content Text node content.
*/
public function append_text( $content ) {
if ( $this->is_inside( array( 'pre', 'template' ) ) ) {
$this->append_preformatted( $content );
return;
}
if (
empty( $this->stacked_elements ) or
$this->has_parent( 'p' ) or
$this->has_parent( self::p_parent_elements )
) {
// Close <p> if the content starts with multiple line breaks.
if ( preg_match( '/^\s*\n\s*\n\s*/', $content ) ) {
$this->end_tag( 'p' );
}
// Split up the contents into paragraphs, separated by double line breaks.
$paragraphs = preg_split( '/\s*\n\s*\n\s*/', $content );
$paragraphs = array_filter( $paragraphs, static function ( $paragraph ) {
return '' !== wpcf7_strip_whitespaces( $paragraph );
} );
$paragraphs = array_values( $paragraphs );
if ( $paragraphs ) {
if ( $this->is_inside( 'p' ) ) {
$paragraph = array_shift( $paragraphs );
$paragraph = self::normalize_paragraph(
$paragraph,
$this->options['auto_br']
);
$this->append_preformatted( $paragraph );
}
foreach ( $paragraphs as $paragraph ) {
$this->start_tag( 'p' );
$paragraph = wpcf7_strip_whitespaces( $paragraph, 'start' );
$paragraph = self::normalize_paragraph(
$paragraph,
$this->options['auto_br']
);
$this->append_preformatted( $paragraph );
}
}
// Close <p> if the content ends with multiple line breaks.
if ( preg_match( '/\s*\n\s*\n\s*$/', $content ) ) {
$this->end_tag( 'p' );
}
// Cases where the content is a single line break.
if ( preg_match( '/^\s*\n\s*$/', $content ) ) {
$auto_br = $this->options['auto_br'] && $this->is_inside( 'p' );
$content = self::normalize_paragraph( $content, $auto_br );
$this->append_preformatted( $content );
}
} else {
$auto_br = $this->options['auto_br'] &&
$this->has_parent( self::br_parent_elements );
$content = self::normalize_paragraph( $content, $auto_br );
$this->append_preformatted( $content );
}
}
/**
* Appends a start tag to the output property.
*
* @param string $tag A start tag.
*/
public function start_tag( $tag ) {
list( $tag, $tag_name ) = self::normalize_start_tag( $tag );
if (
in_array( $tag_name, self::p_child_elements, true ) and
! $this->is_inside( 'p' ) and
! $this->is_inside( self::p_child_elements ) and
! $this->has_parent( self::p_nonparent_elements )
) {
// Open <p> if it does not exist.
$this->start_tag( 'p' );
}
$this->append_start_tag( $tag_name, array(), $tag );
}
/**
* Appends a start tag to the output property.
*
* @param string $tag_name Tag name.
* @param array $atts Associative array of attribute name and value pairs.
* @param string $tag A start tag.
*/
public function append_start_tag( $tag_name, $atts = array(), $tag = '' ) {
if ( ! self::validate_tag_name( $tag_name ) ) {
wp_trigger_error(
__METHOD__,
sprintf(
/* translators: %s: Invalid HTML tag name */
__( 'Invalid tag name (%s) is specified.', 'contact-form-7' ),
$tag_name
),
E_USER_WARNING
);
return false;
}
if ( WP_DEBUG and ! empty( $this->options['allowed_html'] ) ) {
$html_disallowance = array();
if ( ! isset( $this->options['allowed_html'][$tag_name] ) ) {
$html_disallowance = array(
'element' => $tag_name,
);
} else {
$atts_allowed = $this->options['allowed_html'][$tag_name];
$atts_disallowed = array_diff_ukey( $atts, $atts_allowed,
static function ( $key_1, $key_2 ) use ( $atts_allowed ) {
if (
str_starts_with( $key_1, 'data-' ) and
! empty( $atts_allowed['data-*'] ) and
preg_match( '/^data-[a-z0-9_-]+$/', $key_1 )
) {
return 0;
} else {
return $key_1 === $key_2 ? 0 : 1;
}
}
);
if ( ! empty( $atts_disallowed ) ) {
$html_disallowance = array(
'element' => $tag_name,
'attributes' => array_keys( $atts_disallowed ),
);
}
}
if ( $html_disallowance ) {
$notice = sprintf(
/* translators: %s: JSON-formatted array of disallowed HTML */
__( 'HTML Disallowance: %s', 'contact-form-7' ),
wp_json_encode( $html_disallowance, JSON_PRETTY_PRINT )
);
wp_trigger_error( __METHOD__, $notice, E_USER_NOTICE );
}
}
if (
'p' === $tag_name or
in_array( $tag_name, self::p_parent_elements, true ) or
in_array( $tag_name, self::p_nonparent_elements, true )
) {
// Close <p> if it exists.
$this->end_tag( 'p' );
}
if ( 'dd' === $tag_name or 'dt' === $tag_name ) {
// Close <dd> and <dt> if closing tag is omitted.
$this->end_tag( 'dd' );
$this->end_tag( 'dt' );
}
if ( 'li' === $tag_name ) {
// Close <li> if closing tag is omitted.
$this->end_tag( 'li' );
}
if ( 'optgroup' === $tag_name ) {
// Close <option> and <optgroup> if closing tag is omitted.
$this->end_tag( 'option' );
$this->end_tag( 'optgroup' );
}
if ( 'option' === $tag_name ) {
// Close <option> if closing tag is omitted.
$this->end_tag( 'option' );
}
if ( 'rp' === $tag_name or 'rt' === $tag_name ) {
// Close <rp> and <rt> if closing tag is omitted.
$this->end_tag( 'rp' );
$this->end_tag( 'rt' );
}
if ( 'td' === $tag_name or 'th' === $tag_name ) {
// Close <td> and <th> if closing tag is omitted.
$this->end_tag( 'td' );
$this->end_tag( 'th' );
}
if ( 'tr' === $tag_name ) {
// Close <tr> if closing tag is omitted.
$this->end_tag( 'tr' );
}
if ( 'tbody' === $tag_name or 'tfoot' === $tag_name ) {
// Close <thead> if closing tag is omitted.
$this->end_tag( 'thead' );
}
if ( 'tfoot' === $tag_name ) {
// Close <tbody> if closing tag is omitted.
$this->end_tag( 'tbody' );
}
if (
$this->has_parent( $tag_name ) and
! in_array( $tag_name, self::nestable_elements, true )
) {
$this->end_tag( $tag_name );
}
if ( ! in_array( $tag_name, self::void_elements, true ) ) {
array_unshift( $this->stacked_elements, $tag_name );
}
if ( ! in_array( $tag_name, self::p_child_elements, true ) ) {
if ( '' !== $this->output ) {
$this->output = wpcf7_strip_whitespaces( $this->output, 'end' ) . "\n";
}
if ( $this->options['auto_indent'] ) {
$this->append_preformatted(
self::indent( count( $this->stacked_elements ) - 1 )
);
}
}
if ( $tag ) {
$this->append_preformatted( $tag );
} elseif ( $atts ) {
if ( in_array( $tag_name, self::void_elements, true ) ) {
$this->append_preformatted(
sprintf(
'<%1$s %2$s />',
$tag_name,
wpcf7_format_atts( $atts )
)
);
} else {
$this->append_preformatted(
sprintf(
'<%1$s %2$s>',
$tag_name,
wpcf7_format_atts( $atts )
)
);
}
} else {
if ( in_array( $tag_name, self::void_elements, true ) ) {
$this->append_preformatted(
sprintf(
'<%s />',
$tag_name
)
);
} else {
$this->append_preformatted(
sprintf(
'<%s>',
$tag_name
)
);
}
}
}
/**
* Closes an element and its open descendants at a time.
*
* @param string $tag An end tag.
*/
public function end_tag( $tag ) {
if ( preg_match( '/<\/(.+?)(?:\s|>)/', $tag, $matches ) ) {
$tag_name = strtolower( $matches[1] );
} else {
$tag_name = strtolower( $tag );
}
$stacked_elements = array_values( $this->stacked_elements );
$tag_position = array_search( $tag_name, $stacked_elements, true );
if ( false === $tag_position ) {
return;
}
// Element groups that make up an indirect nesting structure.
// Descendant can contain ancestors.
static $nesting_families = array(
array(
'ancestors' => array( 'dl' ),
'descendants' => array( 'dd', 'dt' ),
),
array(
'ancestors' => array( 'ol', 'ul', 'menu' ),
'descendants' => array( 'li' ),
),
array(
'ancestors' => array( 'table' ),
'descendants' => array( 'td', 'th', 'tr', 'thead', 'tbody', 'tfoot' ),
),
);
foreach ( $nesting_families as $family ) {
$ancestors = (array) $family['ancestors'];
$descendants = (array) $family['descendants'];
if ( in_array( $tag_name, $descendants, true ) ) {
$intersect = array_intersect(
$ancestors,
array_slice( $stacked_elements, 0, $tag_position )
);
if ( $intersect ) { // Ancestor appears after descendant.
return;
}
}
}
while ( $element = array_shift( $this->stacked_elements ) ) {
$this->append_end_tag( $element );
if ( $element === $tag_name ) {
break;
}
}
}
/**
* Appends an end tag to the output property.
*
* @param string $tag_name Tag name.
*/
public function append_end_tag( $tag_name ) {
if ( ! in_array( $tag_name, self::p_child_elements, true ) ) {
// Remove unnecessary <br />.
$this->output = preg_replace( '/\s*<br \/>\s*$/', '', $this->output );
$this->output = wpcf7_strip_whitespaces( $this->output, 'end' ) . "\n";
if ( $this->options['auto_indent'] ) {
$this->append_preformatted(
self::indent( count( $this->stacked_elements ) )
);
}
}
$this->append_preformatted(
sprintf( '</%s>', $tag_name )
);
// Remove trailing <p></p>.
$this->output = preg_replace( '/<p>\s*<\/p>$/', '', $this->output );
}
/**
* Closes all open tags.
*/
public function close_all_tags() {
while ( $element = array_shift( $this->stacked_elements ) ) {
$this->append_end_tag( $element );
}
}
/**
* Appends an HTML comment to the output property.
*
* @param string $tag An HTML comment.
*/
public function append_comment( $tag ) {
$this->append_preformatted( $tag );
}
/**
* Returns true if it is currently inside one of HTML elements specified
* by tag names.
*
* @param string|array $tag_names A tag name or an array of tag names.
*/
public function is_inside( $tag_names ) {
$tag_names = (array) $tag_names;
foreach ( $this->stacked_elements as $element ) {
if ( in_array( $element, $tag_names, true ) ) {
return true;
}
}
return false;
}
/**
* Returns true if the parent node is one of HTML elements specified
* by tag names.
*
* @param string|array $tag_names A tag name or an array of tag names.
*/
public function has_parent( $tag_names ) {
$tag_names = (array) $tag_names;
$parent = reset( $this->stacked_elements );
if ( false === $parent ) {
return false;
}
return in_array( $parent, $tag_names, true );
}
/**
* Calls the callback given by the first parameter. The buffered output
* will be appended to the output property.
*/
public function call_user_func( $callback, ...$args ) {
ob_start();
$result = call_user_func( $callback, ...$args );
$output = ob_get_clean();
if ( false !== $output ) {
$this->append_preformatted( "\n" . $output . "\n" );
}
return $result;
}
/**
* Closes all remaining tags, returns and resets the output.
*/
public function output() {
$this->close_all_tags();
$output = $this->output;
$this->output = '';
return $output;
}
/**
* Prints the output. Returns false if the allowed_html option is empty.
*/
public function print() {
if ( empty( $this->options['allowed_html'] ) ) {
return false;
}
echo wp_kses( $this->output(), $this->options['allowed_html'] );
}
/**
* Calculates the position of the next chunk based on the position and
* length of the current chunk.
*
* @param array $chunk An associative array of the current chunk.
* @return int The position of the next chunk.
*/
public static function calc_next_position( $chunk ) {
return $chunk['position'] + strlen( $chunk['content'] );
}
/**
* Outputs a set of tabs to indent.
*
* @param int $level Indentation level.
* @return string A series of tabs.
*/
public static function indent( $level ) {
$level = (int) $level;
if ( 0 < $level ) {
return str_repeat( "\t", $level );
}
return '';
}
/**
* Normalizes a start tag.
*
* @param string $tag A start tag or a tag name.
* @return array An array includes the normalized start tag and tag name.
*/
public static function normalize_start_tag( $tag ) {
if ( preg_match( '/<(.+?)[\s\/>]/', $tag, $matches ) ) {
$tag_name = strtolower( $matches[1] );
} else {
$tag_name = strtolower( $tag );
$tag = sprintf( '<%s>', $tag_name );
}
if ( in_array( $tag_name, self::void_elements, true ) ) {
// Normalize void element.
$tag = preg_replace( '/\s*\/?>/', ' />', $tag );
}
return array( $tag, $tag_name );
}
/**
* Normalizes a paragraph of text.
*
* @param string $paragraph A paragraph of text.
* @param bool $auto_br Optional. If true, line breaks will be replaced
* by a br element.
* @return string The normalized paragraph.
*/
public static function normalize_paragraph( $paragraph, $auto_br = false ) {
if ( $auto_br ) {
$paragraph = preg_replace( '/\s*\n\s*/', "<br />\n", $paragraph );
}
$paragraph = preg_replace( '/[ ]+/', ' ', $paragraph );
return $paragraph;
}
/**
* Returns true if the specified tag name is valid.
*/
public static function validate_tag_name( $tag_name ) {
return preg_match( '/^[a-z][0-9a-z]*(?:[:][a-z][0-9a-z]*)?$/', $tag_name );
}
}

View File

@ -0,0 +1,430 @@
<?php
/**
* Integration API
*
* @link https://contactform7.com/integration-with-external-apis/
*/
class WPCF7_Integration {
private static $instance;
private $services = array();
private $categories = array();
private function __construct() {}
/**
* Returns initially supported service categories.
*
* @return array Service categories.
*/
public static function get_builtin_categories() {
return array(
'spam_protection' => __( 'Spam protection', 'contact-form-7' ),
'email_marketing' => __( 'Email marketing', 'contact-form-7' ),
'payments' => __( 'Payments', 'contact-form-7' ),
);
}
/**
* Returns the singleton instance of this class.
*
* @return WPCF7_Integration The instance.
*/
public static function get_instance() {
if ( empty( self::$instance ) ) {
self::$instance = new self();
self::$instance->categories = self::get_builtin_categories();
}
return self::$instance;
}
/**
* Adds a service to the services list.
*/
public function add_service( $name, WPCF7_Service $service ) {
$name = sanitize_key( $name );
if ( empty( $name ) or isset( $this->services[$name] ) ) {
return false;
}
$this->services[$name] = $service;
}
/**
* Adds a service category to the categories list.
*/
public function add_category( $name, $title ) {
$name = sanitize_key( $name );
if ( empty( $name ) or isset( $this->categories[$name] ) ) {
return false;
}
$this->categories[$name] = $title;
}
/**
* Returns true if a service with the name exists in the services list.
*
* @param string $name The name of service to search.
*/
public function service_exists( $name = '' ) {
if ( '' === $name ) {
return (bool) count( $this->services );
} else {
return isset( $this->services[$name] );
}
}
/**
* Returns a service object with the name.
*
* @param string $name The name of service.
* @return WPCF7_Service|bool The service object if it exists,
* false otherwise.
*/
public function get_service( $name ) {
if ( $this->service_exists( $name ) ) {
return $this->services[$name];
} else {
return false;
}
}
/**
* Prints services list.
*/
public function list_services( $args = '' ) {
$args = wp_parse_args( $args, array(
'include' => array(),
) );
$singular = false;
$services = (array) $this->services;
if ( ! empty( $args['include'] ) ) {
$services = array_intersect_key( $services,
array_flip( (array) $args['include'] )
);
if ( 1 === count( $services ) ) {
$singular = true;
}
}
if ( empty( $services ) ) {
return;
}
$action = wpcf7_current_action();
foreach ( $services as $name => $service ) {
$cats = array_intersect_key( $this->categories,
array_flip( $service->get_categories() )
);
?>
<div class="card<?php echo $service->is_active() ? ' active' : ''; ?>" id="<?php echo esc_attr( $name ); ?>">
<?php $service->icon(); ?>
<h2 class="title"><?php echo esc_html( $service->get_title() ); ?></h2>
<div class="infobox">
<?php echo esc_html( implode( ', ', $cats ) ); ?>
<br />
<?php $service->link(); ?>
</div>
<br class="clear" />
<div class="inside">
<?php
if ( $singular ) {
$service->display( $action );
} else {
$service->display();
}
?>
</div>
</div>
<?php
}
}
}
/**
* Abstract class for services.
*
* Only instances of this class's subclasses are allowed to be
* listed on the Integration page.
*/
abstract class WPCF7_Service {
abstract public function get_title();
abstract public function is_active();
public function get_categories() {
return array();
}
public function icon() {
return '';
}
public function link() {
return '';
}
public function load( $action = '' ) {
}
public function display( $action = '' ) {
}
public function admin_notice( $message = '' ) {
}
}
/**
* Class for services that use OAuth.
*
* While this is not an abstract class, subclassing this class for
* your aim is advised.
*/
class WPCF7_Service_OAuth2 extends WPCF7_Service {
protected $client_id = '';
protected $client_secret = '';
protected $access_token = '';
protected $refresh_token = '';
protected $authorization_endpoint = 'https://example.com/authorization';
protected $token_endpoint = 'https://example.com/token';
public function get_title() {
return '';
}
public function is_active() {
return ! empty( $this->refresh_token );
}
protected function save_data() {
}
protected function reset_data() {
}
protected function get_redirect_uri() {
return admin_url();
}
protected function menu_page_url( $args = '' ) {
return menu_page_url( 'wpcf7-integration', false );
}
public function load( $action = '' ) {
if ( 'auth_redirect' === $action ) {
$code = wpcf7_superglobal_get( 'code' );
if ( $code ) {
$this->request_token( $code );
}
if ( ! empty( $this->access_token ) ) {
$message = 'success';
} else {
$message = 'failed';
}
wp_safe_redirect( $this->menu_page_url(
array(
'action' => 'setup',
'message' => $message,
)
) );
exit();
}
}
protected function authorize( $scope = '' ) {
$endpoint = add_query_arg(
array(
'response_type' => 'code',
'client_id' => $this->client_id,
'redirect_uri' => urlencode( $this->get_redirect_uri() ),
'scope' => $scope,
),
$this->authorization_endpoint
);
if ( wp_redirect( sanitize_url( $endpoint ) ) ) {
exit();
}
}
protected function get_http_authorization_header( $scheme = 'basic' ) {
$scheme = strtolower( trim( $scheme ) );
switch ( $scheme ) {
case 'bearer':
return sprintf( 'Bearer %s', $this->access_token );
case 'basic':
default:
return sprintf( 'Basic %s',
base64_encode( $this->client_id . ':' . $this->client_secret )
);
}
}
protected function request_token( $authorization_code ) {
$endpoint = add_query_arg(
array(
'code' => $authorization_code,
'redirect_uri' => urlencode( $this->get_redirect_uri() ),
'grant_type' => 'authorization_code',
),
$this->token_endpoint
);
$request = array(
'headers' => array(
'Authorization' => $this->get_http_authorization_header( 'basic' ),
),
);
$response = wp_remote_post( sanitize_url( $endpoint ), $request );
$response_code = (int) wp_remote_retrieve_response_code( $response );
$response_body = wp_remote_retrieve_body( $response );
$response_body = json_decode( $response_body, true );
if ( WP_DEBUG and 400 <= $response_code ) {
$this->log( $endpoint, $request, $response );
}
if ( 401 === $response_code ) { // Unauthorized
$this->access_token = null;
$this->refresh_token = null;
} else {
if ( isset( $response_body['access_token'] ) ) {
$this->access_token = $response_body['access_token'];
} else {
$this->access_token = null;
}
if ( isset( $response_body['refresh_token'] ) ) {
$this->refresh_token = $response_body['refresh_token'];
} else {
$this->refresh_token = null;
}
}
$this->save_data();
return $response;
}
protected function refresh_token() {
$endpoint = add_query_arg(
array(
'refresh_token' => $this->refresh_token,
'grant_type' => 'refresh_token',
),
$this->token_endpoint
);
$request = array(
'headers' => array(
'Authorization' => $this->get_http_authorization_header( 'basic' ),
),
);
$response = wp_remote_post( sanitize_url( $endpoint ), $request );
$response_code = (int) wp_remote_retrieve_response_code( $response );
$response_body = wp_remote_retrieve_body( $response );
$response_body = json_decode( $response_body, true );
if ( WP_DEBUG and 400 <= $response_code ) {
$this->log( $endpoint, $request, $response );
}
if ( 401 === $response_code ) { // Unauthorized
$this->access_token = null;
$this->refresh_token = null;
} else {
if ( isset( $response_body['access_token'] ) ) {
$this->access_token = $response_body['access_token'];
} else {
$this->access_token = null;
}
if ( isset( $response_body['refresh_token'] ) ) {
$this->refresh_token = $response_body['refresh_token'];
}
}
$this->save_data();
return $response;
}
protected function remote_request( $url, $request = array() ) {
static $refreshed = false;
$request = wp_parse_args( $request, array() );
$request['headers'] = array_merge(
$request['headers'],
array(
'Authorization' => $this->get_http_authorization_header( 'bearer' ),
)
);
$response = wp_remote_request( sanitize_url( $url ), $request );
if ( 401 === wp_remote_retrieve_response_code( $response )
and ! $refreshed ) {
$this->refresh_token();
$refreshed = true;
$response = $this->remote_request( $url, $request );
}
return $response;
}
protected function log( $url, $request, $response ) {
wpcf7_log_remote_request( $url, $request, $response );
}
}

View File

@ -0,0 +1,26 @@
( function( $ ) {
$( function() {
var supportHtml5 = ( function() {
var features = {};
var input = document.createElement( 'input' );
var inputTypes = [ 'date' ];
$.each( inputTypes, function( index, value ) {
input.setAttribute( 'type', value );
features[ value ] = input.type !== 'text';
} );
return features;
} )();
if ( ! supportHtml5.date ) {
$( 'input.wpcf7-date[type="date"]' ).each( function() {
$( this ).datepicker( {
dateFormat: 'yy-mm-dd',
minDate: new Date( $( this ).attr( 'min' ) ),
maxDate: new Date( $( this ).attr( 'max' ) )
} );
} );
}
} );
} )( jQuery );

View File

@ -0,0 +1,8 @@
<?php
return array(
'dependencies' => array(
'wp-i18n',
),
'version' => WPCF7_VERSION,
);

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,443 @@
/*!
* jQuery UI CSS Framework 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*
* http://api.jqueryui.com/category/theming/
*
* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Verdana%2CArial%2Csans-serif&fwDefault=normal&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=cccccc&bgTextureHeader=highlight_soft&bgImgOpacityHeader=75&borderColorHeader=aaaaaa&fcHeader=222222&iconColorHeader=222222&bgColorContent=ffffff&bgTextureContent=flat&bgImgOpacityContent=75&borderColorContent=aaaaaa&fcContent=222222&iconColorContent=222222&bgColorDefault=e6e6e6&bgTextureDefault=glass&bgImgOpacityDefault=75&borderColorDefault=d3d3d3&fcDefault=555555&iconColorDefault=888888&bgColorHover=dadada&bgTextureHover=glass&bgImgOpacityHover=75&borderColorHover=999999&fcHover=212121&iconColorHover=454545&bgColorActive=ffffff&bgTextureActive=glass&bgImgOpacityActive=65&borderColorActive=aaaaaa&fcActive=212121&iconColorActive=454545&bgColorHighlight=fbf9ee&bgTextureHighlight=glass&bgImgOpacityHighlight=55&borderColorHighlight=fcefa1&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=glass&bgImgOpacityError=95&borderColorError=cd0a0a&fcError=cd0a0a&iconColorError=cd0a0a&bgColorOverlay=aaaaaa&bgTextureOverlay=flat&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=flat&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px
*/
/* Component containers
----------------------------------*/
.ui-widget {
font-family: Verdana,Arial,sans-serif;
font-size: 1.1em;
}
.ui-widget .ui-widget {
font-size: 1em;
}
.ui-widget input,
.ui-widget select,
.ui-widget textarea,
.ui-widget button {
font-family: Verdana,Arial,sans-serif;
font-size: 1em;
}
.ui-widget.ui-widget-content {
border: 1px solid #d3d3d3;
}
.ui-widget-content {
border: 1px solid #aaaaaa;
background: #ffffff;
color: #222222;
}
.ui-widget-content a {
color: #222222;
}
.ui-widget-header {
border: 1px solid #aaaaaa;
background: #cccccc url("images/ui-bg_highlight-soft_75_cccccc_1x100.png") 50% 50% repeat-x;
color: #222222;
font-weight: bold;
}
.ui-widget-header a {
color: #222222;
}
/* Interaction states
----------------------------------*/
.ui-state-default,
.ui-widget-content .ui-state-default,
.ui-widget-header .ui-state-default,
.ui-button,
/* We use html here because we need a greater specificity to make sure disabled
works properly when clicked or hovered */
html .ui-button.ui-state-disabled:hover,
html .ui-button.ui-state-disabled:active {
border: 1px solid #d3d3d3;
background: #e6e6e6 url("images/ui-bg_glass_75_e6e6e6_1x400.png") 50% 50% repeat-x;
font-weight: normal;
color: #555555;
}
.ui-state-default a,
.ui-state-default a:link,
.ui-state-default a:visited,
a.ui-button,
a:link.ui-button,
a:visited.ui-button,
.ui-button {
color: #555555;
text-decoration: none;
}
.ui-state-hover,
.ui-widget-content .ui-state-hover,
.ui-widget-header .ui-state-hover,
.ui-state-focus,
.ui-widget-content .ui-state-focus,
.ui-widget-header .ui-state-focus,
.ui-button:hover,
.ui-button:focus {
border: 1px solid #999999;
background: #dadada url("images/ui-bg_glass_75_dadada_1x400.png") 50% 50% repeat-x;
font-weight: normal;
color: #212121;
}
.ui-state-hover a,
.ui-state-hover a:hover,
.ui-state-hover a:link,
.ui-state-hover a:visited,
.ui-state-focus a,
.ui-state-focus a:hover,
.ui-state-focus a:link,
.ui-state-focus a:visited,
a.ui-button:hover,
a.ui-button:focus {
color: #212121;
text-decoration: none;
}
.ui-visual-focus {
box-shadow: 0 0 3px 1px rgb(94, 158, 214);
}
.ui-state-active,
.ui-widget-content .ui-state-active,
.ui-widget-header .ui-state-active,
a.ui-button:active,
.ui-button:active,
.ui-button.ui-state-active:hover {
border: 1px solid #aaaaaa;
background: #ffffff url("images/ui-bg_glass_65_ffffff_1x400.png") 50% 50% repeat-x;
font-weight: normal;
color: #212121;
}
.ui-icon-background,
.ui-state-active .ui-icon-background {
border: #aaaaaa;
background-color: #212121;
}
.ui-state-active a,
.ui-state-active a:link,
.ui-state-active a:visited {
color: #212121;
text-decoration: none;
}
/* Interaction Cues
----------------------------------*/
.ui-state-highlight,
.ui-widget-content .ui-state-highlight,
.ui-widget-header .ui-state-highlight {
border: 1px solid #fcefa1;
background: #fbf9ee url("images/ui-bg_glass_55_fbf9ee_1x400.png") 50% 50% repeat-x;
color: #363636;
}
.ui-state-checked {
border: 1px solid #fcefa1;
background: #fbf9ee;
}
.ui-state-highlight a,
.ui-widget-content .ui-state-highlight a,
.ui-widget-header .ui-state-highlight a {
color: #363636;
}
.ui-state-error,
.ui-widget-content .ui-state-error,
.ui-widget-header .ui-state-error {
border: 1px solid #cd0a0a;
background: #fef1ec url("images/ui-bg_glass_95_fef1ec_1x400.png") 50% 50% repeat-x;
color: #cd0a0a;
}
.ui-state-error a,
.ui-widget-content .ui-state-error a,
.ui-widget-header .ui-state-error a {
color: #cd0a0a;
}
.ui-state-error-text,
.ui-widget-content .ui-state-error-text,
.ui-widget-header .ui-state-error-text {
color: #cd0a0a;
}
.ui-priority-primary,
.ui-widget-content .ui-priority-primary,
.ui-widget-header .ui-priority-primary {
font-weight: bold;
}
.ui-priority-secondary,
.ui-widget-content .ui-priority-secondary,
.ui-widget-header .ui-priority-secondary {
opacity: .7;
filter:Alpha(Opacity=70); /* support: IE8 */
font-weight: normal;
}
.ui-state-disabled,
.ui-widget-content .ui-state-disabled,
.ui-widget-header .ui-state-disabled {
opacity: .35;
filter:Alpha(Opacity=35); /* support: IE8 */
background-image: none;
}
.ui-state-disabled .ui-icon {
filter:Alpha(Opacity=35); /* support: IE8 - See #6059 */
}
/* Icons
----------------------------------*/
/* states and images */
.ui-icon {
width: 16px;
height: 16px;
}
.ui-icon,
.ui-widget-content .ui-icon {
background-image: url("images/ui-icons_222222_256x240.png");
}
.ui-widget-header .ui-icon {
background-image: url("images/ui-icons_222222_256x240.png");
}
.ui-state-hover .ui-icon,
.ui-state-focus .ui-icon,
.ui-button:hover .ui-icon,
.ui-button:focus .ui-icon {
background-image: url("images/ui-icons_454545_256x240.png");
}
.ui-state-active .ui-icon,
.ui-button:active .ui-icon {
background-image: url("images/ui-icons_454545_256x240.png");
}
.ui-state-highlight .ui-icon,
.ui-button .ui-state-highlight.ui-icon {
background-image: url("images/ui-icons_2e83ff_256x240.png");
}
.ui-state-error .ui-icon,
.ui-state-error-text .ui-icon {
background-image: url("images/ui-icons_cd0a0a_256x240.png");
}
.ui-button .ui-icon {
background-image: url("images/ui-icons_888888_256x240.png");
}
/* positioning */
.ui-icon-blank { background-position: 16px 16px; }
.ui-icon-caret-1-n { background-position: 0 0; }
.ui-icon-caret-1-ne { background-position: -16px 0; }
.ui-icon-caret-1-e { background-position: -32px 0; }
.ui-icon-caret-1-se { background-position: -48px 0; }
.ui-icon-caret-1-s { background-position: -65px 0; }
.ui-icon-caret-1-sw { background-position: -80px 0; }
.ui-icon-caret-1-w { background-position: -96px 0; }
.ui-icon-caret-1-nw { background-position: -112px 0; }
.ui-icon-caret-2-n-s { background-position: -128px 0; }
.ui-icon-caret-2-e-w { background-position: -144px 0; }
.ui-icon-triangle-1-n { background-position: 0 -16px; }
.ui-icon-triangle-1-ne { background-position: -16px -16px; }
.ui-icon-triangle-1-e { background-position: -32px -16px; }
.ui-icon-triangle-1-se { background-position: -48px -16px; }
.ui-icon-triangle-1-s { background-position: -65px -16px; }
.ui-icon-triangle-1-sw { background-position: -80px -16px; }
.ui-icon-triangle-1-w { background-position: -96px -16px; }
.ui-icon-triangle-1-nw { background-position: -112px -16px; }
.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
.ui-icon-arrow-1-n { background-position: 0 -32px; }
.ui-icon-arrow-1-ne { background-position: -16px -32px; }
.ui-icon-arrow-1-e { background-position: -32px -32px; }
.ui-icon-arrow-1-se { background-position: -48px -32px; }
.ui-icon-arrow-1-s { background-position: -65px -32px; }
.ui-icon-arrow-1-sw { background-position: -80px -32px; }
.ui-icon-arrow-1-w { background-position: -96px -32px; }
.ui-icon-arrow-1-nw { background-position: -112px -32px; }
.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
.ui-icon-arrowthick-1-n { background-position: 1px -48px; }
.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
.ui-icon-arrow-4 { background-position: 0 -80px; }
.ui-icon-arrow-4-diag { background-position: -16px -80px; }
.ui-icon-extlink { background-position: -32px -80px; }
.ui-icon-newwin { background-position: -48px -80px; }
.ui-icon-refresh { background-position: -64px -80px; }
.ui-icon-shuffle { background-position: -80px -80px; }
.ui-icon-transfer-e-w { background-position: -96px -80px; }
.ui-icon-transferthick-e-w { background-position: -112px -80px; }
.ui-icon-folder-collapsed { background-position: 0 -96px; }
.ui-icon-folder-open { background-position: -16px -96px; }
.ui-icon-document { background-position: -32px -96px; }
.ui-icon-document-b { background-position: -48px -96px; }
.ui-icon-note { background-position: -64px -96px; }
.ui-icon-mail-closed { background-position: -80px -96px; }
.ui-icon-mail-open { background-position: -96px -96px; }
.ui-icon-suitcase { background-position: -112px -96px; }
.ui-icon-comment { background-position: -128px -96px; }
.ui-icon-person { background-position: -144px -96px; }
.ui-icon-print { background-position: -160px -96px; }
.ui-icon-trash { background-position: -176px -96px; }
.ui-icon-locked { background-position: -192px -96px; }
.ui-icon-unlocked { background-position: -208px -96px; }
.ui-icon-bookmark { background-position: -224px -96px; }
.ui-icon-tag { background-position: -240px -96px; }
.ui-icon-home { background-position: 0 -112px; }
.ui-icon-flag { background-position: -16px -112px; }
.ui-icon-calendar { background-position: -32px -112px; }
.ui-icon-cart { background-position: -48px -112px; }
.ui-icon-pencil { background-position: -64px -112px; }
.ui-icon-clock { background-position: -80px -112px; }
.ui-icon-disk { background-position: -96px -112px; }
.ui-icon-calculator { background-position: -112px -112px; }
.ui-icon-zoomin { background-position: -128px -112px; }
.ui-icon-zoomout { background-position: -144px -112px; }
.ui-icon-search { background-position: -160px -112px; }
.ui-icon-wrench { background-position: -176px -112px; }
.ui-icon-gear { background-position: -192px -112px; }
.ui-icon-heart { background-position: -208px -112px; }
.ui-icon-star { background-position: -224px -112px; }
.ui-icon-link { background-position: -240px -112px; }
.ui-icon-cancel { background-position: 0 -128px; }
.ui-icon-plus { background-position: -16px -128px; }
.ui-icon-plusthick { background-position: -32px -128px; }
.ui-icon-minus { background-position: -48px -128px; }
.ui-icon-minusthick { background-position: -64px -128px; }
.ui-icon-close { background-position: -80px -128px; }
.ui-icon-closethick { background-position: -96px -128px; }
.ui-icon-key { background-position: -112px -128px; }
.ui-icon-lightbulb { background-position: -128px -128px; }
.ui-icon-scissors { background-position: -144px -128px; }
.ui-icon-clipboard { background-position: -160px -128px; }
.ui-icon-copy { background-position: -176px -128px; }
.ui-icon-contact { background-position: -192px -128px; }
.ui-icon-image { background-position: -208px -128px; }
.ui-icon-video { background-position: -224px -128px; }
.ui-icon-script { background-position: -240px -128px; }
.ui-icon-alert { background-position: 0 -144px; }
.ui-icon-info { background-position: -16px -144px; }
.ui-icon-notice { background-position: -32px -144px; }
.ui-icon-help { background-position: -48px -144px; }
.ui-icon-check { background-position: -64px -144px; }
.ui-icon-bullet { background-position: -80px -144px; }
.ui-icon-radio-on { background-position: -96px -144px; }
.ui-icon-radio-off { background-position: -112px -144px; }
.ui-icon-pin-w { background-position: -128px -144px; }
.ui-icon-pin-s { background-position: -144px -144px; }
.ui-icon-play { background-position: 0 -160px; }
.ui-icon-pause { background-position: -16px -160px; }
.ui-icon-seek-next { background-position: -32px -160px; }
.ui-icon-seek-prev { background-position: -48px -160px; }
.ui-icon-seek-end { background-position: -64px -160px; }
.ui-icon-seek-start { background-position: -80px -160px; }
/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
.ui-icon-seek-first { background-position: -80px -160px; }
.ui-icon-stop { background-position: -96px -160px; }
.ui-icon-eject { background-position: -112px -160px; }
.ui-icon-volume-off { background-position: -128px -160px; }
.ui-icon-volume-on { background-position: -144px -160px; }
.ui-icon-power { background-position: 0 -176px; }
.ui-icon-signal-diag { background-position: -16px -176px; }
.ui-icon-signal { background-position: -32px -176px; }
.ui-icon-battery-0 { background-position: -48px -176px; }
.ui-icon-battery-1 { background-position: -64px -176px; }
.ui-icon-battery-2 { background-position: -80px -176px; }
.ui-icon-battery-3 { background-position: -96px -176px; }
.ui-icon-circle-plus { background-position: 0 -192px; }
.ui-icon-circle-minus { background-position: -16px -192px; }
.ui-icon-circle-close { background-position: -32px -192px; }
.ui-icon-circle-triangle-e { background-position: -48px -192px; }
.ui-icon-circle-triangle-s { background-position: -64px -192px; }
.ui-icon-circle-triangle-w { background-position: -80px -192px; }
.ui-icon-circle-triangle-n { background-position: -96px -192px; }
.ui-icon-circle-arrow-e { background-position: -112px -192px; }
.ui-icon-circle-arrow-s { background-position: -128px -192px; }
.ui-icon-circle-arrow-w { background-position: -144px -192px; }
.ui-icon-circle-arrow-n { background-position: -160px -192px; }
.ui-icon-circle-zoomin { background-position: -176px -192px; }
.ui-icon-circle-zoomout { background-position: -192px -192px; }
.ui-icon-circle-check { background-position: -208px -192px; }
.ui-icon-circlesmall-plus { background-position: 0 -208px; }
.ui-icon-circlesmall-minus { background-position: -16px -208px; }
.ui-icon-circlesmall-close { background-position: -32px -208px; }
.ui-icon-squaresmall-plus { background-position: -48px -208px; }
.ui-icon-squaresmall-minus { background-position: -64px -208px; }
.ui-icon-squaresmall-close { background-position: -80px -208px; }
.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
/* Misc visuals
----------------------------------*/
/* Corner radius */
.ui-corner-all,
.ui-corner-top,
.ui-corner-left,
.ui-corner-tl {
border-top-left-radius: 4px;
}
.ui-corner-all,
.ui-corner-top,
.ui-corner-right,
.ui-corner-tr {
border-top-right-radius: 4px;
}
.ui-corner-all,
.ui-corner-bottom,
.ui-corner-left,
.ui-corner-bl {
border-bottom-left-radius: 4px;
}
.ui-corner-all,
.ui-corner-bottom,
.ui-corner-right,
.ui-corner-br {
border-bottom-right-radius: 4px;
}
/* Overlays */
.ui-widget-overlay {
background: #aaaaaa;
opacity: .3;
filter: Alpha(Opacity=30); /* support: IE8 */
}
.ui-widget-shadow {
-webkit-box-shadow: -8px -8px 8px #aaaaaa;
box-shadow: -8px -8px 8px #aaaaaa;
}

View File

@ -0,0 +1,156 @@
<?php
/**
* Retrieves an associative array of languages to which
* this plugin is translated.
*
* @return array Array of languages.
*/
function wpcf7_l10n() {
static $l10n = array();
if ( ! empty( $l10n ) ) {
return $l10n;
}
if ( ! is_admin() ) {
return $l10n;
}
require_once ABSPATH . 'wp-admin/includes/translation-install.php';
$api = translations_api( 'plugins', array(
'slug' => 'contact-form-7',
'version' => WPCF7_VERSION,
) );
if ( is_wp_error( $api ) or empty( $api['translations'] ) ) {
return $l10n;
}
foreach ( (array) $api['translations'] as $translation ) {
if (
! empty( $translation['language'] ) and
! empty( $translation['english_name'] )
) {
$l10n[$translation['language']] = $translation['english_name'];
}
}
return $l10n;
}
/**
* Returns true if the given locale code looks valid.
*
* @param string $locale Locale code.
*/
function wpcf7_is_valid_locale( $locale ) {
if ( ! is_string( $locale ) ) {
return false;
}
$pattern = '/^[a-z]{2,3}(?:_[a-zA-Z_]{2,})?$/';
return (bool) preg_match( $pattern, $locale );
}
/**
* Returns true if the given locale is an RTL language.
*/
function wpcf7_is_rtl( $locale = '' ) {
static $rtl_locales = array(
'ar' => 'Arabic',
'ary' => 'Moroccan Arabic',
'azb' => 'South Azerbaijani',
'fa_IR' => 'Persian',
'haz' => 'Hazaragi',
'he_IL' => 'Hebrew',
'ps' => 'Pashto',
'ug_CN' => 'Uighur',
);
if ( empty( $locale ) and function_exists( 'is_rtl' ) ) {
return is_rtl();
}
if ( empty( $locale ) ) {
$locale = determine_locale();
}
return isset( $rtl_locales[$locale] );
}
/**
* Loads a translation file into the plugin's text domain.
*
* @param string $locale Locale code.
* @return bool True on success, false on failure.
*/
function wpcf7_load_textdomain( $locale = '' ) {
$mofile = path_join(
WP_LANG_DIR . '/plugins/',
sprintf( '%s-%s.mo', WPCF7_TEXT_DOMAIN, $locale )
);
return load_textdomain( WPCF7_TEXT_DOMAIN, $mofile, $locale );
}
/**
* Unloads translations for the plugin's text domain.
*
* @param bool $reloadable Whether the text domain can be loaded
* just-in-time again.
* @return bool True on success, false on failure.
*/
function wpcf7_unload_textdomain( $reloadable = false ) {
return unload_textdomain( WPCF7_TEXT_DOMAIN, $reloadable );
}
/**
* Switches translation locale, calls the callback, then switches back
* to the original locale.
*
* @param string $locale Locale code.
* @param callable $callback The callable to be called.
* @param mixed $args Parameters to be passed to the callback.
* @return mixed The return value of the callback.
*/
function wpcf7_switch_locale( $locale, callable $callback, ...$args ) {
static $available_locales = null;
if ( ! isset( $available_locales ) ) {
$available_locales = array_merge(
array( 'en_US' ),
get_available_languages()
);
}
$previous_locale = determine_locale();
$do_switch_locale = (
$locale !== $previous_locale &&
in_array( $locale, $available_locales, true ) &&
in_array( $previous_locale, $available_locales, true )
);
if ( $do_switch_locale ) {
wpcf7_unload_textdomain();
switch_to_locale( $locale );
wpcf7_load_textdomain( $locale );
}
$result = call_user_func( $callback, ...$args );
if ( $do_switch_locale ) {
wpcf7_unload_textdomain( true );
restore_previous_locale();
wpcf7_load_textdomain( $previous_locale );
}
return $result;
}

View File

@ -0,0 +1,198 @@
<?php
/**
* Class that represents a mail-tag.
*/
class WPCF7_MailTag {
private $tag;
private $tagname = '';
private $name = '';
private $options = array();
private $values = array();
private $form_tag = null;
/**
* The constructor method.
*/
public function __construct( $tag, $tagname, $values ) {
$this->tag = $tag;
$this->name = $this->tagname = $tagname;
$this->options = array(
'do_not_heat' => false,
'format' => '',
);
if ( ! empty( $values ) ) {
preg_match_all( '/"[^"]*"|\'[^\']*\'/', $values, $matches );
$this->values = wpcf7_strip_quote_deep( $matches[0] );
}
if ( preg_match( '/^_raw_(.+)$/', $tagname, $matches ) ) {
$this->name = trim( $matches[1] );
$this->options['do_not_heat'] = true;
}
if ( preg_match( '/^_format_(.+)$/', $tagname, $matches ) ) {
$this->name = trim( $matches[1] );
$this->options['format'] = $this->values[0];
}
}
/**
* Returns the name part of this mail-tag.
*/
public function tag_name() {
return $this->tagname;
}
/**
* Returns the form field name corresponding to this mail-tag.
*/
public function field_name() {
return strtr( $this->name, '.', '_' );
}
/**
* Returns the value of the specified option.
*/
public function get_option( $option ) {
return $this->options[$option];
}
/**
* Returns the values part of this mail-tag.
*/
public function values() {
return $this->values;
}
/**
* Retrieves the WPCF7_FormTag object that corresponds to this mail-tag.
*/
public function corresponding_form_tag() {
if ( $this->form_tag instanceof WPCF7_FormTag ) {
return $this->form_tag;
}
if ( $submission = WPCF7_Submission::get_instance() ) {
$contact_form = $submission->get_contact_form();
$tags = $contact_form->scan_form_tags( array(
'name' => $this->field_name(),
'feature' => '! zero-controls-container',
) );
if ( $tags ) {
$this->form_tag = $tags[0];
}
}
return $this->form_tag;
}
}
use Contactable\SWV;
/**
* Mail-tag output calculator.
*/
class WPCF7_MailTag_OutputCalculator {
const email = 0b100;
const text = 0b010;
const blank = 0b001;
private $contact_form;
public function __construct( WPCF7_ContactForm $contact_form ) {
$this->contact_form = $contact_form;
}
public function calc_output( WPCF7_MailTag $mail_tag ) {
return $this->calc_swv_result(
$mail_tag,
$this->contact_form->get_schema()
);
}
private function calc_swv_result( WPCF7_MailTag $mail_tag, SWV\Rule $rule ) {
if ( $rule instanceof SWV\AnyRule ) {
$result = 0b000;
foreach ( $rule->rules() as $child_rule ) {
$result |= $this->calc_swv_result( $mail_tag, $child_rule );
}
return $result;
}
if ( $rule instanceof SWV\CompositeRule ) {
$result = 0b111;
foreach ( $rule->rules() as $child_rule ) {
$result &= $this->calc_swv_result( $mail_tag, $child_rule );
}
return $result;
}
$field_prop = $rule->get_property( 'field' );
if ( empty( $field_prop ) or $field_prop !== $mail_tag->field_name() ) {
return self::email | self::text | self::blank;
}
if ( $rule instanceof SWV\RequiredRule ) {
return ~ self::blank;
}
if ( $rule instanceof SWV\EmailRule ) {
return self::email | self::blank;
}
if ( $rule instanceof SWV\EnumRule ) {
$acceptable_values = (array) $rule->get_property( 'accept' );
$acceptable_values = array_map( 'strval', $acceptable_values );
$acceptable_values = array_filter( $acceptable_values );
$acceptable_values = array_unique( $acceptable_values );
if ( ! $mail_tag->get_option( 'do_not_heat' ) ) {
$pipes = $this->contact_form->get_pipes(
$mail_tag->field_name()
);
$acceptable_values = array_map(
static function ( $val ) use ( $pipes ) {
return $pipes->do_pipe( $val );
},
$acceptable_values
);
}
$email_values = array_filter(
$acceptable_values,
'wpcf7_is_mailbox_list'
);
if ( count( $email_values ) === count( $acceptable_values ) ) {
return self::email | self::blank;
} else {
return self::email | self::text | self::blank;
}
}
return self::email | self::text | self::blank;
}
}

View File

@ -0,0 +1,632 @@
<?php
add_filter( 'wpcf7_mail_html_body', 'wpcf7_mail_html_body_autop', 10, 1 );
/**
* Filter callback that applies auto-p to HTML email message body.
*/
function wpcf7_mail_html_body_autop( $body ) {
if ( wpcf7_autop_or_not( array( 'for' => 'mail' ) ) ) {
$body = wpcf7_autop( $body );
}
return $body;
}
/**
* Class that represents an attempt to compose and send email.
*/
class WPCF7_Mail {
private static $current = null;
private $name = '';
private $locale = '';
private $template = array();
private $component = '';
private $use_html = false;
private $exclude_blank = false;
/**
* Returns the singleton instance of this class.
*/
public static function get_current() {
return self::$current;
}
/**
* Returns the name of the email template currently processed.
*
* Expected output: 'mail' or 'mail_2'
*/
public static function get_current_template_name() {
$current = self::get_current();
if ( $current instanceof self ) {
return $current->get_template_name();
}
}
/**
* Returns the name of the email template component currently processed.
*
* Expected output: 'recipient', 'sender', 'subject',
* 'additional_headers', 'body', or 'attachments'
*/
public static function get_current_component_name() {
$current = self::get_current();
if ( $current instanceof self ) {
return $current->get_component_name();
}
}
/**
* Composes and sends email based on the specified template.
*
* @param array $template Array of email template.
* @param string $name Optional name of the template, such as
* 'mail' or 'mail_2'. Default empty string.
* @return bool Whether the email was sent successfully.
*/
public static function send( $template, $name = '' ) {
self::$current = new self( $name, $template );
return self::$current->compose();
}
/**
* The constructor method.
*
* @param string $name The name of the email template.
* Such as 'mail' or 'mail_2'.
* @param array $template Array of email template.
*/
private function __construct( $name, $template ) {
$this->name = trim( $name );
$this->use_html = ! empty( $template['use_html'] );
$this->exclude_blank = ! empty( $template['exclude_blank'] );
$this->template = wp_parse_args( $template, array(
'subject' => '',
'sender' => '',
'body' => '',
'recipient' => '',
'additional_headers' => '',
'attachments' => '',
) );
if ( $submission = WPCF7_Submission::get_instance() ) {
$contact_form = $submission->get_contact_form();
$this->locale = $contact_form->locale();
}
}
/**
* Returns the name of the email template.
*/
public function name() {
return $this->name;
}
/**
* Returns the name of the email template. A wrapper method of name().
*/
public function get_template_name() {
return $this->name();
}
/**
* Returns the name of the email template component currently processed.
*/
public function get_component_name() {
return $this->component;
}
/**
* Retrieves a component from the email template.
*
* @param string $component The name of the component.
* @param bool $replace_tags Whether to replace mail-tags
* within the component.
* @return string The text representation of the email component.
*/
public function get( $component, $replace_tags = false ) {
$this->component = $component;
$use_html = ( $this->use_html && 'body' === $component );
$exclude_blank = ( $this->exclude_blank && 'body' === $component );
$template = $this->template;
$component = isset( $template[$component] ) ? $template[$component] : '';
if ( $replace_tags ) {
$component = $this->replace_tags( $component, array(
'html' => $use_html,
'exclude_blank' => $exclude_blank,
) );
if ( $use_html ) {
// Convert <example@example.com> to &lt;example@example.com&gt;.
$component = preg_replace_callback(
'/<(.*?)>/',
static function ( $matches ) {
if ( is_email( $matches[1] ) ) {
return sprintf( '&lt;%s&gt;', $matches[1] );
} else {
return $matches[0];
}
},
$component
);
if ( ! preg_match( '%<html[>\s].*</html>%is', $component ) ) {
$component = $this->htmlize( $component );
}
}
}
$this->component = '';
return $component;
}
/**
* Creates HTML message body by adding the header and footer.
*
* @param string $body The body part of HTML.
* @return string Formatted HTML.
*/
private function htmlize( $body ) {
if ( $this->locale ) {
$lang_atts = sprintf( ' %s',
wpcf7_format_atts( array(
'dir' => wpcf7_is_rtl( $this->locale ) ? 'rtl' : 'ltr',
'lang' => str_replace( '_', '-', $this->locale ),
) )
);
} else {
$lang_atts = '';
}
$header = apply_filters( 'wpcf7_mail_html_header',
'<!doctype html>
<html xmlns="http://www.w3.org/1999/xhtml"' . $lang_atts . '>
<head>
<title>' . esc_html( $this->get( 'subject', true ) ) . '</title>
</head>
<body>
',
$this
);
$body = apply_filters( 'wpcf7_mail_html_body', $body, $this );
$footer = apply_filters( 'wpcf7_mail_html_footer',
'</body>
</html>',
$this
);
return $header . $body . $footer;
}
/**
* Composes an email message and attempts to send it.
*
* @param bool $send Whether to attempt to send email. Default true.
*/
private function compose( $send = true ) {
$components = array(
'subject' => $this->get( 'subject', true ),
'sender' => $this->get( 'sender', true ),
'body' => $this->get( 'body', true ),
'recipient' => $this->get( 'recipient', true ),
'additional_headers' => $this->get( 'additional_headers', true ),
'attachments' => $this->attachments(),
);
$components = apply_filters( 'wpcf7_mail_components',
$components, wpcf7_get_current_contact_form(), $this
);
if ( ! $send ) {
return $components;
}
$subject = wpcf7_strip_newline( $components['subject'] );
$sender = wpcf7_strip_newline( $components['sender'] );
$recipient = wpcf7_strip_newline( $components['recipient'] );
$body = $components['body'];
$additional_headers = trim( $components['additional_headers'] );
$headers = "From: $sender\n";
if ( $this->use_html ) {
$headers .= "Content-Type: text/html\n";
$headers .= "X-WPCF7-Content-Type: text/html\n";
} else {
$headers .= "X-WPCF7-Content-Type: text/plain\n";
}
if ( $additional_headers ) {
$headers .= $additional_headers . "\n";
}
$attachments = array_filter(
(array) $components['attachments'],
function ( $attachment ) {
$path = path_join( WP_CONTENT_DIR, $attachment );
if ( ! wpcf7_is_file_path_in_content_dir( $path ) ) {
wp_trigger_error(
'',
sprintf(
/* translators: %s: Attachment file path. */
__( 'Failed to attach a file. %s is not in the allowed directory.', 'contact-form-7' ),
$path
),
E_USER_NOTICE
);
return false;
}
if ( ! is_readable( $path ) or ! is_file( $path ) ) {
wp_trigger_error(
'',
sprintf(
/* translators: %s: Attachment file path. */
__( 'Failed to attach a file. %s is not a readable file.', 'contact-form-7' ),
$path
),
E_USER_NOTICE
);
return false;
}
static $total_size = array();
if ( ! isset( $total_size[$this->name] ) ) {
$total_size[$this->name] = 0;
}
$file_size = (int) @filesize( $path );
if ( 25 * MB_IN_BYTES < $total_size[$this->name] + $file_size ) {
wp_trigger_error(
'',
__( 'Failed to attach a file. The total file size exceeds the limit of 25 megabytes.', 'contact-form-7' ),
E_USER_NOTICE
);
return false;
}
$total_size[$this->name] += $file_size;
return true;
}
);
return wp_mail( $recipient, $subject, $body, $headers, $attachments );
}
/**
* Replaces mail-tags within the given text.
*/
public function replace_tags( $content, $options = '' ) {
if ( true === $options ) {
$options = array( 'html' => true );
}
$options = wp_parse_args( $options, array(
'html' => false,
'exclude_blank' => false,
) );
return wpcf7_mail_replace_tags( $content, $options );
}
/**
* Creates an array of attachments based on uploaded files and local files.
*/
private function attachments( $template = null ) {
if ( ! $template ) {
$template = $this->get( 'attachments' );
}
$attachments = array();
if ( $submission = WPCF7_Submission::get_instance() ) {
$uploaded_files = $submission->uploaded_files();
foreach ( (array) $uploaded_files as $name => $paths ) {
if ( false !== strpos( $template, "[{$name}]" ) ) {
$attachments = array_merge( $attachments, (array) $paths );
}
}
}
foreach ( explode( "\n", $template ) as $line ) {
$line = trim( $line );
if ( '' === $line or '[' === substr( $line, 0, 1 ) ) {
continue;
}
$attachments[] = path_join( WP_CONTENT_DIR, $line );
}
if ( $submission = WPCF7_Submission::get_instance() ) {
$attachments = array_merge(
$attachments,
(array) $submission->extra_attachments( $this->name )
);
}
return $attachments;
}
}
/**
* Replaces all mail-tags within the given text content.
*
* @param string $content Text including mail-tags.
* @param string|array $options Optional. Output options.
* @return string Result of replacement.
*/
function wpcf7_mail_replace_tags( $content, $options = '' ) {
$options = wp_parse_args( $options, array(
'html' => false,
'exclude_blank' => false,
) );
if ( is_array( $content ) ) {
foreach ( $content as $key => $value ) {
$content[$key] = wpcf7_mail_replace_tags( $value, $options );
}
return $content;
}
$content = explode( "\n", $content );
foreach ( $content as $num => $line ) {
$line = new WPCF7_MailTaggedText( $line, $options );
$replaced = $line->replace_tags();
if ( $options['exclude_blank'] ) {
$replaced_tags = $line->get_replaced_tags();
if (
empty( $replaced_tags ) or
array_filter( $replaced_tags, 'strlen' )
) {
$content[$num] = $replaced;
} else {
unset( $content[$num] ); // Remove a line.
}
} else {
$content[$num] = $replaced;
}
}
$content = implode( "\n", $content );
return $content;
}
add_action( 'phpmailer_init', 'wpcf7_phpmailer_init', 10, 1 );
/**
* Adds custom properties to the PHPMailer object.
*/
function wpcf7_phpmailer_init( $phpmailer ) {
$custom_headers = $phpmailer->getCustomHeaders();
$phpmailer->clearCustomHeaders();
$wpcf7_content_type = false;
foreach ( (array) $custom_headers as $custom_header ) {
$name = $custom_header[0];
$value = $custom_header[1];
if ( 'X-WPCF7-Content-Type' === $name ) {
$wpcf7_content_type = trim( $value );
} else {
$phpmailer->addCustomHeader( $name, $value );
}
}
if ( 'text/html' === $wpcf7_content_type ) {
$phpmailer->msgHTML( $phpmailer->Body );
} elseif ( 'text/plain' === $wpcf7_content_type ) {
$phpmailer->AltBody = '';
}
}
/**
* Class that represents a single-line text including mail-tags.
*/
class WPCF7_MailTaggedText {
private $html = false;
private $callback = null;
private $content = '';
private $replaced_tags = array();
/**
* The constructor method.
*/
public function __construct( $content, $options = '' ) {
$options = wp_parse_args( $options, array(
'html' => false,
'callback' => null,
) );
$this->html = (bool) $options['html'];
if (
null !== $options['callback'] and
is_callable( $options['callback'] )
) {
$this->callback = $options['callback'];
} elseif ( $this->html ) {
$this->callback = array( $this, 'replace_tags_callback_html' );
} else {
$this->callback = array( $this, 'replace_tags_callback' );
}
$this->content = $content;
}
/**
* Retrieves mail-tags that have been replaced by this instance.
*
* @return array List of mail-tags replaced.
*/
public function get_replaced_tags() {
return $this->replaced_tags;
}
/**
* Replaces mail-tags based on regexp.
*/
public function replace_tags() {
$regex = '/(\[?)\[[\t ]*'
. '([a-zA-Z_][0-9a-zA-Z:._-]*)' // [2] = name
. '((?:[\t ]+"[^"]*"|[\t ]+\'[^\']*\')*)' // [3] = values
. '[\t ]*\](\]?)/';
return preg_replace_callback( $regex, $this->callback, $this->content );
}
/**
* Callback function for replacement. For HTML message body.
*/
private function replace_tags_callback_html( $matches ) {
return $this->replace_tags_callback( $matches, true );
}
/**
* Callback function for replacement.
*/
private function replace_tags_callback( $matches, $html = false ) {
// allow [[foo]] syntax for escaping a tag
if ( '[' === $matches[1] and ']' === $matches[4] ) {
return substr( $matches[0], 1, -1 );
}
$tag = $matches[0];
$tagname = $matches[2];
$values = $matches[3];
$mail_tag = new WPCF7_MailTag( $tag, $tagname, $values );
$field_name = $mail_tag->field_name();
$submission = WPCF7_Submission::get_instance();
$submitted = $submission
? $submission->get_posted_data( $field_name )
: null;
if ( $mail_tag->get_option( 'do_not_heat' ) ) {
$submitted = wpcf7_superglobal_post( $field_name );
}
$replaced = $submitted;
if ( null !== $replaced ) {
if ( $format = $mail_tag->get_option( 'format' ) ) {
$replaced = $this->format( $replaced, $format );
}
$separator = ( 'body' === WPCF7_Mail::get_current_component_name() )
? wp_get_list_item_separator()
: ', ';
$replaced = wpcf7_flat_join( $replaced, array(
'separator' => $separator,
) );
if ( $html ) {
$replaced = esc_html( $replaced );
$replaced = wptexturize( $replaced );
}
}
if ( $form_tag = $mail_tag->corresponding_form_tag() ) {
$type = $form_tag->type;
$replaced = apply_filters(
"wpcf7_mail_tag_replaced_{$type}", $replaced,
$submitted, $html, $mail_tag
);
}
$replaced = apply_filters(
'wpcf7_mail_tag_replaced', $replaced,
$submitted, $html, $mail_tag
);
if ( null !== $replaced ) {
$replaced = trim( $replaced );
$this->replaced_tags[$tag] = $replaced;
return $replaced;
}
$special = apply_filters( 'wpcf7_special_mail_tags', null,
$mail_tag->tag_name(), $html, $mail_tag
);
if ( null !== $special ) {
$this->replaced_tags[$tag] = $special;
return $special;
}
return $tag;
}
/**
* Formats string based on the formatting option in the form-tag.
*/
public function format( $original, $format ) {
$original = (array) $original;
foreach ( $original as $key => $value ) {
if ( preg_match( '/^[0-9]{4}-[0-9]{2}-[0-9]{2}$/', $value ) ) {
$datetime = date_create( $value, wp_timezone() );
if ( false !== $datetime ) {
$original[$key] = wp_date( $format, $datetime->getTimestamp() );
}
}
}
return $original;
}
}

View File

@ -0,0 +1,149 @@
<?php
/**
* Pipe-related classes.
*
* @link https://contactform7.com/selectable-recipient-with-pipes/
*/
/**
* Class representing a pair of pipe.
*/
class WPCF7_Pipe {
public $before = '';
public $after = '';
public function __construct( $text ) {
$text = (string) $text;
$pipe_pos = strpos( $text, '|' );
if ( false === $pipe_pos ) {
$this->before = $this->after = wpcf7_strip_whitespaces( $text );
} else {
$this->before = wpcf7_strip_whitespaces( substr( $text, 0, $pipe_pos ) );
$this->after = wpcf7_strip_whitespaces( substr( $text, $pipe_pos + 1 ) );
}
}
}
/**
* Class representing a list of pipes.
*/
class WPCF7_Pipes {
private $pipes = array();
public function __construct( $texts = null ) {
foreach ( (array) $texts as $text ) {
$this->add_pipe( $text );
}
}
private function add_pipe( $text ) {
$pipe = new WPCF7_Pipe( $text );
$this->pipes[] = $pipe;
}
public function merge( self $another ) {
$this->pipes = array_merge( $this->pipes, $another->pipes );
}
public function do_pipe( $input ) {
$input_canonical = wpcf7_canonicalize( $input, array(
'strto' => 'as-is',
) );
foreach ( $this->pipes as $pipe ) {
$before_canonical = wpcf7_canonicalize( $pipe->before, array(
'strto' => 'as-is',
) );
if ( $input_canonical === $before_canonical ) {
return $pipe->after;
}
}
return $input;
}
public function collect_befores() {
$befores = array();
foreach ( $this->pipes as $pipe ) {
$befores[] = $pipe->before;
}
return $befores;
}
public function collect_afters() {
$afters = array();
foreach ( $this->pipes as $pipe ) {
$afters[] = $pipe->after;
}
return $afters;
}
public function zero() {
return empty( $this->pipes );
}
public function random_pipe() {
if ( $this->zero() ) {
return null;
}
return $this->pipes[array_rand( $this->pipes )];
}
public function to_array() {
return array_map(
static function ( WPCF7_Pipe $pipe ) {
return array(
$pipe->before,
$pipe->after,
);
},
$this->pipes
);
}
}
/**
* Trait for classes that hold cross-tag WPCF7_Pipes object.
*/
trait WPCF7_PipesHolder {
protected $pipes;
public function get_pipes( $field_name ) {
if ( isset( $this->pipes[$field_name] ) ) {
return $this->pipes[$field_name];
}
$result = new WPCF7_Pipes();
$tags = $this->scan_form_tags( array(
'name' => $field_name,
) );
foreach ( $tags as $tag ) {
if ( $tag->pipes instanceof WPCF7_Pipes ) {
$result->merge( $tag->pipes );
}
}
return $this->pipes[$field_name] = $result;
}
public function scan_form_tags() {
return array();
}
}

View File

@ -0,0 +1,20 @@
<?php
/**
* Handy trait provides methods to handle dynamic properties.
*/
trait WPCF7_PocketHolder {
protected $pocket = array();
public function pull( $key ) {
if ( isset( $this->pocket[$key] ) ) {
return $this->pocket[$key];
}
}
public function push( $key, $value ) {
$this->pocket[$key] = $value;
}
}

View File

@ -0,0 +1,524 @@
<?php
add_action(
'rest_api_init',
static function () {
$controller = new WPCF7_REST_Controller();
$controller->register_routes();
},
10, 0
);
class WPCF7_REST_Controller {
const route_namespace = 'contact-form-7/v1';
public function register_routes() {
register_rest_route( self::route_namespace,
'/contact-forms',
array(
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'get_contact_forms' ),
'permission_callback' => static function () {
if ( current_user_can( 'wpcf7_read_contact_forms' ) ) {
return true;
} else {
return new WP_Error( 'wpcf7_forbidden',
__( 'You are not allowed to access contact forms.', 'contact-form-7' ),
array( 'status' => 403 )
);
}
},
),
array(
'methods' => WP_REST_Server::CREATABLE,
'callback' => array( $this, 'create_contact_form' ),
'permission_callback' => static function () {
if ( current_user_can( 'wpcf7_edit_contact_forms' ) ) {
return true;
} else {
return new WP_Error( 'wpcf7_forbidden',
__( 'You are not allowed to create a contact form.', 'contact-form-7' ),
array( 'status' => 403 )
);
}
},
),
)
);
register_rest_route( self::route_namespace,
'/contact-forms/(?P<id>\d+)',
array(
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'get_contact_form' ),
'permission_callback' => static function ( WP_REST_Request $request ) {
$id = (int) $request->get_param( 'id' );
if ( current_user_can( 'wpcf7_edit_contact_form', $id ) ) {
return true;
} else {
return new WP_Error( 'wpcf7_forbidden',
__( 'You are not allowed to access the requested contact form.', 'contact-form-7' ),
array( 'status' => 403 )
);
}
},
),
array(
'methods' => WP_REST_Server::EDITABLE,
'callback' => array( $this, 'update_contact_form' ),
'permission_callback' => static function ( WP_REST_Request $request ) {
$id = (int) $request->get_param( 'id' );
if ( current_user_can( 'wpcf7_edit_contact_form', $id ) ) {
return true;
} else {
return new WP_Error( 'wpcf7_forbidden',
__( 'You are not allowed to access the requested contact form.', 'contact-form-7' ),
array( 'status' => 403 )
);
}
},
),
array(
'methods' => WP_REST_Server::DELETABLE,
'callback' => array( $this, 'delete_contact_form' ),
'permission_callback' => static function ( WP_REST_Request $request ) {
$id = (int) $request->get_param( 'id' );
if ( current_user_can( 'wpcf7_delete_contact_form', $id ) ) {
return true;
} else {
return new WP_Error( 'wpcf7_forbidden',
__( 'You are not allowed to access the requested contact form.', 'contact-form-7' ),
array( 'status' => 403 )
);
}
},
),
)
);
register_rest_route( self::route_namespace,
'/contact-forms/(?P<id>\d+)/feedback',
array(
array(
'methods' => WP_REST_Server::CREATABLE,
'callback' => array( $this, 'create_feedback' ),
'permission_callback' => '__return_true',
),
)
);
register_rest_route( self::route_namespace,
'/contact-forms/(?P<id>\d+)/feedback/schema',
array(
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'get_schema' ),
'permission_callback' => '__return_true',
),
'schema' => 'wpcf7_swv_get_meta_schema',
)
);
register_rest_route( self::route_namespace,
'/contact-forms/(?P<id>\d+)/refill',
array(
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'get_refill' ),
'permission_callback' => '__return_true',
),
)
);
}
public function get_contact_forms( WP_REST_Request $request ) {
$args = array();
$per_page = $request->get_param( 'per_page' );
if ( null !== $per_page ) {
$args['posts_per_page'] = (int) $per_page;
}
$offset = $request->get_param( 'offset' );
if ( null !== $offset ) {
$args['offset'] = (int) $offset;
}
$order = $request->get_param( 'order' );
if ( null !== $order ) {
$args['order'] = (string) $order;
}
$orderby = $request->get_param( 'orderby' );
if ( null !== $orderby ) {
$args['orderby'] = (string) $orderby;
}
$search = $request->get_param( 'search' );
if ( null !== $search ) {
$args['s'] = (string) $search;
}
$items = WPCF7_ContactForm::find( $args );
$response = array();
foreach ( $items as $item ) {
$response[] = array(
'id' => $item->id(),
'hash' => $item->hash(),
'slug' => $item->name(),
'title' => $item->title(),
'locale' => $item->locale(),
);
}
return rest_ensure_response( $response );
}
public function create_contact_form( WP_REST_Request $request ) {
$id = (int) $request->get_param( 'id' );
if ( $id ) {
return new WP_Error( 'wpcf7_post_exists',
__( 'Cannot create existing contact form.', 'contact-form-7' ),
array( 'status' => 400 )
);
}
$args = $request->get_params();
$args['id'] = -1; // Create
$context = $request->get_param( 'context' );
$item = wpcf7_save_contact_form( $args, $context );
if ( ! $item ) {
return new WP_Error( 'wpcf7_cannot_save',
__( 'There was an error saving the contact form.', 'contact-form-7' ),
array( 'status' => 500 )
);
}
$response = array(
'id' => $item->id(),
'slug' => $item->name(),
'title' => $item->title(),
'locale' => $item->locale(),
'properties' => $this->get_properties( $item ),
'config_errors' => array(),
);
if ( wpcf7_validate_configuration() ) {
$config_validator = new WPCF7_ConfigValidator( $item );
$config_validator->validate();
$response['config_errors'] = $config_validator->collect_error_messages(
array( 'decodes_html_entities' => true )
);
if ( 'save' === $context ) {
$config_validator->save();
}
}
return rest_ensure_response( $response );
}
public function get_contact_form( WP_REST_Request $request ) {
$id = (int) $request->get_param( 'id' );
$item = wpcf7_contact_form( $id );
if ( ! $item ) {
return new WP_Error( 'wpcf7_not_found',
__( 'The requested contact form was not found.', 'contact-form-7' ),
array( 'status' => 404 )
);
}
$response = array(
'id' => $item->id(),
'slug' => $item->name(),
'title' => $item->title(),
'locale' => $item->locale(),
'properties' => $this->get_properties( $item ),
);
return rest_ensure_response( $response );
}
public function update_contact_form( WP_REST_Request $request ) {
$id = (int) $request->get_param( 'id' );
$item = wpcf7_contact_form( $id );
if ( ! $item ) {
return new WP_Error( 'wpcf7_not_found',
__( 'The requested contact form was not found.', 'contact-form-7' ),
array( 'status' => 404 )
);
}
$args = $request->get_params();
$context = $request->get_param( 'context' );
$item = wpcf7_save_contact_form( $args, $context );
if ( ! $item ) {
return new WP_Error( 'wpcf7_cannot_save',
__( 'There was an error saving the contact form.', 'contact-form-7' ),
array( 'status' => 500 )
);
}
$response = array(
'id' => $item->id(),
'slug' => $item->name(),
'title' => $item->title(),
'locale' => $item->locale(),
'properties' => $this->get_properties( $item ),
'config_errors' => array(),
);
if ( wpcf7_validate_configuration() ) {
$config_validator = new WPCF7_ConfigValidator( $item );
$config_validator->validate();
$response['config_errors'] = $config_validator->collect_error_messages(
array( 'decodes_html_entities' => true )
);
if ( 'save' === $context ) {
$config_validator->save();
}
}
return rest_ensure_response( $response );
}
public function delete_contact_form( WP_REST_Request $request ) {
$id = (int) $request->get_param( 'id' );
$item = wpcf7_contact_form( $id );
if ( ! $item ) {
return new WP_Error( 'wpcf7_not_found',
__( 'The requested contact form was not found.', 'contact-form-7' ),
array( 'status' => 404 )
);
}
$result = $item->delete();
if ( ! $result ) {
return new WP_Error( 'wpcf7_cannot_delete',
__( 'There was an error deleting the contact form.', 'contact-form-7' ),
array( 'status' => 500 )
);
}
$response = array( 'deleted' => true );
return rest_ensure_response( $response );
}
public function create_feedback( WP_REST_Request $request ) {
$content_type = $request->get_header( 'Content-Type' ) ?? '';
if ( ! str_starts_with( $content_type, 'multipart/form-data' ) ) {
return new WP_Error( 'wpcf7_unsupported_media_type',
__( 'The request payload format is not supported.', 'contact-form-7' ),
array( 'status' => 415 )
);
}
$url_params = $request->get_url_params();
$item = null;
if ( ! empty( $url_params['id'] ) ) {
$item = wpcf7_contact_form( $url_params['id'] );
}
if ( ! $item ) {
return new WP_Error( 'wpcf7_not_found',
__( 'The requested contact form was not found.', 'contact-form-7' ),
array( 'status' => 404 )
);
}
$unit_tag = wpcf7_sanitize_unit_tag(
$request->get_param( '_wpcf7_unit_tag' )
);
if ( empty( $unit_tag ) ) {
return new WP_Error( 'wpcf7_unit_tag_not_found',
__( 'There is no valid unit tag.', 'contact-form-7' ),
array( 'status' => 400 )
);
}
$result = $item->submit();
$response = array_merge( $result, array(
'into' => sprintf( '#%s', $unit_tag ),
'invalid_fields' => array(),
) );
if ( ! empty( $result['invalid_fields'] ) ) {
$invalid_fields = array();
foreach ( (array) $result['invalid_fields'] as $name => $field ) {
if ( ! wpcf7_is_name( $name ) ) {
continue;
}
$name = strtr( $name, '.', '_' );
$invalid_fields[] = array(
'field' => $name,
'message' => $field['reason'],
'idref' => $field['idref'],
'error_id' => sprintf(
'%1$s-ve-%2$s',
$unit_tag,
$name
),
);
}
$response['invalid_fields'] = $invalid_fields;
}
$response = wpcf7_apply_filters_deprecated(
'wpcf7_ajax_json_echo',
array( $response, $result ),
'5.2',
'wpcf7_feedback_response'
);
$response = apply_filters( 'wpcf7_feedback_response', $response, $result );
return rest_ensure_response( $response );
}
public function get_schema( WP_REST_Request $request ) {
$url_params = $request->get_url_params();
$item = null;
if ( ! empty( $url_params['id'] ) ) {
$item = wpcf7_contact_form( $url_params['id'] );
}
if ( ! $item ) {
return new WP_Error( 'wpcf7_not_found',
__( 'The requested contact form was not found.', 'contact-form-7' ),
array( 'status' => 404 )
);
}
$schema = $item->get_schema();
$response = isset( $schema ) ? $schema->to_array() : array();
return rest_ensure_response( $response );
}
public function get_refill( WP_REST_Request $request ) {
$id = (int) $request->get_param( 'id' );
$item = wpcf7_contact_form( $id );
if ( ! $item ) {
return new WP_Error( 'wpcf7_not_found',
__( 'The requested contact form was not found.', 'contact-form-7' ),
array( 'status' => 404 )
);
}
$response = wpcf7_apply_filters_deprecated(
'wpcf7_ajax_onload',
array( array() ),
'5.2',
'wpcf7_refill_response'
);
$response = apply_filters( 'wpcf7_refill_response', array() );
return rest_ensure_response( $response );
}
private function get_properties( WPCF7_ContactForm $contact_form ) {
$properties = $contact_form->get_properties();
$properties['form'] = array(
'content' => (string) $properties['form'],
'fields' => array_map(
static function ( WPCF7_FormTag $form_tag ) {
return array(
'type' => $form_tag->type,
'basetype' => $form_tag->basetype,
'name' => $form_tag->name,
'options' => $form_tag->options,
'raw_values' => $form_tag->raw_values,
'labels' => $form_tag->labels,
'values' => $form_tag->values,
'pipes' => $form_tag->pipes instanceof WPCF7_Pipes
? $form_tag->pipes->to_array()
: $form_tag->pipes,
'content' => $form_tag->content,
);
},
$contact_form->scan_form_tags()
),
);
$properties['additional_settings'] = array(
'content' => (string) $properties['additional_settings'],
'settings' => array_filter( array_map(
static function ( $setting ) {
$pattern = '/^([a-zA-Z0-9_]+)[\t ]*:(.*)$/';
if ( preg_match( $pattern, $setting, $matches ) ) {
$name = trim( $matches[1] );
$value = trim( $matches[2] );
if ( in_array( $value, array( 'on', 'true' ), true ) ) {
$value = true;
} elseif ( in_array( $value, array( 'off', 'false' ), true ) ) {
$value = false;
}
return array( $name, $value );
}
return false;
},
explode( "\n", $properties['additional_settings'] )
) ),
);
return $properties;
}
private function get_argument_schema() {
return array(
'id' => array(
'description' => __( 'Unique identifier for the contact form.', 'contact-form-7' ),
'type' => 'integer',
'required' => true,
),
);
}
}

View File

@ -0,0 +1,108 @@
<?php
/**
* All the functions and classes in this file are deprecated.
* You should not use them. The functions and classes will be
* removed in a later version.
*/
function wpcf7_add_shortcode( $tag, $callback, $has_name = false ) {
wpcf7_deprecated_function( __FUNCTION__, '4.6', 'wpcf7_add_form_tag' );
return wpcf7_add_form_tag( $tag, $callback, $has_name );
}
function wpcf7_remove_shortcode( $tag ) {
wpcf7_deprecated_function( __FUNCTION__, '4.6', 'wpcf7_remove_form_tag' );
return wpcf7_remove_form_tag( $tag );
}
function wpcf7_do_shortcode( $content ) {
wpcf7_deprecated_function( __FUNCTION__, '4.6',
'wpcf7_replace_all_form_tags' );
return wpcf7_replace_all_form_tags( $content );
}
function wpcf7_scan_shortcode( $cond = null ) {
wpcf7_deprecated_function( __FUNCTION__, '4.6', 'wpcf7_scan_form_tags' );
return wpcf7_scan_form_tags( $cond );
}
class WPCF7_ShortcodeManager {
private static $form_tags_manager;
private function __construct() {}
public static function get_instance() {
wpcf7_deprecated_function( __METHOD__, '4.6',
'WPCF7_FormTagsManager::get_instance'
);
self::$form_tags_manager = WPCF7_FormTagsManager::get_instance();
return new self();
}
public function get_scanned_tags() {
wpcf7_deprecated_function( __METHOD__, '4.6',
'WPCF7_FormTagsManager::get_scanned_tags'
);
return self::$form_tags_manager->get_scanned_tags();
}
public function add_shortcode( $tag, $callback, $has_name = false ) {
wpcf7_deprecated_function( __METHOD__, '4.6',
'WPCF7_FormTagsManager::add'
);
return self::$form_tags_manager->add( $tag, $callback, $has_name );
}
public function remove_shortcode( $tag ) {
wpcf7_deprecated_function( __METHOD__, '4.6',
'WPCF7_FormTagsManager::remove'
);
return self::$form_tags_manager->remove( $tag );
}
public function normalize_shortcode( $content ) {
wpcf7_deprecated_function( __METHOD__, '4.6',
'WPCF7_FormTagsManager::normalize'
);
return self::$form_tags_manager->normalize( $content );
}
public function do_shortcode( $content, $exec = true ) {
wpcf7_deprecated_function( __METHOD__, '4.6',
'WPCF7_FormTagsManager::replace_all'
);
if ( $exec ) {
return self::$form_tags_manager->replace_all( $content );
} else {
return self::$form_tags_manager->scan( $content );
}
}
public function scan_shortcode( $content ) {
wpcf7_deprecated_function( __METHOD__, '4.6',
'WPCF7_FormTagsManager::scan'
);
return self::$form_tags_manager->scan( $content );
}
}
class WPCF7_Shortcode extends WPCF7_FormTag {
public function __construct( $tag ) {
wpcf7_deprecated_function( 'WPCF7_Shortcode', '4.6', 'WPCF7_FormTag' );
parent::__construct( $tag );
}
}

View File

@ -0,0 +1,271 @@
<?php
/**
** Special Mail Tags
** https://contactform7.com/special-mail-tags/
**/
add_filter( 'wpcf7_special_mail_tags', 'wpcf7_special_mail_tag', 10, 4 );
/**
* Returns output string of a special mail-tag.
*
* @param string $output The string to be output.
* @param string $name The tag name of the special mail-tag.
* @param bool $html Whether the mail-tag is used in an HTML content.
* @param WPCF7_MailTag $mail_tag An object representation of the mail-tag.
* @return string Output of the given special mail-tag.
*/
function wpcf7_special_mail_tag( $output, $name, $html, $mail_tag = null ) {
if ( ! $mail_tag instanceof WPCF7_MailTag ) {
wpcf7_doing_it_wrong(
sprintf( '%s()', __FUNCTION__ ),
__( 'The fourth parameter ($mail_tag) must be an instance of the WPCF7_MailTag class.', 'contact-form-7' ),
'5.2.2'
);
}
$name = preg_replace( '/^wpcf7\./', '_', $name ); // for back-compat
$submission = WPCF7_Submission::get_instance();
if ( ! $submission ) {
return $output;
}
if ( '_remote_ip' === $name ) {
if ( $remote_ip = $submission->get_meta( 'remote_ip' ) ) {
return $remote_ip;
} else {
return '';
}
}
if ( '_user_agent' === $name ) {
if ( $user_agent = $submission->get_meta( 'user_agent' ) ) {
return $html ? esc_html( $user_agent ) : $user_agent;
} else {
return '';
}
}
if ( '_url' === $name ) {
if ( $url = $submission->get_meta( 'url' ) ) {
return $url;
} else {
return '';
}
}
if ( '_date' === $name or '_time' === $name ) {
if ( $timestamp = $submission->get_meta( 'timestamp' ) ) {
if ( '_date' === $name ) {
return wp_date( get_option( 'date_format' ), $timestamp );
}
if ( '_time' === $name ) {
return wp_date( get_option( 'time_format' ), $timestamp );
}
}
return '';
}
if ( '_invalid_fields' === $name ) {
return (string) count( $submission->get_invalid_fields() );
}
if ( '_contact_form_title' === $name ) {
$contact_form = $submission->get_contact_form();
return $html
? esc_html( $contact_form->title() )
: $contact_form->title();
}
return $output;
}
add_filter( 'wpcf7_special_mail_tags', 'wpcf7_post_related_smt', 10, 4 );
/**
* Returns output string of a special mail-tag.
*
* @param string $output The string to be output.
* @param string $name The tag name of the special mail-tag.
* @param bool $html Whether the mail-tag is used in an HTML content.
* @param WPCF7_MailTag $mail_tag An object representation of the mail-tag.
* @return string Output of the given special mail-tag.
*/
function wpcf7_post_related_smt( $output, $name, $html, $mail_tag = null ) {
if ( ! $mail_tag instanceof WPCF7_MailTag ) {
wpcf7_doing_it_wrong(
sprintf( '%s()', __FUNCTION__ ),
__( 'The fourth parameter ($mail_tag) must be an instance of the WPCF7_MailTag class.', 'contact-form-7' ),
'5.2.2'
);
}
if ( ! str_starts_with( $name, '_post_' ) ) {
return $output;
}
$submission = WPCF7_Submission::get_instance();
if ( ! $submission ) {
return $output;
}
$post_id = (int) $submission->get_meta( 'container_post_id' );
if ( ! $post_id or ! $post = get_post( $post_id ) ) {
return '';
}
if ( '_post_id' === $name ) {
return (string) $post->ID;
}
if ( '_post_name' === $name ) {
return $post->post_name;
}
if ( '_post_title' === $name ) {
return $html ? esc_html( $post->post_title ) : $post->post_title;
}
if ( '_post_url' === $name ) {
return get_permalink( $post->ID );
}
$user = new WP_User( $post->post_author );
if ( '_post_author' === $name ) {
return $user->display_name;
}
if ( '_post_author_email' === $name ) {
return $user->user_email;
}
return $output;
}
add_filter( 'wpcf7_special_mail_tags', 'wpcf7_site_related_smt', 10, 4 );
/**
* Returns output string of a special mail-tag.
*
* @param string $output The string to be output.
* @param string $name The tag name of the special mail-tag.
* @param bool $html Whether the mail-tag is used in an HTML content.
* @param WPCF7_MailTag $mail_tag An object representation of the mail-tag.
* @return string Output of the given special mail-tag.
*/
function wpcf7_site_related_smt( $output, $name, $html, $mail_tag = null ) {
if ( ! $mail_tag instanceof WPCF7_MailTag ) {
wpcf7_doing_it_wrong(
sprintf( '%s()', __FUNCTION__ ),
__( 'The fourth parameter ($mail_tag) must be an instance of the WPCF7_MailTag class.', 'contact-form-7' ),
'5.2.2'
);
}
$filter = $html ? 'display' : 'raw';
if ( '_site_title' === $name ) {
$output = get_bloginfo( 'name', $filter );
if ( ! $html ) {
$output = wp_specialchars_decode( $output, ENT_QUOTES );
}
return $output;
}
if ( '_site_description' === $name ) {
$output = get_bloginfo( 'description', $filter );
if ( ! $html ) {
$output = wp_specialchars_decode( $output, ENT_QUOTES );
}
return $output;
}
if ( '_site_url' === $name ) {
return get_bloginfo( 'url', $filter );
}
if ( '_site_domain' === $name ) {
$url = get_bloginfo( 'url', $filter );
$host = wp_parse_url( $url, PHP_URL_HOST );
if ( null === $host ) {
return '';
}
if ( str_starts_with( $host, 'www.' ) ) {
$host = substr( $host, 4 );
}
return $host;
}
if ( '_site_admin_email' === $name ) {
return get_bloginfo( 'admin_email', $filter );
}
return $output;
}
add_filter( 'wpcf7_special_mail_tags', 'wpcf7_user_related_smt', 10, 4 );
/**
* Returns output string of a special mail-tag.
*
* @param string $output The string to be output.
* @param string $name The tag name of the special mail-tag.
* @param bool $html Whether the mail-tag is used in an HTML content.
* @param WPCF7_MailTag $mail_tag An object representation of the mail-tag.
* @return string Output of the given special mail-tag.
*/
function wpcf7_user_related_smt( $output, $name, $html, $mail_tag = null ) {
if ( ! $mail_tag instanceof WPCF7_MailTag ) {
wpcf7_doing_it_wrong(
sprintf( '%s()', __FUNCTION__ ),
__( 'The fourth parameter ($mail_tag) must be an instance of the WPCF7_MailTag class.', 'contact-form-7' ),
'5.2.2'
);
}
if ( ! str_starts_with( $name, '_user_' ) or '_user_agent' === $name ) {
return $output;
}
$submission = WPCF7_Submission::get_instance();
if ( ! $submission ) {
return $output;
}
$user_id = (int) $submission->get_meta( 'current_user_id' );
if ( ! $user_id ) {
return '';
}
$primary_props = array( 'user_login', 'user_email', 'user_url' );
$opt = ltrim( $name, '_' );
$opt = in_array( $opt, $primary_props, true ) ? $opt : substr( $opt, 5 );
$user = new WP_User( $user_id );
if ( $user->has_prop( $opt ) ) {
return (string) $user->get( $opt );
}
return '';
}

View File

@ -0,0 +1,927 @@
<?php
/**
* Class representing contact form submission.
*/
class WPCF7_Submission {
use WPCF7_PocketHolder;
private static $instance;
private $contact_form;
private $status = 'init';
private $posted_data = array();
private $posted_data_hash = null;
private $skip_spam_check = false;
private $uploaded_files = array();
private $extra_attachments = array();
private $skip_mail = false;
private $response = '';
private $invalid_fields = array();
private $meta = array();
private $consent = array();
private $spam_log = array();
private $result_props = array();
/**
* Returns the singleton instance of this class.
*/
public static function get_instance( $contact_form = null, $options = '' ) {
if ( $contact_form instanceof WPCF7_ContactForm ) {
if ( empty( self::$instance ) ) {
self::$instance = new self( $contact_form, $options );
self::$instance->proceed();
return self::$instance;
} else {
return null;
}
} else {
if ( empty( self::$instance ) ) {
return null;
} else {
return self::$instance;
}
}
}
/**
* Returns true if this submission is created via WP REST API.
*/
public static function is_restful() {
return wp_is_serving_rest_request();
}
/**
* Constructor.
*/
private function __construct( WPCF7_ContactForm $contact_form, $options = '' ) {
$options = wp_parse_args( $options, array(
'skip_mail' => false,
) );
$this->contact_form = $contact_form;
$this->skip_mail = (bool) $options['skip_mail'];
}
/**
* Destructor.
*/
public function __destruct() {
$this->remove_uploaded_files();
}
/**
* The main logic of submission.
*/
private function proceed() {
$callback = function () {
$contact_form = $this->contact_form;
$this->setup_meta_data();
$this->setup_posted_data();
if ( $this->is( 'init' ) and ! $this->validate() ) {
$this->set_status( 'validation_failed' );
$this->set_response( $contact_form->message( 'validation_error' ) );
}
if ( $this->is( 'init' ) and ! $this->accepted() ) {
$this->set_status( 'acceptance_missing' );
$this->set_response( $contact_form->message( 'accept_terms' ) );
}
if ( $this->is( 'init' ) and $this->spam() ) {
$this->set_status( 'spam' );
$this->set_response( $contact_form->message( 'spam' ) );
}
if ( $this->is( 'init' ) and ! $this->unship_uploaded_files() ) {
$this->set_status( 'validation_failed' );
$this->set_response( $contact_form->message( 'validation_error' ) );
}
if ( $this->is( 'init' ) ) {
$abort = ! $this->before_send_mail();
if ( $abort ) {
if ( $this->is( 'init' ) ) {
$this->set_status( 'aborted' );
}
if ( '' === $this->get_response() ) {
$this->set_response( $contact_form->filter_message(
__( 'Sending mail has been aborted.', 'contact-form-7' ) )
);
}
} elseif ( $this->mail() ) {
$this->set_status( 'mail_sent' );
$this->set_response( $contact_form->message( 'mail_sent_ok' ) );
do_action( 'wpcf7_mail_sent', $contact_form );
} else {
$this->set_status( 'mail_failed' );
$this->set_response( $contact_form->message( 'mail_sent_ng' ) );
do_action( 'wpcf7_mail_failed', $contact_form );
}
}
};
wpcf7_switch_locale( $this->contact_form->locale(), $callback );
}
/**
* Returns the current status property.
*/
public function get_status() {
return $this->status;
}
/**
* Sets the status property.
*
* @param string $status The status.
*/
public function set_status( $status ) {
if ( preg_match( '/^[a-z][0-9a-z_]+$/', $status ) ) {
$this->status = $status;
return true;
}
return false;
}
/**
* Returns true if the specified status is identical to the current
* status property.
*
* @param string $status The status to compare.
*/
public function is( $status ) {
return $this->status === $status;
}
/**
* Returns an associative array of submission result properties.
*
* @return array Submission result properties.
*/
public function get_result() {
$result = array_merge( $this->result_props, array(
'status' => $this->get_status(),
'message' => $this->get_response(),
) );
if ( $this->is( 'validation_failed' ) ) {
$result['invalid_fields'] = $this->get_invalid_fields();
}
switch ( $this->get_status() ) {
case 'init':
case 'validation_failed':
case 'acceptance_missing':
case 'spam':
$result['posted_data_hash'] = '';
break;
default:
$result['posted_data_hash'] = $this->get_posted_data_hash();
break;
}
$result = apply_filters( 'wpcf7_submission_result', $result, $this );
return $result;
}
/**
* Adds items to the array of submission result properties.
*
* @param string|array|object $data Value to add to result properties.
* @return array Added result properties.
*/
public function add_result_props( $data = '' ) {
$data = wp_parse_args( $data, array() );
$this->result_props = array_merge( $this->result_props, $data );
return $data;
}
/**
* Retrieves the response property.
*
* @return string The current response property value.
*/
public function get_response() {
return $this->response;
}
/**
* Sets the response property.
*
* @param string $response New response property value.
*/
public function set_response( $response ) {
$this->response = $response;
return true;
}
/**
* Retrieves the contact form property.
*
* @return WPCF7_ContactForm A contact form object.
*/
public function get_contact_form() {
return $this->contact_form;
}
/**
* Search an invalid field by field name.
*
* @param string $name The field name.
* @return array|bool An associative array of validation error
* or false when no invalid field.
*/
public function get_invalid_field( $name ) {
return $this->invalid_fields[$name] ?? false;
}
/**
* Retrieves all invalid fields.
*
* @return array Invalid fields.
*/
public function get_invalid_fields() {
return $this->invalid_fields;
}
/**
* Retrieves meta information.
*
* @param string $name Name of the meta information.
* @return string|null The meta information of the given name if it exists,
* null otherwise.
*/
public function get_meta( $name ) {
return $this->meta[$name] ?? null;
}
/**
* Collects meta information about this submission.
*/
private function setup_meta_data() {
$this->meta = array(
'timestamp' => time(),
'remote_ip' => $this->get_remote_ip_addr(),
'remote_port' => wpcf7_superglobal_server( 'REMOTE_PORT' ),
'user_agent' => wpcf7_superglobal_server( 'HTTP_USER_AGENT' ),
'url' => $this->get_request_url(),
'unit_tag' => wpcf7_sanitize_unit_tag(
wpcf7_superglobal_post( '_wpcf7_unit_tag' )
),
'container_post_id' => absint(
wpcf7_superglobal_post( '_wpcf7_container_post' )
),
'current_user_id' => get_current_user_id(),
'do_not_store' => $this->contact_form->is_true( 'do_not_store' ),
);
return $this->meta;
}
/**
* Retrieves user input data through this submission.
*
* @param string $name Optional field name.
* @return string|array|null The user input of the field, or array of all
* fields values if no field name specified.
*/
public function get_posted_data( $name = '' ) {
if ( ! empty( $name ) ) {
return $this->posted_data[$name] ?? null;
}
return $this->posted_data;
}
/**
* Retrieves a user input string value through the specified field.
*
* @param string $name Field name.
* @return string The user input. If the input is an array,
* the first item in the array.
*/
public function get_posted_string( $name ) {
$data = $this->get_posted_data( $name );
$data = wpcf7_array_flatten( $data );
if ( empty( $data ) ) {
return '';
}
// Returns the first array item.
return trim( reset( $data ) );
}
/**
* Constructs posted data property based on user input values.
*/
private function setup_posted_data() {
$posted_data = array_filter(
(array) $_POST,
static function ( $key ) {
return ! str_starts_with( $key, '_' );
},
ARRAY_FILTER_USE_KEY
);
$posted_data = wp_unslash( $posted_data );
$posted_data = $this->sanitize_posted_data( $posted_data );
$tags = $this->contact_form->scan_form_tags( array(
'feature' => array(
'name-attr',
'! not-for-mail',
),
) );
$tags = array_reduce( $tags, static function ( $carry, $tag ) {
if ( $tag->name and ! isset( $carry[$tag->name] ) ) {
$carry[$tag->name] = $tag;
}
return $carry;
}, array() );
foreach ( $tags as $tag ) {
$value_orig = $value = $posted_data[$tag->name] ?? '';
if ( wpcf7_form_tag_supports( $tag->type, 'selectable-values' ) ) {
$value = ( '' === $value ) ? array() : (array) $value;
if ( WPCF7_USE_PIPE ) {
$pipes = $this->contact_form->get_pipes( $tag->name );
$value = array_map( static function ( $value ) use ( $pipes ) {
return $pipes->do_pipe( $value );
}, $value );
}
}
$value = apply_filters( "wpcf7_posted_data_{$tag->type}",
$value,
$value_orig,
$tag
);
$posted_data[$tag->name] = $value;
if ( $tag->has_option( 'consent_for:storage' ) and empty( $value ) ) {
$this->meta['do_not_store'] = true;
}
}
$this->posted_data = apply_filters( 'wpcf7_posted_data', $posted_data );
$this->posted_data_hash = $this->create_posted_data_hash();
return $this->posted_data;
}
/**
* Sanitizes user input data.
*/
private function sanitize_posted_data( $value ) {
return map_deep( $value, static function ( $val ) {
$val = (string) $val;
$val = wp_check_invalid_utf8( $val );
$val = wp_kses_no_null( $val );
$val = wpcf7_strip_whitespaces( $val );
return $val;
} );
}
/**
* Returns the time-dependent variable for hash creation.
*
* @return float Float value rounded up to the next highest integer.
*/
private function posted_data_hash_tick() {
return ceil( time() / ( HOUR_IN_SECONDS / 2 ) );
}
/**
* Creates a hash string based on posted data, the remote IP address,
* contact form location, and window of time.
*
* @param string $tick Optional. If not specified, result of
* posted_data_hash_tick() will be used.
* @return string The hash.
*/
private function create_posted_data_hash( $tick = '' ) {
if ( '' === $tick ) {
$tick = $this->posted_data_hash_tick();
}
$hash = wp_hash(
wpcf7_flat_join( array_merge(
array(
$tick,
$this->get_meta( 'remote_ip' ),
$this->get_meta( 'unit_tag' ),
),
$this->posted_data
) ),
'wpcf7_submission'
);
return $hash;
}
/**
* Returns the hash string created for this submission.
*
* @return string The current hash for the submission.
*/
public function get_posted_data_hash() {
return $this->posted_data_hash;
}
/**
* Verifies that the given string is equivalent to the posted data hash.
*
* @param string $hash Optional. This value will be compared to the
* current posted data hash for the submission. If not
* specified, the value of $_POST['_wpcf7_posted_data_hash']
* will be used.
* @return int|bool 1 if $hash is created 0-30 minutes ago,
* 2 if $hash is created 30-60 minutes ago,
* false if $hash is invalid.
*/
public function verify_posted_data_hash( $hash = '' ) {
if ( '' === $hash ) {
$hash = wpcf7_superglobal_post( '_wpcf7_posted_data_hash' );
}
if ( '' === $hash ) {
return false;
}
$tick = $this->posted_data_hash_tick();
// Hash created 0-30 minutes ago.
$expected_1 = $this->create_posted_data_hash( $tick );
if ( hash_equals( $expected_1, $hash ) ) {
return 1;
}
// Hash created 30-60 minutes ago.
$expected_2 = $this->create_posted_data_hash( $tick - 1 );
if ( hash_equals( $expected_2, $hash ) ) {
return 2;
}
return false;
}
/**
* Retrieves the remote IP address of this submission.
*/
private function get_remote_ip_addr() {
$ip_addr = wpcf7_superglobal_server( 'REMOTE_ADDR' );
if ( ! WP_Http::is_ip_address( $ip_addr ) ) {
$ip_addr = '';
}
return apply_filters( 'wpcf7_remote_ip_addr', $ip_addr );
}
/**
* Retrieves the request URL of this submission.
*/
private function get_request_url() {
$home_url = untrailingslashit( home_url() );
if ( self::is_restful() ) {
$referer = wpcf7_superglobal_server( 'HTTP_REFERER' );
if ( $referer and str_starts_with( $referer, $home_url ) ) {
return sanitize_url( $referer );
}
}
$url = preg_replace( '%(?<!:|/)/.*$%', '', $home_url )
. wpcf7_get_request_uri();
return $url;
}
/**
* Runs user input validation.
*
* @return bool True if no invalid field is found.
*/
private function validate() {
if ( $this->invalid_fields ) {
return false;
}
$result = new WPCF7_Validation();
$this->contact_form->validate_schema(
array(
'text' => true,
'file' => false,
'field' => array(),
),
$result
);
$tags = $this->contact_form->scan_form_tags( array(
'feature' => '! file-uploading',
) );
foreach ( $tags as $tag ) {
$type = $tag->type;
$result = apply_filters( "wpcf7_validate_{$type}", $result, $tag );
}
$result = apply_filters( 'wpcf7_validate', $result, $tags );
$this->invalid_fields = $result->get_invalid_fields();
return $result->is_valid();
}
/**
* Returns true if user consent is obtained.
*/
private function accepted() {
return apply_filters( 'wpcf7_acceptance', true, $this );
}
/**
* Adds user consent data to this submission.
*
* @param string $name Field name.
* @param string $conditions Conditions of consent.
*/
public function add_consent( $name, $conditions ) {
$this->consent[$name] = $conditions;
return true;
}
/**
* Collects user consent data.
*
* @return array User consent data.
*/
public function collect_consent() {
return (array) $this->consent;
}
/**
* Executes spam protections.
*
* @return bool True if spam captured.
*/
private function spam() {
$spam = false;
$skip_spam_check = apply_filters( 'wpcf7_skip_spam_check',
$this->skip_spam_check,
$this
);
if ( $skip_spam_check ) {
return $spam;
}
if (
$this->contact_form->is_true( 'subscribers_only' ) and
current_user_can( 'wpcf7_submit', $this->contact_form->id() )
) {
return $spam;
}
$user_agent = (string) $this->get_meta( 'user_agent' );
if ( strlen( $user_agent ) < 2 ) {
$spam = true;
$this->add_spam_log( array(
'agent' => 'wpcf7',
'reason' => __( 'User-Agent string is unnaturally short.', 'contact-form-7' ),
) );
}
if ( ! $this->verify_nonce() ) {
$spam = true;
$this->add_spam_log( array(
'agent' => 'wpcf7',
'reason' => __( 'Submitted nonce is invalid.', 'contact-form-7' ),
) );
}
return apply_filters( 'wpcf7_spam', $spam, $this );
}
/**
* Adds a spam log.
*
* @link https://contactform7.com/2019/05/31/why-is-this-message-marked-spam/
*/
public function add_spam_log( $data = '' ) {
$data = wp_parse_args( $data, array(
'agent' => '',
'reason' => '',
) );
$this->spam_log[] = $data;
}
/**
* Retrieves the spam logging data.
*
* @return array Spam logging data.
*/
public function get_spam_log() {
return $this->spam_log;
}
/**
* Verifies that a correct security nonce was used.
*/
private function verify_nonce() {
if ( ! $this->contact_form->nonce_is_active() or ! is_user_logged_in() ) {
return true;
}
$nonce = wpcf7_superglobal_post( '_wpnonce' );
return wpcf7_verify_nonce( $nonce );
}
/**
* Function called just before sending email.
*/
private function before_send_mail() {
$abort = false;
do_action_ref_array( 'wpcf7_before_send_mail', array(
$this->contact_form,
&$abort,
$this,
) );
return ! $abort;
}
/**
* Sends emails based on user input values and contact form email templates.
*/
private function mail() {
$contact_form = $this->contact_form;
$skip_mail = apply_filters( 'wpcf7_skip_mail',
$this->skip_mail, $contact_form
);
if ( $skip_mail ) {
return true;
}
$result = WPCF7_Mail::send( $contact_form->prop( 'mail' ), 'mail' );
if ( $result ) {
$additional_mail = array();
if (
$mail_2 = $contact_form->prop( 'mail_2' ) and
$mail_2['active']
) {
$additional_mail['mail_2'] = $mail_2;
}
$additional_mail = apply_filters( 'wpcf7_additional_mail',
$additional_mail, $contact_form
);
foreach ( $additional_mail as $name => $template ) {
WPCF7_Mail::send( $template, $name );
}
return true;
}
return false;
}
/**
* Retrieves files uploaded through this submission.
*/
public function uploaded_files() {
return $this->uploaded_files;
}
/**
* Adds a file to the uploaded files array.
*
* @param string $name Field name.
* @param string|array $file_path File path or array of file paths.
*/
private function add_uploaded_file( $name, $file_path ) {
if ( ! wpcf7_is_name( $name ) ) {
return false;
}
$paths = (array) $file_path;
$uploaded_files = array();
$hash_strings = array();
foreach ( $paths as $path ) {
if ( @is_file( $path ) and @is_readable( $path ) ) {
$uploaded_files[] = $path;
$hash_strings[] = hash_file( 'sha256', $path );
}
}
$this->uploaded_files[$name] = $uploaded_files;
if ( empty( $this->posted_data[$name] ) ) {
$this->posted_data[$name] = implode( ' ', $hash_strings );
}
}
/**
* Removes uploaded files.
*/
private function remove_uploaded_files() {
$filesystem = WPCF7_Filesystem::get_instance();
foreach ( (array) $this->uploaded_files as $file_path ) {
foreach ( (array) $file_path as $path ) {
if ( wpcf7_is_file_path_in_content_dir( $path ) ) {
wpcf7_rmdir_p( $path );
// Remove parent dir if empty.
$filesystem->delete( dirname( $path ), false );
}
}
}
}
/**
* Moves uploaded files to the tmp directory and validates them.
*
* @return bool True if no invalid file is found.
*/
private function unship_uploaded_files() {
$result = new WPCF7_Validation();
$tags = $this->contact_form->scan_form_tags( array(
'feature' => 'file-uploading',
) );
foreach ( $tags as $tag ) {
if ( empty( $_FILES[$tag->name] ) ) {
continue;
}
$file = $_FILES[$tag->name];
$options = array(
'tag' => $tag,
'name' => $tag->name,
'required' => $tag->is_required(),
'filetypes' => $tag->get_option( 'filetypes' ),
'limit' => $tag->get_limit_option(),
'schema' => $this->contact_form->get_schema(),
);
$new_files = wpcf7_unship_uploaded_file( $file, $options );
if ( is_wp_error( $new_files ) ) {
$result->invalidate( $tag, $new_files );
} else {
$this->add_uploaded_file( $tag->name, $new_files );
}
$result = apply_filters(
"wpcf7_validate_{$tag->type}",
$result, $tag,
array(
'uploaded_files' => $new_files,
)
);
}
$this->invalid_fields = $result->get_invalid_fields();
return $result->is_valid();
}
/**
* Adds extra email attachment files that are independent from form fields.
*
* @param string|array $file_path A file path or an array of file paths.
* @param string $template Optional. The name of the template to which
* the files are attached.
* @return bool True if it succeeds to attach a file at least,
* or false otherwise.
*/
public function add_extra_attachments( $file_path, $template = 'mail' ) {
if ( ! did_action( 'wpcf7_before_send_mail' ) ) {
return false;
}
$extra_attachments = array();
foreach ( (array) $file_path as $path ) {
$path = path_join( WP_CONTENT_DIR, $path );
if ( file_exists( $path ) ) {
$extra_attachments[] = $path;
}
}
if ( empty( $extra_attachments ) ) {
return false;
}
if ( ! isset( $this->extra_attachments[$template] ) ) {
$this->extra_attachments[$template] = array();
}
$this->extra_attachments[$template] = array_merge(
$this->extra_attachments[$template],
$extra_attachments
);
return true;
}
/**
* Returns extra email attachment files.
*
* @param string $template An email template name.
* @return array Array of file paths.
*/
public function extra_attachments( $template ) {
if ( isset( $this->extra_attachments[$template] ) ) {
return (array) $this->extra_attachments[$template];
}
return array();
}
}

View File

@ -0,0 +1,6 @@
<?php
return array(
'dependencies' => array(),
'version' => WPCF7_VERSION,
);

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,207 @@
<?php
namespace Contactable\SWV;
use WP_Error;
/**
* The base class of SWV rules.
*/
abstract class Rule {
protected $properties = array();
public function __construct( $properties = '' ) {
$this->properties = wp_parse_args( $properties, array() );
}
/**
* Returns true if this rule matches the given context.
*
* @param array $context Context.
*/
public function matches( $context ) {
$field = $this->get_property( 'field' );
if ( ! empty( $context['field'] ) ) {
if ( $field and ! in_array( $field, (array) $context['field'], true ) ) {
return false;
}
}
return true;
}
/**
* Validates with this rule's logic.
*
* @param array $context Context.
*/
public function validate( $context ) {
return true;
}
/**
* Converts the properties to an array.
*
* @return array Array of properties.
*/
public function to_array() {
$properties = (array) $this->properties;
if ( defined( 'static::rule_name' ) and static::rule_name ) {
$properties = array( 'rule' => static::rule_name ) + $properties;
}
return $properties;
}
/**
* Returns the property value specified by the given property name.
*
* @param string $name Property name.
* @return mixed Property value.
*/
public function get_property( $name ) {
if ( isset( $this->properties[$name] ) ) {
return $this->properties[$name];
}
}
/**
* Returns the default user input value from $_POST.
*
* @return mixed Default user input value.
*/
public function get_default_input() {
$field = $this->get_property( 'field' );
if ( isset( $_POST[$field] ) ) {
return wp_unslash( $_POST[$field] );
}
return '';
}
/**
* Returns the default user upload file from $_FILES.
*
* @return object Default user upload file.
*/
public function get_default_upload() {
$field = $this->get_property( 'field' );
if ( isset( $_FILES[$field] ) ) {
return (object) wp_unslash( $_FILES[$field] );
}
return (object) array();
}
/**
* Creates an error object. Returns false if the error property is omitted.
*/
protected function create_error() {
$error_code = defined( 'static::rule_name' )
? sprintf( 'swv_%s', static::rule_name )
: 'swv';
return new WP_Error(
$error_code,
(string) $this->get_property( 'error' ),
$this
);
}
}
/**
* The base class of SWV composite rules.
*/
abstract class CompositeRule extends Rule {
protected $rules = array();
/**
* Adds a sub-rule to this composite rule.
*
* @param Rule $rule Sub-rule to be added.
*/
public function add_rule( $rule ) {
if ( $rule instanceof Rule ) {
$this->rules[] = $rule;
}
}
/**
* Returns an iterator of sub-rules.
*/
public function rules() {
foreach ( $this->rules as $rule ) {
yield $rule;
}
}
/**
* Returns true if this rule matches the given context.
*
* @param array $context Context.
*/
public function matches( $context ) {
return true;
}
/**
* Validates with this rule's logic.
*
* @param array $context Context.
*/
public function validate( $context ) {
foreach ( $this->rules() as $rule ) {
if ( $rule->matches( $context ) ) {
$result = $rule->validate( $context );
if ( is_wp_error( $result ) ) {
return $result;
}
}
}
return true;
}
/**
* Converts the properties to an array.
*
* @return array Array of properties.
*/
public function to_array() {
$rules_arrays = array_map(
static function ( $rule ) {
return $rule->to_array();
},
$this->rules
);
return array_merge(
parent::to_array(),
array(
'rules' => $rules_arrays,
)
);
}
}

View File

@ -0,0 +1,35 @@
<?php
namespace Contactable\SWV;
class AllRule extends CompositeRule {
const rule_name = 'all';
public function matches( $context ) {
if ( false === parent::matches( $context ) ) {
return false;
}
return true;
}
public function validate( $context ) {
foreach ( $this->rules() as $rule ) {
if ( $rule->matches( $context ) ) {
$result = $rule->validate( $context );
if ( is_wp_error( $result ) ) {
if ( $result->get_error_message() ) {
return $result;
} else {
return $this->create_error();
}
}
}
}
return true;
}
}

View File

@ -0,0 +1,31 @@
<?php
namespace Contactable\SWV;
class AnyRule extends CompositeRule {
const rule_name = 'any';
public function matches( $context ) {
if ( false === parent::matches( $context ) ) {
return false;
}
return true;
}
public function validate( $context ) {
foreach ( $this->rules() as $rule ) {
if ( $rule->matches( $context ) ) {
$result = $rule->validate( $context );
if ( ! is_wp_error( $result ) ) {
return true;
}
}
}
return $this->create_error();
}
}

View File

@ -0,0 +1,36 @@
<?php
namespace Contactable\SWV;
class DateRule extends Rule {
const rule_name = 'date';
public function matches( $context ) {
if ( false === parent::matches( $context ) ) {
return false;
}
if ( empty( $context['text'] ) ) {
return false;
}
return true;
}
public function validate( $context ) {
$input = $this->get_default_input();
$input = wpcf7_array_flatten( $input );
$input = wpcf7_strip_whitespaces( $input );
$input = wpcf7_exclude_blank( $input );
foreach ( $input as $i ) {
if ( ! wpcf7_is_date( $i ) ) {
return $this->create_error();
}
}
return true;
}
}

View File

@ -0,0 +1,46 @@
<?php
namespace Contactable\SWV;
class DayofweekRule extends Rule {
const rule_name = 'dayofweek';
public function matches( $context ) {
if ( false === parent::matches( $context ) ) {
return false;
}
if ( empty( $context['text'] ) ) {
return false;
}
return true;
}
public function validate( $context ) {
$input = $this->get_default_input();
$input = wpcf7_array_flatten( $input );
$input = wpcf7_strip_whitespaces( $input );
$input = wpcf7_exclude_blank( $input );
$acceptable_values = (array) $this->get_property( 'accept' );
$acceptable_values = array_map( 'intval', $acceptable_values );
$acceptable_values = array_filter( $acceptable_values );
$acceptable_values = array_unique( $acceptable_values );
foreach ( $input as $i ) {
if ( wpcf7_is_date( $i ) ) {
$datetime = date_create_immutable( $i, wp_timezone() );
$dow = (int) $datetime->format( 'N' );
if ( ! in_array( $dow, $acceptable_values, true ) ) {
return $this->create_error();
}
}
}
return true;
}
}

View File

@ -0,0 +1,36 @@
<?php
namespace Contactable\SWV;
class EmailRule extends Rule {
const rule_name = 'email';
public function matches( $context ) {
if ( false === parent::matches( $context ) ) {
return false;
}
if ( empty( $context['text'] ) ) {
return false;
}
return true;
}
public function validate( $context ) {
$input = $this->get_default_input();
$input = wpcf7_array_flatten( $input );
$input = wpcf7_strip_whitespaces( $input );
$input = wpcf7_exclude_blank( $input );
foreach ( $input as $i ) {
if ( ! wpcf7_is_email( $i ) ) {
return $this->create_error();
}
}
return true;
}
}

View File

@ -0,0 +1,57 @@
<?php
namespace Contactable\SWV;
class EnumRule extends Rule {
const rule_name = 'enum';
public function matches( $context ) {
if ( false === parent::matches( $context ) ) {
return false;
}
if ( empty( $context['text'] ) ) {
return false;
}
return true;
}
public function validate( $context ) {
$input = $this->get_default_input();
$input = wpcf7_array_flatten( $input );
$input = wpcf7_strip_whitespaces( $input );
$input = wpcf7_exclude_blank( $input );
$acceptable_values = (array) $this->get_property( 'accept' );
$acceptable_values = array_map(
static function ( $val ) {
$val = strval( $val );
$val = wpcf7_normalize_newline( $val );
return $val;
},
$acceptable_values
);
$acceptable_values = array_unique( $acceptable_values );
$acceptable_values = array_filter( $acceptable_values,
static function ( $val ) {
return '' !== $val;
}
);
foreach ( $input as $i ) {
$i = wpcf7_normalize_newline( $i );
if ( ! in_array( $i, $acceptable_values, true ) ) {
return $this->create_error();
}
}
return true;
}
}

View File

@ -0,0 +1,60 @@
<?php
namespace Contactable\SWV;
class FileRule extends Rule {
const rule_name = 'file';
public function matches( $context ) {
if ( false === parent::matches( $context ) ) {
return false;
}
if ( empty( $context['file'] ) ) {
return false;
}
return true;
}
public function validate( $context ) {
$input = $this->get_default_upload()->name ?? '';
$input = wpcf7_array_flatten( $input );
$input = wpcf7_exclude_blank( $input );
$acceptable_filetypes = array();
foreach ( (array) $this->get_property( 'accept' ) as $accept ) {
if ( preg_match( '/^\.[a-z0-9]+$/i', $accept ) ) {
$acceptable_filetypes[] = strtolower( $accept );
} else {
foreach ( wpcf7_convert_mime_to_ext( $accept ) as $ext ) {
$acceptable_filetypes[] = sprintf(
'.%s',
strtolower( trim( $ext, ' .' ) )
);
}
}
}
$acceptable_filetypes = array_unique( $acceptable_filetypes );
foreach ( $input as $i ) {
$last_period_pos = strrpos( $i, '.' );
if ( false === $last_period_pos ) { // no period
return $this->create_error();
}
$suffix = strtolower( substr( $i, $last_period_pos ) );
if ( ! in_array( $suffix, $acceptable_filetypes, true ) ) {
return $this->create_error();
}
}
return true;
}
}

View File

@ -0,0 +1,42 @@
<?php
namespace Contactable\SWV;
class MaxDateRule extends Rule {
const rule_name = 'maxdate';
public function matches( $context ) {
if ( false === parent::matches( $context ) ) {
return false;
}
if ( empty( $context['text'] ) ) {
return false;
}
return true;
}
public function validate( $context ) {
$input = $this->get_default_input();
$input = wpcf7_array_flatten( $input );
$input = wpcf7_strip_whitespaces( $input );
$input = wpcf7_exclude_blank( $input );
$threshold = $this->get_property( 'threshold' );
if ( ! wpcf7_is_date( $threshold ) ) {
return true;
}
foreach ( $input as $i ) {
if ( wpcf7_is_date( $i ) and $threshold < $i ) {
return $this->create_error();
}
}
return true;
}
}

View File

@ -0,0 +1,39 @@
<?php
namespace Contactable\SWV;
class MaxFileSizeRule extends Rule {
const rule_name = 'maxfilesize';
public function matches( $context ) {
if ( false === parent::matches( $context ) ) {
return false;
}
if ( empty( $context['file'] ) ) {
return false;
}
return true;
}
public function validate( $context ) {
$input = $this->get_default_upload()->size ?? '';
$input = wpcf7_array_flatten( $input );
$input = wpcf7_exclude_blank( $input );
if ( empty( $input ) ) {
return true;
}
$threshold = $this->get_property( 'threshold' );
if ( $threshold < array_sum( $input ) ) {
return $this->create_error();
}
return true;
}
}

View File

@ -0,0 +1,40 @@
<?php
namespace Contactable\SWV;
class MaxItemsRule extends Rule {
const rule_name = 'maxitems';
public function matches( $context ) {
if ( false === parent::matches( $context ) ) {
return false;
}
if ( empty( $context['text'] ) ) {
return false;
}
return true;
}
public function validate( $context ) {
$input = $this->get_default_input();
$input = wpcf7_array_flatten( $input );
$input = wpcf7_strip_whitespaces( $input );
$input = wpcf7_exclude_blank( $input );
$threshold = $this->get_property( 'threshold' );
if ( ! wpcf7_is_number( $threshold ) ) {
return true;
}
if ( (int) $threshold < count( $input ) ) {
return $this->create_error();
}
return true;
}
}

View File

@ -0,0 +1,46 @@
<?php
namespace Contactable\SWV;
class MaxLengthRule extends Rule {
const rule_name = 'maxlength';
public function matches( $context ) {
if ( false === parent::matches( $context ) ) {
return false;
}
if ( empty( $context['text'] ) ) {
return false;
}
return true;
}
public function validate( $context ) {
$input = $this->get_default_input();
$input = wpcf7_array_flatten( $input );
$input = wpcf7_strip_whitespaces( $input );
$input = wpcf7_exclude_blank( $input );
if ( empty( $input ) ) {
return true;
}
$total = 0;
foreach ( $input as $i ) {
$total += wpcf7_count_code_units( $i );
}
$threshold = (int) $this->get_property( 'threshold' );
if ( $total <= $threshold ) {
return true;
} else {
return $this->create_error();
}
}
}

View File

@ -0,0 +1,42 @@
<?php
namespace Contactable\SWV;
class MaxNumberRule extends Rule {
const rule_name = 'maxnumber';
public function matches( $context ) {
if ( false === parent::matches( $context ) ) {
return false;
}
if ( empty( $context['text'] ) ) {
return false;
}
return true;
}
public function validate( $context ) {
$input = $this->get_default_input();
$input = wpcf7_array_flatten( $input );
$input = wpcf7_strip_whitespaces( $input );
$input = wpcf7_exclude_blank( $input );
$threshold = $this->get_property( 'threshold' );
if ( ! wpcf7_is_number( $threshold ) ) {
return true;
}
foreach ( $input as $i ) {
if ( wpcf7_is_number( $i ) and (float) $threshold < (float) $i ) {
return $this->create_error();
}
}
return true;
}
}

View File

@ -0,0 +1,42 @@
<?php
namespace Contactable\SWV;
class MinDateRule extends Rule {
const rule_name = 'mindate';
public function matches( $context ) {
if ( false === parent::matches( $context ) ) {
return false;
}
if ( empty( $context['text'] ) ) {
return false;
}
return true;
}
public function validate( $context ) {
$input = $this->get_default_input();
$input = wpcf7_array_flatten( $input );
$input = wpcf7_strip_whitespaces( $input );
$input = wpcf7_exclude_blank( $input );
$threshold = $this->get_property( 'threshold' );
if ( ! wpcf7_is_date( $threshold ) ) {
return true;
}
foreach ( $input as $i ) {
if ( wpcf7_is_date( $i ) and $i < $threshold ) {
return $this->create_error();
}
}
return true;
}
}

View File

@ -0,0 +1,39 @@
<?php
namespace Contactable\SWV;
class MinFileSizeRule extends Rule {
const rule_name = 'minfilesize';
public function matches( $context ) {
if ( false === parent::matches( $context ) ) {
return false;
}
if ( empty( $context['file'] ) ) {
return false;
}
return true;
}
public function validate( $context ) {
$input = $this->get_default_upload()->size ?? '';
$input = wpcf7_array_flatten( $input );
$input = wpcf7_exclude_blank( $input );
if ( empty( $input ) ) {
return true;
}
$threshold = $this->get_property( 'threshold' );
if ( array_sum( $input ) < $threshold ) {
return $this->create_error();
}
return true;
}
}

View File

@ -0,0 +1,40 @@
<?php
namespace Contactable\SWV;
class MinItemsRule extends Rule {
const rule_name = 'minitems';
public function matches( $context ) {
if ( false === parent::matches( $context ) ) {
return false;
}
if ( empty( $context['text'] ) ) {
return false;
}
return true;
}
public function validate( $context ) {
$input = $this->get_default_input();
$input = wpcf7_array_flatten( $input );
$input = wpcf7_strip_whitespaces( $input );
$input = wpcf7_exclude_blank( $input );
$threshold = $this->get_property( 'threshold' );
if ( ! wpcf7_is_number( $threshold ) ) {
return true;
}
if ( count( $input ) < (int) $threshold ) {
return $this->create_error();
}
return true;
}
}

View File

@ -0,0 +1,46 @@
<?php
namespace Contactable\SWV;
class MinLengthRule extends Rule {
const rule_name = 'minlength';
public function matches( $context ) {
if ( false === parent::matches( $context ) ) {
return false;
}
if ( empty( $context['text'] ) ) {
return false;
}
return true;
}
public function validate( $context ) {
$input = $this->get_default_input();
$input = wpcf7_array_flatten( $input );
$input = wpcf7_strip_whitespaces( $input );
$input = wpcf7_exclude_blank( $input );
if ( empty( $input ) ) {
return true;
}
$total = 0;
foreach ( $input as $i ) {
$total += wpcf7_count_code_units( $i );
}
$threshold = (int) $this->get_property( 'threshold' );
if ( $threshold <= $total ) {
return true;
} else {
return $this->create_error();
}
}
}

View File

@ -0,0 +1,42 @@
<?php
namespace Contactable\SWV;
class MinNumberRule extends Rule {
const rule_name = 'minnumber';
public function matches( $context ) {
if ( false === parent::matches( $context ) ) {
return false;
}
if ( empty( $context['text'] ) ) {
return false;
}
return true;
}
public function validate( $context ) {
$input = $this->get_default_input();
$input = wpcf7_array_flatten( $input );
$input = wpcf7_strip_whitespaces( $input );
$input = wpcf7_exclude_blank( $input );
$threshold = $this->get_property( 'threshold' );
if ( ! wpcf7_is_number( $threshold ) ) {
return true;
}
foreach ( $input as $i ) {
if ( wpcf7_is_number( $i ) and (float) $i < (float) $threshold ) {
return $this->create_error();
}
}
return true;
}
}

View File

@ -0,0 +1,36 @@
<?php
namespace Contactable\SWV;
class NumberRule extends Rule {
const rule_name = 'number';
public function matches( $context ) {
if ( false === parent::matches( $context ) ) {
return false;
}
if ( empty( $context['text'] ) ) {
return false;
}
return true;
}
public function validate( $context ) {
$input = $this->get_default_input();
$input = wpcf7_array_flatten( $input );
$input = wpcf7_strip_whitespaces( $input );
$input = wpcf7_exclude_blank( $input );
foreach ( $input as $i ) {
if ( ! wpcf7_is_number( $i ) ) {
return $this->create_error();
}
}
return true;
}
}

View File

@ -0,0 +1,34 @@
<?php
namespace Contactable\SWV;
class RequiredRule extends Rule {
const rule_name = 'required';
public function matches( $context ) {
if ( false === parent::matches( $context ) ) {
return false;
}
if ( empty( $context['text'] ) ) {
return false;
}
return true;
}
public function validate( $context ) {
$input = $this->get_default_input();
$input = wpcf7_array_flatten( $input );
$input = wpcf7_strip_whitespaces( $input );
$input = wpcf7_exclude_blank( $input );
if ( empty( $input ) ) {
return $this->create_error();
}
return true;
}
}

View File

@ -0,0 +1,33 @@
<?php
namespace Contactable\SWV;
class RequiredFileRule extends Rule {
const rule_name = 'requiredfile';
public function matches( $context ) {
if ( false === parent::matches( $context ) ) {
return false;
}
if ( empty( $context['file'] ) ) {
return false;
}
return true;
}
public function validate( $context ) {
$input = $this->get_default_upload()->tmp_name ?? '';
$input = wpcf7_array_flatten( $input );
$input = wpcf7_exclude_blank( $input );
if ( empty( $input ) ) {
return $this->create_error();
}
return true;
}
}

View File

@ -0,0 +1,50 @@
<?php
namespace Contactable\SWV;
class StepNumberRule extends Rule {
const rule_name = 'stepnumber';
public function matches( $context ) {
if ( false === parent::matches( $context ) ) {
return false;
}
if ( empty( $context['text'] ) ) {
return false;
}
return true;
}
public function validate( $context ) {
$input = $this->get_default_input();
$input = wpcf7_array_flatten( $input );
$input = wpcf7_strip_whitespaces( $input );
$input = wpcf7_exclude_blank( $input );
$base = floatval( $this->get_property( 'base' ) );
$interval = floatval( $this->get_property( 'interval' ) );
if ( ! ( 0 < $interval ) ) {
return true;
}
foreach ( $input as $i ) {
$remainder = fmod( floatval( $i ) - $base, $interval );
if (
0.0 === round( abs( $remainder ), 6 ) or
0.0 === round( abs( $remainder - $interval ), 6 )
) {
continue;
}
return $this->create_error();
}
return true;
}
}

Some files were not shown because too many files have changed in this diff Show More