first commit

This commit is contained in:
Rachit Bhargava
2023-07-21 17:12:10 -04:00
parent d0fe47dde4
commit 5d0f0734d8
14003 changed files with 2829464 additions and 0 deletions

1
wp/wp-content/et-cache Symbolic link
View File

@@ -0,0 +1 @@
./uploads/et-cache

2
wp/wp-content/index.php Normal file
View File

@@ -0,0 +1,2 @@
<?php
// Silence is golden.

View File

@@ -0,0 +1,20 @@
<?php
/*
* Exclude Campaign cron from cache
*/
$regex_path_patterns = array(
'#^/iper_cron/?#',
);
foreach ($regex_path_patterns as $regex_path_pattern) {
if (preg_match($regex_path_pattern, $_SERVER['REQUEST_URI'])) {
add_action( 'send_headers', 'add_header_nocache', 15 );
break;
}
}
function add_header_nocache() {
header( 'Cache-Control: no-cache, must-revalidate, max-age=0' );
}

View File

@@ -0,0 +1,76 @@
<?php
/**
* Plugin Name: Pantheon MU Plugin Loader
* Description: Loads the MU plugins required to run the site
* Author: Pantheon Systems
* Author URI: https://pantheon.io
* Version: 1.0
*/
if ( defined( 'WP_INSTALLING' ) && WP_INSTALLING ) {
return;
}
// Add mu-plugins here.
$pantheon_mu_plugins = [
'pantheon-mu-plugin/pantheon.php',
];
foreach ( $pantheon_mu_plugins as $file ) {
require_once WPMU_PLUGIN_DIR . '/' . $file;
}
unset( $file );
add_action( 'pre_current_active_plugins', function () use ( $pantheon_mu_plugins ) {
global $plugins, $wp_list_table;
// Add our own mu-plugins to the page.
foreach ( $pantheon_mu_plugins as $plugin_file ) {
// Do not apply markup/translate as it'll be cached.
$plugin_data = get_plugin_data( WPMU_PLUGIN_DIR . "/$plugin_file", false, false );
if ( empty( $plugin_data['Name'] ) ) {
$plugin_data['Name'] = $plugin_file;
}
$plugins['mustuse'][ $plugin_file ] = $plugin_data;
}
// Recount totals.
$GLOBALS['totals']['mustuse'] = count( $plugins['mustuse'] );
// Only apply the rest if we're actually looking at the page.
if ( $GLOBALS['status'] !== 'mustuse' ) {
return;
}
// Reset the list table's data.
$wp_list_table->items = $plugins['mustuse'];
foreach ( $wp_list_table->items as $plugin_file => $plugin_data ) {
$wp_list_table->items[ $plugin_file ] = _get_plugin_data_markup_translate( $plugin_file, $plugin_data, false, true );
}
$total_this_page = $GLOBALS['totals']['mustuse'];
if ( $GLOBALS['orderby'] ) {
uasort( $wp_list_table->items, [ $wp_list_table, '_order_callback' ] );
}
// Force showing all plugins.
// See https://core.trac.wordpress.org/ticket/27110.
$plugins_per_page = $total_this_page;
$wp_list_table->set_pagination_args( [
'total_items' => $total_this_page,
'per_page' => $plugins_per_page,
] );
});
add_filter( 'network_admin_plugin_action_links', function ( $actions, $plugin_file, $plugin_data, $context ) use ( $pantheon_mu_plugins ) {
if ( $context !== 'mustuse' || ! in_array( $plugin_file, $pantheon_mu_plugins, true ) ) {
return $actions;
}
$actions[] = sprintf( '<span style="color:#333">File: <code>%s</code></span>', $plugin_file );
return $actions;
}, 10, 4 );

View File

@@ -0,0 +1,3 @@
# Ignore composer files.
/vendor
composer.lock

View File

@@ -0,0 +1 @@
* @pantheon-systems/cms-platform

View File

@@ -0,0 +1,16 @@
# editorconfig.org
root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = tab
[{.jshintrc,*.json,*.yml}]
indent_style = space
indent_size = 2
[{*.txt,wp-config-sample.php}]
end_of_line = crlf

View File

@@ -0,0 +1,63 @@
#login {
width: 500px;
}
#return-to-pantheon {
margin-bottom: 20px;
display: flex;
justify-content: space-between;
align-items: center;
}
#return-to-pantheon .left {
font-size: 16px;
font-weight: 400;
line-height: 1.4;
}
#return-to-pantheon a{
display: flex;
align-items: center;
justify-content: space-between;
color: #000000;
padding: 5px 10px;
background: #F8DD44;
color: #000000 !important;
text-decoration: none !important;
font-size: 12px;
text-align: center;
border-radius: 10px;
min-width: 130px
}
#return-to-pantheon a:hover {
-webkit-transition: all 0.25s;
-moz-transition: all 0.25s;
transition: all 0.25s;
background: #EFD01B;
color: #333333 !important;
}
#return-to-pantheon .fist-icon {
display: inline-block;
width: 12px;
margin-right: 5px;
}
@media (max-width: 499px) {
#login {
width: 320px;
}
#return-to-pantheon {
flex-direction: column;
}
#return-to-pantheon .left {
order: 2;
}
#return-to-pantheon .right {
margin-bottom: 25px;
order: 1;
}
}

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="14px" height="32px" viewBox="0 0 14 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 46.2 (44496) - http://www.bohemiancoding.com/sketch -->
<title>Group 11</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="WP---button" transform="translate(-322.000000, -538.000000)" fill="#333333">
<g id="Group" transform="translate(311.000000, 534.000000)">
<g id="Group-11" transform="translate(11.000000, 4.000000)">
<path d="M1.54822908,0 L4.52272957,6.90999702 L0.736842105,6.90999702 L1.98837032,9.82347541 L9.66224514,9.82347541 L1.54822908,0 L1.54822908,0 Z M11.589856,24.7575559 L10.3368651,21.8425037 L8.57849426,21.8425037 L8.54163298,21.7553741 L6.11083637,16.1102593 L4.6957728,16.1102593 L7.16386951,21.8425037 L2.66269769,21.8425037 L10.7780302,31.6679821 L7.80265209,24.7575559 L11.589856,24.7575559 L11.589856,24.7575559 Z" id="Fill-1"></path>
<path d="M6.3944081,15.35938 L5.16291955,12.493687 L4.54724842,12.493687 L5.77976089,15.3559463 L3.74741716,15.3559463 L6.2165378,21.0911952 L1.18058487,21.0911952 C0.756241333,21.0911952 0.522640287,21.0911952 0.330873868,20.4898718 C0.102099894,19.7718033 0,18.2748614 0,15.6365067 C0,12.9982951 0.102099894,11.5016393 0.330873868,10.7831416 C0.522640287,10.1818182 0.756241333,10.1818182 1.18058487,10.1818182 L6.73391219,10.1818182 L8.96270314,15.35938 L6.3944081,15.35938 Z M12.6233793,18.7798987 C12.7164101,18.7798987 12.9331895,18.892924 12.9331895,19.9363338 C12.9331895,20.9791714 12.7164101,21.0911952 12.6233793,21.0911952 L8.86294364,21.0911952 L7.86842046,18.7798987 L12.6233793,18.7798987 Z M12.6233793,12.493687 L8.3441065,12.493687 L7.34958333,10.1818182 L12.6233793,10.1818182 C12.7164101,10.1818182 12.9331895,10.2944143 12.9331895,11.3369657 C12.9331895,12.3800894 12.7164101,12.493687 12.6233793,12.493687 Z M13.063228,15.9142057 C13.1571364,15.9142057 13.3739159,16.0268018 13.3739159,17.0699255 C13.3739159,18.1130492 13.1571364,18.225073 13.063228,18.225073 L7.6291147,18.225073 L6.63415269,15.9142057 L13.063228,15.9142057 Z M13.063228,13.0485127 C13.1571364,13.0485127 13.3739159,13.1601073 13.3739159,14.2036602 C13.3739159,15.2463547 13.1571364,15.35938 13.063228,15.35938 L9.57837427,15.35938 L8.58297345,13.0485127 L13.063228,13.0485127 Z" id="Path"></path>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@@ -0,0 +1,8 @@
jQuery(document).ready(function( $ ) {
$('#return-to-pantheon')
.detach()
.prependTo('#loginform')
.show();
});

View File

@@ -0,0 +1,96 @@
<?php
/**
* WP-CLI commands for the Pantheon mu-plugin.
*
* @package pantheon
*/
namespace Pantheon\CLI;
use Pantheon_Cache;
use WP_CLI;
// Support the old pantheon-cache command but return a deprecation notice.
WP_CLI::add_command( 'pantheon-cache set-maintenance-mode', '\\Pantheon\\CLI\\__deprecated_maintenance_mode_output' );
WP_CLI::add_command( 'pantheon cache set-maintenance-mode', '\\Pantheon\\CLI\\set_maintenance_mode_command' );
WP_CLI::add_command( 'pantheon set-maintenance-mode', '\\Pantheon\\CLI\\set_maintenance_mode_command' );
/**
* Sets maintenance mode status.
*
* Enable maintenance mode to work on your site while serving cached pages
* to visitors and bots, or everyone except administators.
*
* ## DEPRECATION NOTICE
*
* This command is deprecated and will be removed in a future release.
* Use `pantheon set-maintenance-mode` instead.
*
* ## USAGE
*
* wp pantheon-cache set-maintenance-mode <status> (deprecated) or
* wp pantheon cache set-maintenance-mode <status>
*
* ## OPTIONS
*
* <status>
* : Maintenance mode status.
* ---
* options:
* - disabled
* - anonymous
* - everyone
* ---
*
* @subcommand set-maintenance-mode
*
* @deprecated 1.0.0
*/
function __deprecated_maintenance_mode_output( $args ) {
$allowed_args = [ 'disabled', 'anonymous', 'everyone' ];
$replacement_command = ( ! empty( $args && count( $args ) === 1 ) && in_array( $args[0], $allowed_args, true ) ) ? 'set-maintenance-mode ' . $args[0] : false;
WP_CLI::warning( WP_CLI::colorize( '%y' . sprintf( __( 'This command is deprecated and will be removed in a future release. Use `wp pantheon %s` instead.', 'pantheon-systems' ), $replacement_command ) . '%n' ) );
WP_CLI::line( __( 'Run `wp pantheon set-maintenance-mode --help` for more information.', 'pantheon-systems' ) );
// The command should fail before we get here, but in case it doesn't, display an error.
if ( false === $replacement_command ) {
WP_CLI::error( __( 'Invalid arguments. Run `wp pantheon set-maintenance-mode --help` for more infomation.', 'pantheon-systems' ) );
}
set_maintenance_mode_command( $args );
}
/**
* Sets maintenance mode status.
*
* Enable maintenance mode to work on your site while serving cached pages
* to visitors and bots, or everyone except administators.
*
* ## OPTIONS
*
* <status>
* : Maintenance mode status.
* ---
* options:
* - disabled
* - anonymous
* - everyone
* ---
*
* @subcommand set-maintenance-mode
*/
function set_maintenance_mode_command( $args ) {
list( $status ) = $args;
$out = Pantheon_Cache()->default_options;
if ( ! empty( $status )
&& in_array( $status, [ 'anonymous', 'everyone' ], true ) ) {
$out['maintenance_mode'] = $status;
} else {
$out['maintenance_mode'] = 'disabled';
}
update_option( Pantheon_Cache::SLUG, $out );
WP_CLI::success( sprintf( 'Maintenance mode set to: %s', $out['maintenance_mode'] ) );
}

View File

@@ -0,0 +1,741 @@
<?php
/**
* File mostly copied from wp-admin/includes/network.php.
*
* Changes:
* - Multisite instructions on step2
* - Text area rows increased
* - Allow altering config filename
* - Allow altering config contents
* - Remove if file_exists .htaccess
*/
/**
* Check for an existing network.
*
* @since 3.0.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @return string|false Base domain if network exists, otherwise false.
*/
function network_domain_check() {
global $wpdb;
$sql = $wpdb->prepare( 'SHOW TABLES LIKE %s', $wpdb->esc_like( $wpdb->site ) );
if ( $wpdb->get_var( $sql ) ) {
return $wpdb->get_var( "SELECT domain FROM $wpdb->site ORDER BY id ASC LIMIT 1" );
}
return false;
}
/**
* Allow subdomain installation
*
* @since 3.0.0
* @return bool Whether subdomain installation is allowed
*/
function allow_subdomain_install() {
$domain = preg_replace( '|https?://([^/]+)|', '$1', get_option( 'home' ) );
if ( parse_url( get_option( 'home' ), PHP_URL_PATH ) || 'localhost' === $domain || preg_match( '|^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$|', $domain ) ) {
return false;
}
return true;
}
/**
* Allow subdirectory installation.
*
* @since 3.0.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @return bool Whether subdirectory installation is allowed
*/
function allow_subdirectory_install() {
global $wpdb;
/**
* Filters whether to enable the subdirectory installation feature in Multisite.
*
* @since 3.0.0
*
* @param bool $allow Whether to enable the subdirectory installation feature in Multisite.
* Default false.
*/
if ( apply_filters( 'allow_subdirectory_install', false ) ) {
return true;
}
if ( defined( 'ALLOW_SUBDIRECTORY_INSTALL' ) && ALLOW_SUBDIRECTORY_INSTALL ) {
return true;
}
$post = $wpdb->get_row( "SELECT ID FROM $wpdb->posts WHERE post_date < DATE_SUB(NOW(), INTERVAL 1 MONTH) AND post_status = 'publish'" );
if ( empty( $post ) ) {
return true;
}
return false;
}
/**
* Get base domain of network.
*
* @since 3.0.0
* @return string Base domain.
*/
function get_clean_basedomain() {
$existing_domain = network_domain_check();
if ( $existing_domain ) {
return $existing_domain;
}
$domain = preg_replace( '|https?://|', '', get_option( 'siteurl' ) );
$slash = strpos( $domain, '/' );
if ( $slash ) {
$domain = substr( $domain, 0, $slash );
}
return $domain;
}
/**
* Prints step 1 for Network installation process.
*
* @todo Realistically, step 1 should be a welcome screen explaining what a Network is and such.
* Navigating to Tools > Network should not be a sudden "Welcome to a new install process!
* Fill this out and click here." See also contextual help todo.
*
* @since 3.0.0
*
* @global bool $is_apache
*
* @param false|WP_Error $errors Optional. Error object. Default false.
*/
function network_step1( $errors = false ) {
global $is_apache;
if ( defined( 'DO_NOT_UPGRADE_GLOBAL_TABLES' ) ) {
echo '<div class="error"><p><strong>' . __( 'Error:' ) . '</strong> ' . sprintf(
/* translators: %s: DO_NOT_UPGRADE_GLOBAL_TABLES */
__( 'The constant %s cannot be defined when creating a network.' ),
'<code>DO_NOT_UPGRADE_GLOBAL_TABLES</code>'
) . '</p></div>';
echo '</div>';
require_once ABSPATH . 'wp-admin/admin-footer.php';
die();
}
$active_plugins = get_option( 'active_plugins' );
if ( ! empty( $active_plugins ) ) {
echo '<div class="notice notice-warning"><p><strong>' . __( 'Warning:' ) . '</strong> ' . sprintf(
/* translators: %s: URL to Plugins screen. */
__( 'Please <a href="%s">deactivate your plugins</a> before enabling the Network feature.' ),
admin_url( 'plugins.php?plugin_status=active' )
) . '</p></div>';
echo '<p>' . __( 'Once the network is created, you may reactivate your plugins.' ) . '</p>';
echo '</div>';
require_once ABSPATH . 'wp-admin/admin-footer.php';
die();
}
$hostname = get_clean_basedomain();
$has_ports = strstr( $hostname, ':' );
if ( ( false !== $has_ports && ! in_array( $has_ports, array( ':80', ':443' ), true ) ) ) {
echo '<div class="error"><p><strong>' . __( 'Error:' ) . '</strong> ' . __( 'You cannot install a network of sites with your server address.' ) . '</p></div>';
echo '<p>' . sprintf(
/* translators: %s: Port number. */
__( 'You cannot use port numbers such as %s.' ),
'<code>' . $has_ports . '</code>'
) . '</p>';
echo '<a href="' . esc_url( admin_url() ) . '">' . __( 'Go to Dashboard' ) . '</a>';
echo '</div>';
require_once ABSPATH . 'wp-admin/admin-footer.php';
die();
}
echo '<form method="post">';
wp_nonce_field( 'install-network-1' );
$error_codes = array();
if ( is_wp_error( $errors ) ) {
echo '<div class="error"><p><strong>' . __( 'Error: The network could not be created.' ) . '</strong></p>';
foreach ( $errors->get_error_messages() as $error ) {
echo "<p>$error</p>";
}
echo '</div>';
$error_codes = $errors->get_error_codes();
}
if ( ! empty( $_POST['sitename'] ) && ! in_array( 'empty_sitename', $error_codes, true ) ) {
$site_name = $_POST['sitename'];
} else {
/* translators: %s: Default network title. */
$site_name = sprintf( __( '%s Sites' ), get_option( 'blogname' ) );
}
if ( ! empty( $_POST['email'] ) && ! in_array( 'invalid_email', $error_codes, true ) ) {
$admin_email = $_POST['email'];
} else {
$admin_email = get_option( 'admin_email' );
}
?>
<p><?php _e( 'Welcome to the Network installation process!' ); ?></p>
<p><?php _e( 'Fill in the information below and you&#8217;ll be on your way to creating a network of WordPress sites. Configuration files will be created in the next step.' ); ?></p>
<?php
if ( isset( $_POST['subdomain_install'] ) ) {
$subdomain_install = (bool) $_POST['subdomain_install'];
} elseif ( apache_mod_loaded( 'mod_rewrite' ) ) { // Assume nothing.
$subdomain_install = true;
} elseif ( ! allow_subdirectory_install() ) {
$subdomain_install = true;
} else {
$subdomain_install = false;
$got_mod_rewrite = got_mod_rewrite();
if ( $got_mod_rewrite ) { // Dangerous assumptions.
echo '<div class="updated inline"><p><strong>' . __( 'Note:' ) . '</strong> ';
printf(
/* translators: %s: mod_rewrite */
__( 'Please make sure the Apache %s module is installed as it will be used at the end of this installation.' ),
'<code>mod_rewrite</code>'
);
echo '</p>';
} elseif ( $is_apache ) {
echo '<div class="error inline"><p><strong>' . __( 'Warning:' ) . '</strong> ';
printf(
/* translators: %s: mod_rewrite */
__( 'It looks like the Apache %s module is not installed.' ),
'<code>mod_rewrite</code>'
);
echo '</p>';
}
if ( $got_mod_rewrite || $is_apache ) { // Protect against mod_rewrite mimicry (but ! Apache).
echo '<p>';
printf(
/* translators: 1: mod_rewrite, 2: mod_rewrite documentation URL, 3: Google search for mod_rewrite. */
__( 'If %1$s is disabled, ask your administrator to enable that module, or look at the <a href="%2$s">Apache documentation</a> or <a href="%3$s">elsewhere</a> for help setting it up.' ),
'<code>mod_rewrite</code>',
'https://httpd.apache.org/docs/mod/mod_rewrite.html',
'https://www.google.com/search?q=apache+mod_rewrite'
);
echo '</p></div>';
}
}
if ( allow_subdomain_install() && allow_subdirectory_install() ) :
?>
<h3><?php esc_html_e( 'Addresses of Sites in your Network' ); ?></h3>
<p><?php _e( 'Please choose whether you would like sites in your WordPress network to use sub-domains or sub-directories.' ); ?>
<strong><?php _e( 'You cannot change this later.' ); ?></strong></p>
<p><?php _e( 'You will need a wildcard DNS record if you are going to use the virtual host (sub-domain) functionality.' ); ?></p>
<?php // @todo Link to an MS readme? ?>
<table class="form-table" role="presentation">
<tr>
<th><label><input type="radio" name="subdomain_install" value="1"<?php checked( $subdomain_install ); ?> /> <?php _e( 'Sub-domains' ); ?></label></th>
<td>
<?php
printf(
/* translators: 1: Host name. */
_x( 'like <code>site1.%1$s</code> and <code>site2.%1$s</code>', 'subdomain examples' ),
$hostname
);
?>
</td>
</tr>
<tr>
<th><label><input type="radio" name="subdomain_install" value="0"<?php checked( ! $subdomain_install ); ?> /> <?php _e( 'Sub-directories' ); ?></label></th>
<td>
<?php
printf(
/* translators: 1: Host name. */
_x( 'like <code>%1$s/site1</code> and <code>%1$s/site2</code>', 'subdirectory examples' ),
$hostname
);
?>
</td>
</tr>
</table>
<?php
endif;
if ( WP_CONTENT_DIR !== ABSPATH . 'wp-content' && ( allow_subdirectory_install() || ! allow_subdomain_install() ) ) {
echo '<div class="error inline"><p><strong>' . __( 'Warning:' ) . '</strong> ' . __( 'Subdirectory networks may not be fully compatible with custom wp-content directories.' ) . '</p></div>';
}
$is_www = ( 0 === strpos( $hostname, 'www.' ) );
if ( $is_www ) :
?>
<h3><?php esc_html_e( 'Server Address' ); ?></h3>
<p>
<?php
printf(
/* translators: 1: Site URL, 2: Host name, 3: www. */
__( 'You should consider changing your site domain to %1$s before enabling the network feature. It will still be possible to visit your site using the %3$s prefix with an address like %2$s but any links will not have the %3$s prefix.' ),
'<code>' . substr( $hostname, 4 ) . '</code>',
'<code>' . $hostname . '</code>',
'<code>www</code>'
);
?>
</p>
<table class="form-table" role="presentation">
<tr>
<th scope='row'><?php esc_html_e( 'Server Address' ); ?></th>
<td>
<?php
printf(
/* translators: %s: Host name. */
__( 'The internet address of your network will be %s.' ),
'<code>' . $hostname . '</code>'
);
?>
</td>
</tr>
</table>
<?php endif; ?>
<h3><?php esc_html_e( 'Network Details' ); ?></h3>
<table class="form-table" role="presentation">
<?php if ( 'localhost' === $hostname ) : ?>
<tr>
<th scope="row"><?php esc_html_e( 'Sub-directory Installation' ); ?></th>
<td>
<?php
printf(
/* translators: 1: localhost, 2: localhost.localdomain */
__( 'Because you are using %1$s, the sites in your WordPress network must use sub-directories. Consider using %2$s if you wish to use sub-domains.' ),
'<code>localhost</code>',
'<code>localhost.localdomain</code>'
);
// Uh oh:
if ( ! allow_subdirectory_install() ) {
echo ' <strong>' . __( 'Warning:' ) . ' ' . __( 'The main site in a sub-directory installation will need to use a modified permalink structure, potentially breaking existing links.' ) . '</strong>';
}
?>
</td>
</tr>
<?php elseif ( ! allow_subdomain_install() ) : ?>
<tr>
<th scope="row"><?php esc_html_e( 'Sub-directory Installation' ); ?></th>
<td>
<?php
_e( 'Because your installation is in a directory, the sites in your WordPress network must use sub-directories.' );
// Uh oh:
if ( ! allow_subdirectory_install() ) {
echo ' <strong>' . __( 'Warning:' ) . ' ' . __( 'The main site in a sub-directory installation will need to use a modified permalink structure, potentially breaking existing links.' ) . '</strong>';
}
?>
</td>
</tr>
<?php elseif ( ! allow_subdirectory_install() ) : ?>
<tr>
<th scope="row"><?php esc_html_e( 'Sub-domain Installation' ); ?></th>
<td>
<?php
_e( 'Because your installation is not new, the sites in your WordPress network must use sub-domains.' );
echo ' <strong>' . __( 'The main site in a sub-directory installation will need to use a modified permalink structure, potentially breaking existing links.' ) . '</strong>';
?>
</td>
</tr>
<?php endif; ?>
<?php if ( ! $is_www ) : ?>
<tr>
<th scope='row'><?php esc_html_e( 'Server Address' ); ?></th>
<td>
<?php
printf(
/* translators: %s: Host name. */
__( 'The internet address of your network will be %s.' ),
'<code>' . $hostname . '</code>'
);
?>
</td>
</tr>
<?php endif; ?>
<tr>
<th scope='row'><label for="sitename"><?php esc_html_e( 'Network Title' ); ?></label></th>
<td>
<input name='sitename' id='sitename' type='text' size='45' value='<?php echo esc_attr( $site_name ); ?>' />
<p class="description">
<?php _e( 'What would you like to call your network?' ); ?>
</p>
</td>
</tr>
<tr>
<th scope='row'><label for="email"><?php esc_html_e( 'Network Admin Email' ); ?></label></th>
<td>
<input name='email' id='email' type='text' size='45' value='<?php echo esc_attr( $admin_email ); ?>' />
<p class="description">
<?php _e( 'Your email address.' ); ?>
</p>
</td>
</tr>
</table>
<?php submit_button( __( 'Install' ), 'primary', 'submit' ); ?>
</form>
<?php
}
/**
* Prints step 2 for Network installation process.
*
* @since 3.0.0
*
* @global wpdb $wpdb WordPress database abstraction object.
* @global bool $is_nginx Whether the server software is Nginx or something else.
*
* @param false|WP_Error $errors Optional. Error object. Default false.
*/
function network_step2( $errors = false ) {
global $wpdb, $is_nginx;
$hostname = get_clean_basedomain();
$slashed_home = trailingslashit( get_option( 'home' ) );
$base = parse_url( $slashed_home, PHP_URL_PATH );
$document_root_fix = str_replace( '\\', '/', realpath( $_SERVER['DOCUMENT_ROOT'] ) );
$abspath_fix = str_replace( '\\', '/', ABSPATH );
$home_path = 0 === strpos( $abspath_fix, $document_root_fix ) ? $document_root_fix . $base : get_home_path();
$wp_siteurl_subdir = preg_replace( '#^' . preg_quote( $home_path, '#' ) . '#', '', $abspath_fix );
$rewrite_base = ! empty( $wp_siteurl_subdir ) ? ltrim( trailingslashit( $wp_siteurl_subdir ), '/' ) : '';
$config_filename = 'wp-config.php';
$config_filename = apply_filters( 'pantheon.multisite.config_filename', 'wp-config.php' );
$location_of_wp_config = $abspath_fix;
if ( ! file_exists( ABSPATH . $config_filename ) && file_exists( dirname( ABSPATH ) . '/' . $config_filename ) ) {
$location_of_wp_config = dirname( $abspath_fix );
}
$location_of_wp_config = trailingslashit( $location_of_wp_config );
// Wildcard DNS message.
if ( is_wp_error( $errors ) ) {
echo '<div class="error">' . $errors->get_error_message() . '</div>';
}
if ( $_POST ) {
if ( allow_subdomain_install() ) {
$subdomain_install = allow_subdirectory_install() ? ! empty( $_POST['subdomain_install'] ) : true;
} else {
$subdomain_install = false;
}
} else {
if ( is_multisite() ) {
$subdomain_install = is_subdomain_install();
?>
<p><?php _e( 'The original configuration steps are shown here for reference.' ); ?></p>
<?php
} else {
$subdomain_install = (bool) $wpdb->get_var( "SELECT meta_value FROM $wpdb->sitemeta WHERE site_id = 1 AND meta_key = 'subdomain_install'" );
?>
<div class="error"><p><strong><?php _e( 'Warning:' ); ?></strong> <?php _e( 'An existing WordPress network was detected.' ); ?></p></div>
<p><?php _e( 'Please complete the configuration steps. To create a new network, you will need to empty or remove the network database tables.' ); ?></p>
<?php
}
}
$subdir_match = $subdomain_install ? '' : '([_0-9a-zA-Z-]+/)?';
$subdir_replacement_01 = $subdomain_install ? '' : '$1';
$subdir_replacement_12 = $subdomain_install ? '$1' : '$2';
if ( $_POST || ! is_multisite() ) {
?>
<h3><?php esc_html_e( 'Enabling the Network' ); ?></h3>
<p><?php _e( 'Complete the following steps to enable the features for creating a network of sites.' ); ?></p>
<div class="notice notice-warning inline"><p>
<?php
if ( file_exists( $home_path . 'web.config' ) ) {
echo '<strong>' . __( 'Caution:' ) . '</strong> ';
printf(
/* translators: 1: wp-config.php, 2: web.config */
__( 'You should back up your existing %1$s and %2$s files.' ),
'<code>' . $config_filename . '</code>',
'<code>web.config</code>'
);
} else {
echo '<strong>' . __( 'Caution:' ) . '</strong> ';
printf(
/* translators: %s: wp-config.php */
__( 'You should back up your existing %s file.' ),
'<code>' . $config_filename . '</code>',
);
}
?>
</p></div>
<?php
}
?>
<ol>
<li><p id="network-wpconfig-rules-description">
<?php
printf(
/* translators: 1: wp-config.php, 2: Location of wp-config file, 3: Translated version of "That's all, stop editing! Happy publishing." */
__( 'Add the following to your %1$s file in %2$s <strong>above</strong> the line reading %3$s:' ),
'<code>' . $config_filename . '</code>',
'<code>' . $location_of_wp_config . '</code>',
/*
* translators: This string should only be translated if wp-config-sample.php is localized.
* You can check the localized release package or
* https://i18n.svn.wordpress.org/<locale code>/branches/<wp version>/dist/wp-config-sample.php
*/
'<code>/* ' . __( 'That&#8217;s all, stop editing! Happy publishing.' ) . ' */</code>'
);
?>
</p>
<p class="configuration-rules-label"><label for="network-wpconfig-rules">
<?php
printf(
/* translators: %s: File name (wp-config.php, .htaccess or web.config). */
__( 'Network configuration rules for %s' ),
'<code>' . $config_filename . '</code>'
);
?>
</label></p>
<textarea id="network-wpconfig-rules" class="code" readonly="readonly" cols="100" rows="31" aria-describedby="network-wpconfig-rules-description">
<?php ob_start(); ?>
if ( !empty( $_ENV['PANTHEON_ENVIRONMENT'] )) {
$site_name = $_ENV['PANTHEON_SITE_NAME'];
// Override $hostname value as needed.
switch ( $_ENV['PANTHEON_ENVIRONMENT'] ) {
case 'live':
$hostname = $_SERVER['HTTP_HOST'];
break;
case 'test':
$hostname = 'test-' . $site_name . '.pantheonsite.io';
break;
case 'dev':
$hostname = 'dev-' . $site_name . '.pantheonsite.io';
break;
case 'lando':
$hostname = $site_name . '.lndo.site';
break;
default:
$hostname = $_ENV['PANTHEON_ENVIRONMENT'] . '-' . $site_name . '.pantheonsite.io';
break;
}
} else {
// Override with a default hostname.
$hostname = '<?php echo $hostname ?>';
}
define( 'MULTISITE', true );
define( 'SUBDOMAIN_INSTALL', <?php echo $subdomain_install ? 'true' : 'false'; ?> );
define( 'DOMAIN_CURRENT_SITE', $hostname );
define( 'PATH_CURRENT_SITE', '<?php echo $base; ?>' );
define( 'SITE_ID_CURRENT_SITE', 1 );
define( 'BLOG_ID_CURRENT_SITE', 1 );
<?php
$config_file_contents = ob_get_contents();
ob_end_clean();
$config_file_contents = apply_filters( 'pantheon.multisite.config_contents', $config_file_contents );
echo $config_file_contents;
?>
</textarea>
<?php
$keys_salts = array(
'AUTH_KEY' => '',
'SECURE_AUTH_KEY' => '',
'LOGGED_IN_KEY' => '',
'NONCE_KEY' => '',
'AUTH_SALT' => '',
'SECURE_AUTH_SALT' => '',
'LOGGED_IN_SALT' => '',
'NONCE_SALT' => '',
);
foreach ( $keys_salts as $c => $v ) {
if ( defined( $c ) ) {
unset( $keys_salts[ $c ] );
}
}
if ( ! empty( $keys_salts ) ) {
$keys_salts_str = '';
$from_api = wp_remote_get( 'https://api.wordpress.org/secret-key/1.1/salt/' );
if ( is_wp_error( $from_api ) ) {
foreach ( $keys_salts as $c => $v ) {
$keys_salts_str .= "\ndefine( '$c', '" . wp_generate_password( 64, true, true ) . "' );";
}
} else {
$from_api = explode( "\n", wp_remote_retrieve_body( $from_api ) );
foreach ( $keys_salts as $c => $v ) {
$keys_salts_str .= "\ndefine( '$c', '" . substr( array_shift( $from_api ), 28, 64 ) . "' );";
}
}
$num_keys_salts = count( $keys_salts );
?>
<p id="network-wpconfig-authentication-description">
<?php
if ( 1 === $num_keys_salts ) {
printf(
/* translators: %s: wp-config.php */
__( 'This unique authentication key is also missing from your %s file.' ),
'<code>' . $config_filename . '</code>',
);
} else {
printf(
/* translators: %s: wp-config.php */
__( 'These unique authentication keys are also missing from your %s file.' ),
'<code>' . $config_filename . '</code>',
);
}
?>
<?php _e( 'To make your installation more secure, you should also add:' ); ?>
</p>
<p class="configuration-rules-label"><label for="network-wpconfig-authentication"><?php _e( 'Network configuration authentication keys' ); ?></label></p>
<textarea id="network-wpconfig-authentication" class="code" readonly="readonly" cols="100" rows="<?php echo $num_keys_salts; ?>" aria-describedby="network-wpconfig-authentication-description"><?php echo esc_textarea( $keys_salts_str ); ?></textarea>
<?php
}
?>
</li>
<?php
if ( iis7_supports_permalinks() ) :
// IIS doesn't support RewriteBase, all your RewriteBase are belong to us.
$iis_subdir_match = ltrim( $base, '/' ) . $subdir_match;
$iis_rewrite_base = ltrim( $base, '/' ) . $rewrite_base;
$iis_subdir_replacement = $subdomain_install ? '' : '{R:1}';
$web_config_file = '<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="WordPress Rule 1" stopProcessing="true">
<match url="^index\.php$" ignoreCase="false" />
<action type="None" />
</rule>';
if ( is_multisite() && get_site_option( 'ms_files_rewriting' ) ) {
$web_config_file .= '
<rule name="WordPress Rule for Files" stopProcessing="true">
<match url="^' . $iis_subdir_match . 'files/(.+)" ignoreCase="false" />
<action type="Rewrite" url="' . $iis_rewrite_base . WPINC . '/ms-files.php?file={R:1}" appendQueryString="false" />
</rule>';
}
$web_config_file .= '
<rule name="WordPress Rule 2" stopProcessing="true">
<match url="^' . $iis_subdir_match . 'wp-admin$" ignoreCase="false" />
<action type="Redirect" url="' . $iis_subdir_replacement . 'wp-admin/" redirectType="Permanent" />
</rule>
<rule name="WordPress Rule 3" stopProcessing="true">
<match url="^" ignoreCase="false" />
<conditions logicalGrouping="MatchAny">
<add input="{REQUEST_FILENAME}" matchType="IsFile" ignoreCase="false" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" ignoreCase="false" />
</conditions>
<action type="None" />
</rule>
<rule name="WordPress Rule 4" stopProcessing="true">
<match url="^' . $iis_subdir_match . '(wp-(content|admin|includes).*)" ignoreCase="false" />
<action type="Rewrite" url="' . $iis_rewrite_base . '{R:1}" />
</rule>
<rule name="WordPress Rule 5" stopProcessing="true">
<match url="^' . $iis_subdir_match . '([_0-9a-zA-Z-]+/)?(.*\.php)$" ignoreCase="false" />
<action type="Rewrite" url="' . $iis_rewrite_base . '{R:2}" />
</rule>
<rule name="WordPress Rule 6" stopProcessing="true">
<match url="." ignoreCase="false" />
<action type="Rewrite" url="index.php" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
';
echo '<li><p id="network-webconfig-rules-description">';
printf(
/* translators: 1: File name (.htaccess or web.config), 2: File path. */
__( 'Add the following to your %1$s file in %2$s, <strong>replacing</strong> other WordPress rules:' ),
'<code>web.config</code>',
'<code>' . $home_path . '</code>'
);
echo '</p>';
if ( ! $subdomain_install && WP_CONTENT_DIR !== ABSPATH . 'wp-content' ) {
echo '<p><strong>' . __( 'Warning:' ) . ' ' . __( 'Subdirectory networks may not be fully compatible with custom wp-content directories.' ) . '</strong></p>';
}
?>
<p class="configuration-rules-label"><label for="network-webconfig-rules">
<?php
printf(
/* translators: %s: File name (wp-config.php, .htaccess or web.config). */
__( 'Network configuration rules for %s' ),
'<code>web.config</code>'
);
?>
</label></p>
<textarea id="network-webconfig-rules" class="code" readonly="readonly" cols="100" rows="20" aria-describedby="network-webconfig-rules-description"><?php echo esc_textarea( $web_config_file ); ?></textarea>
</li>
</ol>
<?php
elseif ( $is_nginx ) : // End iis7_supports_permalinks(). Link to Nginx documentation instead:
echo '<li><p>';
printf(
/* translators: %s: Documentation URL. */
__( 'It seems your network is running with Nginx web server. <a href="%s">Learn more about further configuration</a>.' ),
__( 'https://wordpress.org/support/article/nginx/' )
);
echo '</p></li>';
else : // End $is_nginx. Construct an .htaccess file instead:
$ms_files_rewriting = '';
if ( is_multisite() && get_site_option( 'ms_files_rewriting' ) ) {
$ms_files_rewriting = "\n# uploaded files\nRewriteRule ^";
$ms_files_rewriting .= $subdir_match . "files/(.+) {$rewrite_base}" . WPINC . "/ms-files.php?file={$subdir_replacement_12} [L]" . "\n";
}
$htaccess_file = <<<EOF
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase {$base}
RewriteRule ^index\.php$ - [L]
{$ms_files_rewriting}
# add a trailing slash to /wp-admin
RewriteRule ^{$subdir_match}wp-admin$ {$subdir_replacement_01}wp-admin/ [R=301,L]
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
RewriteRule ^{$subdir_match}(wp-(content|admin|includes).*) {$rewrite_base}{$subdir_replacement_12} [L]
RewriteRule ^{$subdir_match}(.*\.php)$ {$rewrite_base}$subdir_replacement_12 [L]
RewriteRule . index.php [L]
EOF;
echo '<li><p id="network-htaccess-rules-description">';
printf(
/* translators: 1: File name (.htaccess or web.config), 2: File path. */
__( 'Add the following to your %1$s file in %2$s, <strong>replacing</strong> other WordPress rules:' ),
'<code>.htaccess</code>',
'<code>' . $home_path . '</code>'
);
echo '</p>';
if ( ! $subdomain_install && WP_CONTENT_DIR !== ABSPATH . 'wp-content' ) {
echo '<p><strong>' . __( 'Warning:' ) . ' ' . __( 'Subdirectory networks may not be fully compatible with custom wp-content directories.' ) . '</strong></p>';
}
?>
<p class="configuration-rules-label"><label for="network-htaccess-rules">
<?php
printf(
/* translators: %s: File name (wp-config.php, .htaccess or web.config). */
__( 'Network configuration rules for %s' ),
'<code>.htaccess</code>'
);
?>
</label></p>
<textarea id="network-htaccess-rules" class="code" readonly="readonly" cols="100" rows="<?php echo substr_count( $htaccess_file, "\n" ) + 1; ?>" aria-describedby="network-htaccess-rules-description"><?php echo esc_textarea( $htaccess_file ); ?></textarea>
</li>
</ol>
<?php
endif; // End IIS/Nginx/Apache code branches.
if ( ! is_multisite() ) {
?>
<p><?php _e( 'Once you complete these steps, your network is enabled and configured. You will have to log in again.' ); ?> <a href="<?php echo esc_url( wp_login_url() ); ?>"><?php _e( 'Log In' ); ?></a></p>
<?php
}
}

View File

@@ -0,0 +1,120 @@
<?php
/**
* File mostly copied from wp-admin/network.php.
*
* Changes:
* - s/__DIR__.'\//ABSPATH . 'wp-admin\//g
* - s/ABSPATH . 'wp-admin\/includes\/network.php/__DIR__ . '\/includes-network.php/g'
*/
define( 'WP_INSTALLING_NETWORK', true );
/** WordPress Administration Bootstrap */
require_once ABSPATH . 'wp-admin/admin.php';
if ( ! current_user_can( 'setup_network' ) ) {
wp_die( __( 'Sorry, you are not allowed to manage options for this site.' ) );
}
if ( is_multisite() ) {
if ( ! is_network_admin() ) {
wp_redirect( network_admin_url( 'setup.php' ) );
exit;
}
if ( ! defined( 'MULTISITE' ) ) {
wp_die( __( 'The Network creation panel is not for WordPress MU networks.' ) );
}
}
require_once __DIR__ . '/includes-network.php';
// We need to create references to ms global tables to enable Network.
foreach ( $wpdb->tables( 'ms_global' ) as $table => $prefixed_table ) {
$wpdb->$table = $prefixed_table;
}
if ( ! network_domain_check() && ( ! defined( 'WP_ALLOW_MULTISITE' ) || ! WP_ALLOW_MULTISITE ) ) {
wp_die(
printf(
/* translators: 1: WP_ALLOW_MULTISITE, 2: wp-config.php */
__( 'You must define the %1$s constant as true in your %2$s file to allow creation of a Network.' ),
'<code>WP_ALLOW_MULTISITE</code>',
'<code>wp-config.php</code>'
)
);
}
if ( is_network_admin() ) {
// Used in the HTML title tag.
$title = __( 'Network Setup' );
$parent_file = 'settings.php';
} else {
// Used in the HTML title tag.
$title = __( 'Create a Network of WordPress Sites' );
$parent_file = 'tools.php';
}
$network_help = '<p>' . __( 'This screen allows you to configure a network as having subdomains (<code>site1.example.com</code>) or subdirectories (<code>example.com/site1</code>). Subdomains require wildcard subdomains to be enabled in Apache and DNS records, if your host allows it.' ) . '</p>' .
'<p>' . __( 'Choose subdomains or subdirectories; this can only be switched afterwards by reconfiguring your installation. Fill out the network details, and click Install. If this does not work, you may have to add a wildcard DNS record (for subdomains) or change to another setting in Permalinks (for subdirectories).' ) . '</p>' .
'<p>' . __( 'The next screen for Network Setup will give you individually-generated lines of code to add to your wp-config.php and .htaccess files. Make sure the settings of your FTP client make files starting with a dot visible, so that you can find .htaccess; you may have to create this file if it really is not there. Make backup copies of those two files.' ) . '</p>' .
'<p>' . __( 'Add the designated lines of code to wp-config.php (just before <code>/*...stop editing...*/</code>) and <code>.htaccess</code> (replacing the existing WordPress rules).' ) . '</p>' .
'<p>' . __( 'Once you add this code and refresh your browser, multisite should be enabled. This screen, now in the Network Admin navigation menu, will keep an archive of the added code. You can toggle between Network Admin and Site Admin by clicking on the Network Admin or an individual site name under the My Sites dropdown in the Toolbar.' ) . '</p>' .
'<p>' . __( 'The choice of subdirectory sites is disabled if this setup is more than a month old because of permalink problems with &#8220;/blog/&#8221; from the main site. This disabling will be addressed in a future version.' ) . '</p>' .
'<p><strong>' . __( 'For more information:' ) . '</strong></p>' .
'<p>' . __( '<a href="https://wordpress.org/support/article/create-a-network/">Documentation on Creating a Network</a>' ) . '</p>' .
'<p>' . __( '<a href="https://wordpress.org/support/article/tools-network-screen/">Documentation on the Network Screen</a>' ) . '</p>';
get_current_screen()->add_help_tab(
array(
'id' => 'network',
'title' => __( 'Network' ),
'content' => $network_help,
)
);
get_current_screen()->set_help_sidebar(
'<p><strong>' . __( 'For more information:' ) . '</strong></p>' .
'<p>' . __( '<a href="https://wordpress.org/support/article/create-a-network/">Documentation on Creating a Network</a>' ) . '</p>' .
'<p>' . __( '<a href="https://wordpress.org/support/article/tools-network-screen/">Documentation on the Network Screen</a>' ) . '</p>' .
'<p>' . __( '<a href="https://wordpress.org/support/">Support</a>' ) . '</p>'
);
require_once ABSPATH . 'wp-admin/admin-header.php';
?>
<div class="wrap">
<h1><?php echo esc_html( $title ); ?></h1>
<?php
if ( $_POST ) {
check_admin_referer( 'install-network-1' );
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
// Create network tables.
install_network();
$base = parse_url( trailingslashit( get_option( 'home' ) ), PHP_URL_PATH );
$subdomain_install = allow_subdomain_install() ? ! empty( $_POST['subdomain_install'] ) : false;
if ( ! network_domain_check() ) {
$result = populate_network( 1, get_clean_basedomain(), sanitize_email( $_POST['email'] ), wp_unslash( $_POST['sitename'] ), $base, $subdomain_install );
if ( is_wp_error( $result ) ) {
if ( 1 === count( $result->get_error_codes() ) && 'no_wildcard_dns' === $result->get_error_code() ) {
network_step2( $result );
} else {
network_step1( $result );
}
} else {
network_step2();
}
} else {
network_step2();
}
} elseif ( is_multisite() || network_domain_check() ) {
network_step2();
} else {
network_step1();
}
?>
</div>
<?php require_once ABSPATH . 'wp-admin/admin-footer.php'; ?>

View File

@@ -0,0 +1,72 @@
<?php
/**
* Modify the WordPress login form for Pantheon
*/
/**
* Should we proceed with adding the return to Pantheon button?
*
* Only if we are on a Pantheon subdomain
*/
$show_return_to_pantheon_button = apply_filters( 'show_return_to_pantheon_button', (
(
false !== stripos( get_site_url(), 'pantheonsite.io') ||
( isset( $_SERVER['HTTP_HOST'] ) && false !== stripos( $_SERVER['HTTP_HOST'], 'pantheonsite.io') )
)
) );
if( $show_return_to_pantheon_button ){
/**
* Enqueue Pantheon login styles
*
* @return void
*/
function Pantheon_Enqueue_Login_style()
{
wp_enqueue_style('pantheon-login-mods', plugin_dir_url(__FILE__) . 'assets/css/return-to-pantheon-button.css', false);
}
add_action('login_enqueue_scripts', 'Pantheon_Enqueue_Login_style', 10);
/**
* Enqueue Pantheon login scripts
*
* @return void
*/
function Pantheon_Enqueue_Login_script()
{
wp_enqueue_script('pantheon-login-mods', plugin_dir_url(__FILE__) . 'assets/js/return-to-pantheon-button.js', array('jquery'), false, true);
}
add_action('login_enqueue_scripts', 'Pantheon_Enqueue_Login_script', 1);
/**
* Print return to Pantheon link HTML
*
* @return void
*/
function Return_To_Pantheon_Button_HTML()
{
$pantheon_dashboard_url = 'https://dashboard.pantheon.io/sites/' . $_ENV['PANTHEON_SITE'] . '#' . $_ENV['PANTHEON_ENVIRONMENT'];
$pantheon_fist_icon_url = plugin_dir_url(__FILE__) . 'assets/images/pantheon-fist-icon-black.svg';
$login_message = apply_filters( 'pantheon_wp_login_text', __('Login to your WordPress Site', 'pantheon') );
?>
<div id="return-to-pantheon" style="display: none;">
<div class="left">
<?php echo $login_message; ?>
</div>
<div class="right">
<a href="<?php echo esc_url( $pantheon_dashboard_url ); ?>">
<img class="fist-icon" src="<?php echo esc_url( $pantheon_fist_icon_url ); ?>">
<?php _e('Return to Pantheon', 'pantheon'); ?>
</a>
</div>
</div>
<?php
}
add_action('login_header', 'Return_To_Pantheon_Button_HTML', 10);
}

View File

@@ -0,0 +1,37 @@
<?php
/**
* If a site has multisite enabled, but has not had the final installation
* steps completed, alert the user and provide links.
*
* @package pantheon
*/
/**
* Detects if a user is using the correct upstream and framework and give them appropriate next steps to finalize WPMS setup.
*
* @return void
*/
function pantheon_multisite_install_finalize_message() { ?>
<div class="notice notice-info is-dismissible">
<?php
if ( isset( $_ENV['PANTHEON_ENVIRONMENT'] ) ) {
if ( getenv( 'FRAMEWORK' ) === 'wordpress_network' ) {
?>
<p><?php esc_html_e( 'Your WordPress Multisite is almost ready!', 'pantheon' ); ?></p>
<p><?php echo sprintf( __( 'Visit <a href="%s">Pantheon Multisite Configuration</a> for documentation on how to finalize configuration of your site network.', 'pantheon' ), 'https://pantheon.io/docs/guides/multisite/config/#install-the-wordpress-site-network' ); ?></p>
<?php
} else {
?>
<p><?php esc_html_e( 'You are trying to configure a WordPress Multisite with a wrong upstream!', 'pantheon' ); ?></p>
<p><?php echo sprintf( __( 'Make sure that you have the correct upstream configuration for WPMS. If you do not have that capability or check if you are eligible, please <a href="%s">Contact Support</a>.', 'pantheon' ), 'https://pantheon.io/support' ); ?></p>
<?php
}
}
?>
</div>
<?php
}
add_action( 'admin_notices', 'pantheon_multisite_install_finalize_message' );

View File

@@ -0,0 +1,41 @@
<?php
namespace Pantheon\NetworkSetup;
/**
* Alter network setup pages to include Pantheon-specific instructions.
*/
/**
* Replace the WordPress core Network Setup page from the Settings menu.
*/
function pantheon_remove_network_setup() {
global $submenu;
if ( isset( $submenu['tools.php'][50] ) ) {
unset( $submenu['tools.php'][50] );
}
}
/**
* Register the Pantheon network setup submenu page.
*/
function pantheon_add_network_setup() {
add_management_page(
__( 'Create a Network of WordPress Sites', 'network-setup' ),
__( 'Network Setup', 'network-setup' ),
'setup_network',
'setup_network',
__NAMESPACE__ . '\\pantheon_render_network_setup_page'
);
}
/**
* Render the Pantheon network setup page.
*/
function pantheon_render_network_setup_page() {
global $wpdb;
require_once __DIR__ . '/network/network.php';
}
add_action( 'admin_menu', __NAMESPACE__ . '\\pantheon_remove_network_setup' );
add_action( 'admin_menu', __NAMESPACE__ . '\\pantheon_add_network_setup' );

View File

@@ -0,0 +1,542 @@
<?php
/* This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
class Pantheon_Cache {
/**
* Define the capability required to see and modify the settings page.
*
* @var string
*/
public $options_capability = 'manage_options';
/**
* Define the default options, which are overridden by what's in wp_options.
*
* @var array
*/
public $default_options = array();
/**
* Stores the options for this plugin (from wp_options).
*
* @var array
*/
public $options = array();
/**
* Store the Paths to be flushed at shutdown.
*
* @var array
*/
public $paths = array();
/**
* The slug for the plugin, used in various places like the options page.
*/
const SLUG = 'pantheon-cache';
/**
* Holds the singleton instance.
*
* @static
* @var object
*/
protected static $instance;
/**
* Get a reference to the singleton.
*
* @return object The singleton instance.
*/
public static function instance() {
if ( ! isset( self::$instance ) ) {
self::$instance = new Pantheon_Cache;
self::$instance->setup();
}
return self::$instance;
}
protected function __construct() {
/** Don't do anything **/
}
/**
* Setup the actions and filters we need to hook into, and initialize any properties we need.
*
* @return void
*/
protected function setup() {
$this->options = get_option( self::SLUG, array() );
$this->default_options = array(
'default_ttl' => 600,
'maintenance_mode' => 'disabled',
);
$this->options = wp_parse_args( $this->options, $this->default_options );
add_action( 'init', array( $this, 'action_init_do_maintenance_mode' ) );
add_action( 'admin_init', array( $this, 'action_admin_init' ) );
add_action( 'admin_menu', array( $this, 'action_admin_menu' ) );
add_action( 'load-plugin-install.php', array( $this, 'action_load_plugin_install' ) );
add_action( 'admin_post_pantheon_cache_flush_site', array( $this, 'flush_site' ) );
add_action( 'send_headers', array( $this, 'cache_add_headers' ) );
add_filter( 'rest_post_dispatch', array( $this, 'filter_rest_post_dispatch_send_cache_control' ), 10, 2 );
add_action( 'admin_notices', function(){
global $wp_object_cache;
if ( empty( $wp_object_cache->missing_redis_message ) ) {
return;
}
$wp_object_cache->missing_redis_message = 'Alert! The Pantheon Redis service needs to be enabled before the WP Redis object cache will function properly.';
}, 9 ); // Before the message is displayed in the plugin notice.
add_action( 'shutdown', array( $this, 'cache_clean_urls' ), 999 );
}
/**
* Displays maintenance mode when enabled.
*/
public function action_init_do_maintenance_mode() {
$do_maintenance_mode = false;
if ( in_array( $this->options['maintenance_mode'], [ 'anonymous', 'everyone' ], true )
&& ! is_user_logged_in() ) {
$do_maintenance_mode = true;
}
if ( 'everyone' === $this->options['maintenance_mode']
&& is_user_logged_in()
&& ! current_user_can( 'manage_options' ) ) {
$do_maintenance_mode = true;
}
if ( defined( 'WP_CLI' ) && WP_CLI ) {
$do_maintenance_mode = false;
}
if ( 'wp-login.php' === $GLOBALS['pagenow'] ) {
$do_maintenance_mode = false;
}
/**
* Modify maintenance mode behavior with more advanced conditionals.
*
* @var boolean $do_maintenance_mode Whether or not to do maintenance mode.
*/
$do_maintenance_mode = apply_filters( 'pantheon_cache_do_maintenance_mode', $do_maintenance_mode );
if ( ! $do_maintenance_mode ) {
return;
}
wp_die(
__( 'Briefly unavailable for scheduled maintenance. Check back in a minute.' ),
__( 'Maintenance' ),
503
);
}
/**
* Prep the Settings API.
*
* @return void
*/
public function action_admin_init() {
register_setting( self::SLUG, self::SLUG, array( self::$instance, 'sanitize_options' ) );
add_settings_section( 'general', false, '__return_false', self::SLUG );
add_settings_field( 'default_ttl', null, array( self::$instance, 'default_ttl_field' ), self::SLUG, 'general' );
add_settings_field( 'maintenance_mode', null, array( self::$instance, 'maintenance_mode_field' ), self::SLUG, 'general' );
}
/**
* Add the settings page to the menu.
*
* @return void
*/
public function action_admin_menu() {
add_options_page( __( 'Pantheon Page Cache', 'pantheon-cache' ), __( 'Pantheon Page Cache', 'pantheon-cache' ), $this->options_capability, self::SLUG, array( self::$instance, 'view_settings_page' ) );
}
/**
* Check to see if JavaScript should trigger the opening of the plugin install box
*/
public function action_load_plugin_install() {
if ( empty( $_GET['action'] ) || 'pantheon-load-infobox' !== $_GET['action'] ) {
return;
}
add_action( 'admin_footer', array( $this, 'action_admin_footer_trigger_plugin_open' ) );
}
/**
* Trigger the opening of the Pantheon Advanced Page Cache infobox
*/
public function action_admin_footer_trigger_plugin_open() {
?>
<script>
jQuery(document).ready(function(){
// Wait until the click event handler is bound by core JavaScript
setTimeout(function(){
jQuery('.plugin-card-pantheon-advanced-page-cache a.open-plugin-details-modal').trigger('click');
}, 1 )
});
</script>
<?php
}
/**
* Add the HTML for the default TTL field.
*
* @return void
*/
public function default_ttl_field() {
echo '<h3>' . __( 'Default Time to Live (TTL)', 'pantheon-cache' ) . '</h3>';
echo '<p>' . __( 'Maximum time a cached page will be served. A higher TTL typically improves site performance.', 'pantheon-cache' ) . '</p>';
echo '<input type="text" name="' . self::SLUG . '[default_ttl]" value="' . $this->options['default_ttl'] . '" size="5" /> ' . __( 'seconds', 'pantheon-cache' );
}
/**
* Add the HTML for the maintenance mode field.
*
* @return void
*/
public function maintenance_mode_field() {
echo '<h3>' . __( 'Maintenance Mode', 'pantheon-cache' ) . '</h3>';
echo '<p>' . __( 'Enable maintenance mode to work on your site while serving cached pages to:', 'pantheon-cache' ) . '</p>';
echo '<label style="display: block; margin-bottom: 5px;"><input type="radio" name="' . self::SLUG . '[maintenance_mode]" value="" ' . checked( 'disabled', $this->options['maintenance_mode'], false ) . ' /> ' . __( 'Disabled', 'pantheon-cache' ) . '</label>';
echo '<label style="display: block; margin-bottom: 5px;"><input type="radio" name="' . self::SLUG . '[maintenance_mode]" value="anonymous" ' . checked( 'anonymous', $this->options['maintenance_mode'], false ) . ' /> ' . __( 'Logged-Out Visitors', 'pantheon-cache' ) . '</label>';
echo '<label style="display: block; margin-bottom: 5px;"><input type="radio" name="' . self::SLUG . '[maintenance_mode]" value="everyone" ' . checked( 'everyone', $this->options['maintenance_mode'], false ) . ' /> ' . __( 'Everyone except Administrators', 'pantheon-cache' ) . '</label>';
}
/**
* Sanitize our options.
*
* @param array $in The POST values.
* @return array The sanitized POST values.
*/
public function sanitize_options( $in ) {
$out = $this->default_options;
// Validate default_ttl
$out['default_ttl'] = absint( $in['default_ttl'] );
if ( $out['default_ttl'] < 60 && isset( $_ENV['PANTHEON_ENVIRONMENT'] ) && 'live' === $_ENV['PANTHEON_ENVIRONMENT'] ) {
$out['default_ttl'] = 60;
}
if ( ! empty( $in['maintenance_mode'] )
&& in_array( $in['maintenance_mode'], [ 'anonymous', 'everyone' ], true ) ) {
$out['maintenance_mode'] = $in['maintenance_mode'];
} else {
$out['maintenance_mode'] = 'disabled';
}
return $out;
}
/**
* Output the settings page.
*
* @return void
*/
public function view_settings_page() {
?>
<div class="wrap">
<h2><?php esc_html_e( 'Pantheon Page Cache', 'pantheon-cache' ); ?></h2>
<?php if ( ! empty( $_GET['cache-cleared'] ) && 'true' == $_GET['cache-cleared'] ) : ?>
<div class="updated below-h2">
<p><?php esc_html_e( 'Site cache flushed.', 'pantheon-cache' ); ?></p>
</div>
<?php endif ?>
<?php if ( class_exists( 'Pantheon_Advanced_Page_Cache\Purger' ) ) : // translators: %s is a link. ?>
<div class="notice notice-success"><p><?php echo wp_kses_post( sprintf( __( 'Pantheon Advanced Page Cache activated. <a target="_blank" href="%s">Learn more</a>', 'pantheon-cache' ), 'https://docs.pantheon.io/guides/wordpress-configurations/wordpress-cache-plugin' ) ); ?></p></div>
<?php else : // translators: %s is a link. ?>
<div class="notice notice-warning"><p><?php echo wp_kses_post( sprintf( __( 'Want to automatically clear related pages when you update content? Learn more about the <a href="%s">Pantheon Advanced Page Cache</a>.', 'pantheon-cache' ), 'https://docs.pantheon.io/guides/wordpress-configurations/wordpress-cache-plugin' ) ); ?></p></div>
<?php endif; ?>
<?php
/**
* Permits the Pantheon Advanced Page Cache plugin to add
* supplemental text.
*/
do_action( 'pantheon_cache_settings_page_top' );
?>
<?php if ( apply_filters( 'pantheon_cache_allow_clear_all', true ) ) : ?>
<form action="admin-post.php" method="POST">
<input type="hidden" name="action" value="pantheon_cache_flush_site" />
<?php wp_nonce_field( 'pantheon-cache-clear-all', 'pantheon-cache-nonce' ); ?>
<h3><?php _e( 'Clear Site Cache', 'pantheon-cache' ); ?></h3>
<p><?php _e( 'Use with care. Clearing the entire site cache will negatively impact performance for a short period of time.', 'pantheon-cache' ); ?></p>
<?php submit_button( __( 'Clear Cache', 'pantheon-cache' ), 'secondary' ); ?>
</form>
<hr />
<?php endif ?>
<style>
.ttl-form th[scope="row"] {
display: none;
}
.ttl-form td {
padding-left: 0;
}
.ttl-form td p {
margin-bottom: 1em;
font-size: 13px;
}
</style>
<form action="options.php" method="POST" class="ttl-form">
<?php settings_fields( self::SLUG ); ?>
<?php do_settings_sections( self::SLUG ); ?>
<?php submit_button( __( 'Save Changes', 'pantheon-cache' ) ); ?>
</form>
<hr />
<?php
/**
* Permits the Pantheon Advanced Page Cache plugin to add
* supplemental text.
*/
do_action( 'pantheon_cache_settings_page_bottom' ); ?>
</div>
<?php
}
/**
* Get the cache-control header value.
*
* This removes "max-age=0" which could hypothetically be used by
* Varnish on an immediate subsequent request.
*
* @return void
*/
private function get_cache_control_header_value() {
if ( ! is_admin() && ! is_user_logged_in() ) {
$ttl = absint( $this->options['default_ttl'] );
if ( $ttl < 60 && isset( $_ENV['PANTHEON_ENVIRONMENT'] ) && 'live' === $_ENV['PANTHEON_ENVIRONMENT'] ) {
$ttl = 60;
}
return sprintf( 'public, max-age=%d', $ttl );
} else {
return 'no-cache, no-store, must-revalidate';
}
}
/**
* Add the cache-control header.
*
* @return void
*/
public function cache_add_headers() {
header( sprintf( 'cache-control: %s', $this->get_cache_control_header_value() ) );
}
/**
* Send the cache control header for REST API requests
*
* @param WP_REST_Response $response Response.
* @return WP_REST_Response Response.
*/
public function filter_rest_post_dispatch_send_cache_control( $response ) {
$response->header( 'Cache-Control', $this->get_cache_control_header_value() );
return $response;
}
/**
* Clear the cache for the entire site.
*
* @return void
*/
public function flush_site() {
if ( ! function_exists( 'current_user_can' ) || false == current_user_can( 'manage_options' ) )
return false;
if ( ! empty( $_POST['pantheon-cache-nonce'] ) && wp_verify_nonce( $_POST['pantheon-cache-nonce'], 'pantheon-cache-clear-all' ) ) {
if ( function_exists( 'pantheon_clear_edge_all' ) ) {
pantheon_clear_edge_all();
}
wp_cache_flush();
wp_redirect( admin_url( 'options-general.php?page=pantheon-cache&cache-cleared=true' ) );
exit();
}
}
/**
* Clear the cache for a post.
*
* @deprecated
*
* @param int $post_id A post ID to clean.
* @return void
*/
public function clean_post_cache( $post_id, $include_homepage = true ) {
if ( method_exists( 'Pantheon_Advanced_Page_Cache\Purger', 'action_clean_post_cache' ) ) {
Pantheon_Advanced_Page_Cache\Purger::action_clean_post_cache( $post_id );
}
}
/**
* Clear the cache for a given term or terms and taxonomy.
*
* @deprecated
*
* @param int|array $ids Single or list of Term IDs.
* @param string $taxonomy Can be empty and will assume tt_ids, else will use for context.
* @return void
*/
public function clean_term_cache( $term_ids, $taxonomy ) {
if ( method_exists( 'Pantheon_Advanced_Page_Cache\Purger', 'action_clean_term_cache' ) ) {
Pantheon_Advanced_Page_Cache\Purger::action_clean_term_cache( $term_ids );
}
}
/**
* Clear the cache for a given term or terms and taxonomy.
*
* @deprecated
*
* @param int|array $object_ids Single or list of term object ID(s).
* @param array|string $object_type The taxonomy object type.
* @return void
*/
public function clean_object_term_cache( $object_ids, $object_type ) {
// Handled by Pantheon Integrated CDN
}
/**
* Enqueue Fully-qualified urls to be cleared on shutdown.
*
* @param array|string $urls List of full urls to clear.
* @return void
*/
public function enqueue_urls( $urls ) {
$paths = array();
$urls = array_filter( (array) $urls, 'is_string' );
foreach ( $urls as $full_url ) {
# Parse down to the path+query, escape regex.
$parsed = parse_url( $full_url );
# Sometimes parse_url can return false, on malformed urls
if (FALSE == $parsed) {
continue;
}
# Build up the path, checking if the array key exists first
if (array_key_exists('path', $parsed)) {
$path = $parsed['path'];
if (array_key_exists('query', $parsed)) {
$path = $path . $parsed['query'];
}
}
# If the path doesn't exist, set it to the null string
else {
$path = '';
}
if ( '' == $path ) {
continue;
}
$path = '^' . preg_quote( $path ) . '$';
$paths[] = $path;
}
$this->paths = array_merge( $this->paths, $paths );
}
/**
* Enqueue a regex to be cleared.
*
* You must understand regular expressions to use this, and be careful.
*
* @param string $regex path regex to clear.
* @return void
*/
public function enqueue_regex( $regex ) {
$this->paths[] = $regex;
}
public function cache_clean_urls() {
if ( empty( $this->paths ) )
return;
$this->paths = apply_filters( 'pantheon_clean_urls', array_unique( $this->paths ) );
# Call the big daddy here
$url = home_url();
$host = parse_url( $url, PHP_URL_HOST );
$this->paths = apply_filters( 'pantheon_final_clean_urls', $this->paths );
if ( function_exists( 'pantheon_clear_edge_paths' ) ) {
pantheon_clear_edge_paths( $this->paths );
}
}
}
/**
* Get a reference to the singleton.
*
* This can be used to reference public methods, e.g. `Pantheon_Cache()->clean_post_cache( 123 )`
*
* @return void
*/
function Pantheon_Cache() {
return Pantheon_Cache::instance();
}
add_action( 'plugins_loaded', 'Pantheon_Cache' );
/**
* @see Pantheon_Cache::clean_post_cache
*
* @deprecated Please call Pantheon Integrated CDN instead.
*/
function pantheon_clean_post_cache( $post_id, $include_homepage = true ) {
Pantheon_Cache()->clean_post_cache( $post_id, $include_homepage );
}
/**
* @see Pantheon_Cache::clean_term_cache
*
* @deprecated Please call Pantheon Integrated CDN instead.
*/
function pantheon_clean_term_cache( $term_ids, $taxonomy ) {
Pantheon_Cache()->clean_term_cache( $term_ids, $taxonomy );
}
/**
* @see Pantheon_Cache::enqueue_urls
*
* @deprecated Please call Pantheon Integrated CDN instead.
*/
function pantheon_enqueue_urls( $urls ) {
Pantheon_Cache()->enqueue_urls( $urls );
}

View File

@@ -0,0 +1,29 @@
<?php
/**
* If a Pantheon site is in Git mode, hide the Plugin installation functionality and show a notice.
*/
if ( ! wp_is_writable( WP_PLUGIN_DIR ) ) {
if ( ! defined( 'DISALLOW_FILE_MODS' ) ) {
define( 'DISALLOW_FILE_MODS', true );
}
add_action( 'admin_notices', '_pantheon_plugin_install_notice' );
add_action( 'network_admin_notices', '_pantheon_plugin_install_notice' );
}
function _pantheon_plugin_install_notice() {
$screen = get_current_screen();
// Only show this notice on the plugins page.
if ( 'plugins' === $screen->id || 'plugins-network' === $screen->id ) { ?>
<div class="update-nag notice notice-warning is-dismissible" style="margin: 5px 6em 15px 0;">
<p style="font-size: 14px; margin: 0;">
<?php
// Translators: %s is a URL to the user's Pantheon Dashboard.
echo wp_kses_post( sprintf( __( 'If you wish to update or add plugins using the WordPress UI, switch your site to SFTP mode from <a href="%s">your Pantheon dashboard</a>.', 'pantheon-systems' ), 'https://dashboard.pantheon.io/sites/' . $_ENV['PANTHEON_SITE'] ) );
?>
</p>
</div>
<?php
}
}

View File

@@ -0,0 +1,182 @@
<?php
/**
* Pantheon MU Plugin Updates
*
* Handles modifying the default WordPress update behavior on Pantheon.
*/
// If on Pantheon...
if ( isset( $_ENV['PANTHEON_ENVIRONMENT'] ) ) {
// Disable WordPress auto updates.
if ( ! defined( 'WP_AUTO_UPDATE_CORE' ) ) {
define( 'WP_AUTO_UPDATE_CORE', false );
}
remove_action( 'wp_maybe_auto_update', 'wp_maybe_auto_update' );
// Remove the default WordPress core update nag.
add_action( 'admin_menu', '_pantheon_hide_update_nag' );
}
/**
* Remove the default WordPress core update nag message.
*
* @return void
*/
function _pantheon_hide_update_nag() {
remove_action( 'admin_notices', 'update_nag', 3 );
remove_action( 'network_admin_notices', 'update_nag', 3 );
}
/**
* Helper function that returns the current WordPress version.
*
* @return string
*/
function _pantheon_get_current_wordpress_version() : string {
include ABSPATH . WPINC . '/version.php';
return $wp_version; // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable
}
/**
* Get the latest WordPress version.
*
* @return string|null
*/
function _pantheon_get_latest_wordpress_version() : ?string {
$core_updates = get_core_updates();
if ( ! is_array( $core_updates ) || empty( $core_updates ) || ! property_exists( $core_updates[0], 'current' ) ) {
return null;
}
return $core_updates[0]->current;
}
/**
* Check if WordPress core is at the latest version.
*
* @return bool
*/
function _pantheon_is_wordpress_core_latest() : bool {
$latest_wp_version = _pantheon_get_latest_wordpress_version();
$wp_version = _pantheon_get_current_wordpress_version();
if ( null === $latest_wp_version ) {
return true;
}
// Return true if our version is the latest.
return version_compare( str_replace( '-src', '', $latest_wp_version ), str_replace( '-src', '', $wp_version ), '<=' ); // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable
}
/**
* Check if WordPress core is a pre-release version.
*
* @return bool
*/
function _pantheon_is_wordpress_core_prerelease() : bool {
$wp_version = _pantheon_get_current_wordpress_version();
// Return true if our version is a prerelease. Pre-releases are identified by a dash in the version number.
return false !== strpos( $wp_version, '-' ); // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable
}
/**
* Replace WordPress core update nag EVERYWHERE with our own notice.
* Use git upstream instead
*
* @return void
*/
function _pantheon_upstream_update_notice() {
$wp_version = _pantheon_get_current_wordpress_version();
$screen = get_current_screen();
// Translators: %s is a URL to the user's Pantheon Dashboard.
$notice_message = sprintf( __( 'Check for updates on <a href="%s">your Pantheon dashboard</a>.', 'pantheon-systems' ), 'https://dashboard.pantheon.io/sites/' . $_ENV['PANTHEON_SITE'] );
// Translators: %s is a URL to Pantheon's upstream updates documentation.
$upstream_help_message = sprintf( __( 'For details on applying updates, see the <a href="%s">Applying Upstream Updates</a> documentation.', 'pantheon-systems' ), 'https://docs.pantheon.io/core-updates' );
$update_help = __( 'If you need help, contact an administrator for your Pantheon organization.', 'pantheon-systems' );
$div_class = esc_attr( 'update-nag notice notice-warning' );
$div_style = esc_attr( 'display: table;' );
$paragraph_style = esc_attr( 'font-size: 14px; font-weight: bold; margin: 0 0 0.5em 0;' );
if ( ! _pantheon_is_wordpress_core_latest() ) {
// If WP core is out of date, alter the message and show the nag everywhere.
// Translators: %s is a URL to the user's Pantheon Dashboard.
$notice_message = sprintf( __( 'A new WordPress update is available! Please update from <a href="%s">your Pantheon dashboard</a>.', 'pantheon-systems' ), 'https://dashboard.pantheon.io/sites/' . $_ENV['PANTHEON_SITE'] );
}
// If WP core is a pre-release, alter the message.
if ( _pantheon_is_wordpress_core_prerelease() ) {
$version = '<span style="font-weight: normal;">(' . $wp_version . ')</span>';
$paragraph_style = esc_attr( 'font-size: 14px;' );
// Translators: %s is the current WordPress version.
$notice_message = sprintf( __( '<strong>You are using a development version of WordPress.</strong> %s', 'pantheon-systems' ), $version );
// If we're on the Updates page, add a note about the Beta Tester plugin.
if ( 'update-core' === $screen->id || 'update-core-network' === $screen->id ) {
$notice_message .= '<br /><span style="font-weight: normal;">';
$notice_message .= __( 'You are responsible for keeping WordPress up-to-date. Pantheon updates to WordPress will not appear in the dashboard as long as you\'re using a pre-release version. If you are using the Beta Tester plugin, you must have your site in SFTP mode to get the latest updates to your Pantheon Dev environment.', 'pantheon-systems' );
}
}
ob_start();
?>
<div class="<?php echo esc_attr( $div_class ); ?>" style="<?php echo esc_attr( $div_style ); ?>">
<p style="<?php echo esc_attr( $paragraph_style ); ?>">
<?php echo wp_kses_post( $notice_message ); ?>
</p>
<?php if ( ! _pantheon_is_wordpress_core_prerelease() ) : ?>
<?php echo wp_kses_post( $upstream_help_message ); ?>
<br />
<?php echo wp_kses_post( $update_help ); ?>
<?php endif; ?>
</div>
<?php
$notice_html = ob_get_clean();
// If a WP core update is not detected, only show the nag on the updates page.
if ( ! _pantheon_is_wordpress_core_latest() || 'update-core' === $screen->id || 'update-core-network' === $screen->id ) {
// Escaping is handled above when we're buffering the output, so we can ignore it here.
echo $notice_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
}
/**
* Register Pantheon specific WordPress update admin notice.
*
* @return void
*/
function _pantheon_register_upstream_update_notice() {
// Only register notice if we are on Pantheon and this is not a WordPress Ajax request.
if ( isset( $_ENV['PANTHEON_ENVIRONMENT'] ) && ! wp_doing_ajax() ) {
add_action( 'admin_notices', '_pantheon_upstream_update_notice' );
add_action( 'network_admin_notices', '_pantheon_upstream_update_notice' );
}
}
add_action( 'admin_init', '_pantheon_register_upstream_update_notice' );
/**
* Return zero updates and current time as last checked time.
*
* @return object
*/
function _pantheon_disable_wp_updates() : object {
$wp_version = _pantheon_get_current_wordpress_version();
return (object) [
'updates' => [],
'version_checked' => $wp_version, // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable
'last_checked' => time(),
];
}
// In the Test and Live environments, clear plugin/theme update notifications.
// Users must check a dev or multidev environment for updates.
if ( isset( $_ENV['PANTHEON_ENVIRONMENT'] ) && in_array( $_ENV['PANTHEON_ENVIRONMENT'], [ 'test', 'live' ], true ) && ( php_sapi_name() !== 'cli' ) ) {
// Disable Plugin Updates.
remove_action( 'load-update-core.php', 'wp_update_plugins' );
add_filter( 'pre_site_transient_update_plugins', '_pantheon_disable_wp_updates' );
// Disable Theme Updates.
remove_action( 'load-update-core.php', 'wp_update_themes' );
add_filter( 'pre_site_transient_update_themes', '_pantheon_disable_wp_updates' );
}

View File

@@ -0,0 +1,51 @@
<?php
/**
* Plugin Name: Pantheon
* Plugin URI: https://pantheon.io/
* Description: Building on Pantheon's and WordPress's strengths, together.
* Version: 1.0.0
* Author: Pantheon
* Author URI: https://pantheon.io/
*
* @package pantheon
*/
if ( isset( $_ENV['PANTHEON_ENVIRONMENT'] ) ) {
require_once 'inc/pantheon-page-cache.php';
if ( ! defined( 'DISABLE_PANTHEON_UPDATE_NOTICES' ) || ! DISABLE_PANTHEON_UPDATE_NOTICES ) {
require_once 'inc/pantheon-updates.php';
}
if ( ! defined('RETURN_TO_PANTHEON_BUTTON') || RETURN_TO_PANTHEON_BUTTON ) {
require_once 'inc/pantheon-login-form-mods.php';
}
if ( 'dev' === $_ENV['PANTHEON_ENVIRONMENT'] && function_exists( 'wp_is_writable' ) ) {
require_once 'inc/pantheon-plugin-install-notice.php';
}
if ( defined( 'WP_CLI' ) && WP_CLI ) {
require_once 'inc/cli.php';
}
if ( ! defined( 'FS_METHOD' ) ) {
/**
* When this constant is not set, WordPress writes and then deletes a
* temporary file to determine if it has direct access to the filesystem,
* which we already know to be the case. This multiplies filesystem
* operations and can degrade performance of the filesystem as a whole in
* the case of large sites that do a lot of filesystem operations.
* Setting this constant to 'direct' tells WordPress to assume it has
* direct access and skip creating the extra temporary file.
*/
define( 'FS_METHOD', 'direct' );
}
// When developing a WordPress Multisite locally, ensure that this constant is set.
// This will set the Multisite variable in all Pantheon environments.
if ( getenv( 'FRAMEWORK' ) === 'wordpress_network' && ! defined( 'WP_ALLOW_MULTISITE' ) ) {
define( 'WP_ALLOW_MULTISITE', true );
}
if ( defined( 'MULTISITE' ) && defined( 'WP_ALLOW_MULTISITE' ) && WP_ALLOW_MULTISITE ) {
require_once 'inc/pantheon-network-setup.php';
}
if ( defined( 'WP_ALLOW_MULTISITE' ) && ( ! defined( 'MULTISITE' ) || empty( MULTISITE ) ) ) {
require_once 'inc/pantheon-multisite-finalize.php';
}
} // Ensuring that this is on Pantheon.

View File

@@ -0,0 +1,28 @@
<?php
/*
Plugin Name: Security Headers
Plugin URI: https://www.medicalalert.com
Description: Add security headers
Author: Connect America
Version: 0.1
Author URI: https://www.medicalalert.com
*/
add_action('send_headers', function(){
// Upgrade HTTP requests to secure HTTPS
header("Content-Security-Policy: upgrade-insecure-requests;");
// Enforce the use of HTTPS
header("Strict-Transport-Security: max-age=31536000; includeSubDomains");
// Prevent Clickjacking
header("X-Frame-Options: SAMEORIGIN");
// Block Access If XSS Attack Is Suspected
header("X-XSS-Protection: 1; mode=block");
// Prevent MIME-Type Sniffing
header("X-Content-Type-Options: nosniff");
// Referrer Policy
header("Referrer-Policy: no-referrer-when-downgrade");
}, 1);

View File

@@ -0,0 +1,286 @@
<?php
/**
* Plugin Name: Contact Form 7 - Show Page
* Description: An add-on for Contact Form 7 that shows the all the post types where the contact form is being used.
* Version: 1.0.3
* Author: Sachyya, Ugene
* Author URI:
* License: GPLv3
*/
/**
* Show admin notice on CF7 dependency.
* @return string Notice about the plugin dependency.
*/
function wpcf7sp_admin_notice() {
// Verify that CF7 is active and updated to the required version (currently 3.9.0)
if ( ! is_plugin_active( 'contact-form-7/wp-contact-form-7.php' ) ) {
echo __( '<div class="error"><p><strong>Contact Form 7</strong> is not activated. The Contact Form 7 plugin must be installed and activated before you can use <strong>Contact Form 7 - Show Page</strong> plugin.</p></div>', 'wpcf7sp' );
}
}
// add_action( 'admin_notices', 'wpcf7sp_admin_notice' );
require_once untrailingslashit( dirname( __FILE__ ) ) . '/tgmpa/call.php';
/**
* Load style file
*/
function wpcf7sp_load_style() {
wp_enqueue_style( 'wpcf7sp_style', plugins_url( '/css/show-page.css', __FILE__ ), '', time(), 'all' );
}
add_action( 'admin_footer', 'wpcf7sp_load_style' );
/**
* Add extra panel to form editor.
*
* @param Array $panels Array form editro panel args.
*
* @return Array $panels Array form editro panel args.
*/
function wpcf7sp_add_panel( $panels ) {
$post = wpcf7_get_current_contact_form();
if ( current_user_can( 'wpcf7_edit_contact_form', $post->id() ) ) {
$panels['cf7-show-page-panel'] = array(
'title' => __( 'CF7 Show Pages', 'wpcf7sp' ),
'callback' => 'wpcf7sp_editor_panel_cf7_show_page'
);
}
return $panels;
}
add_filter( 'wpcf7_editor_panels', 'wpcf7sp_add_panel' );
// Get search string
function wpcf7sp_search_string( $form_id ) {
$wpcf7sp_form_id = $form_id->id();
$wpcf7sp_search_string = 'contact-form-7 id="' . $wpcf7sp_form_id . '"';
return $wpcf7sp_search_string;
}
/**
Search on postypes.
*/
function wpcf7sp_search_on_posttypes( $form_id ) {
$wpcf7sp_search_string = wpcf7sp_search_string( $form_id );
$wpcf7sp_posttypes = apply_filters( 'wpcf7sp_support_posttypes', get_post_types( array( 'public' => true ) ) );
if ( ! ( is_array( $wpcf7sp_posttypes ) || is_string( $wpcf7sp_posttypes ) ) ) {
$wpcf7sp_posttypes = get_post_types( array( 'public' => true ) );
}
$post_query = new WP_Query( array(
's' => $wpcf7sp_search_string,
'post_type' => $wpcf7sp_posttypes,
'posts_per_page' => -1
) );
if ( $post_query->have_posts() ) { ?>
<h4><?php _e( 'Lists of post types using this form.', 'wpcf7sp' ); ?></h4>
<table class="wpcf7sp">
<tbody>
<tr>
<th width="55%"><?php _e( 'Title', 'wpcf7sp' ); ?></th>
<th width="25%"><?php _e( 'Post Type', 'wpcf7sp' ); ?></th>
<th width="20%"></th>
</tr>
<?php
while ( $post_query->have_posts() ) {
$post_query->the_post();
$post_type = get_post_type();
?>
<tr>
<td width="50%"><?php the_title(); ?></td>
<td width="25%"><?php echo esc_html( $post_type ); ?></td>
<td width="25%" class="wpcf7sp-opt">
<a href="<?php the_permalink(); ?>" class="wpcf7sp-alink" target="_blank">View</a>
<a href="<?php echo esc_url( get_edit_post_link( get_the_ID() ) ); ?>" class="wpcf7sp-alink"
target="_blank"><?php _e( 'Edit', 'wpcf7sp' ); ?></a>
</td>
</tr>
<?php
}
?>
</tbody>
</table>
<?php
} else { ?>
<h4><?php _e( 'No "Posts" or "Pages" use this form right now.', 'wpcf7sp' ); ?></h4>
<?php }
}
/**
Search on text widget.
*/
function wpcf7sp_search_on_text_widget( $form_id ) {
$wpcf7sp_search_string = wpcf7sp_search_string( $form_id );
// Query for the text widgets with the contact form.
global $wpdb;
// Get prefixed table name.
$wpcf7sp_table = $wpdb->prefix . 'options';
// Prepare query which searches for option name with widget_text and also verify for the empty and no form used condition.
$wpcf7sp_widget_query = $wpdb->prepare( "SELECT * FROM `$wpcf7sp_table` WHERE `option_name` LIKE '%%widget_text%%' AND `option_value` LIKE '%%%s%%'", $wpcf7sp_search_string );
$wpcf7sp_widget_results = $wpdb->get_results( $wpcf7sp_widget_query );
if ( isset( $wpcf7sp_widget_results[0] )) {
$wpcf7sp_widget_results = $wpcf7sp_widget_results[0];
// Unserialize data which contains all the text widgets found.
$wpcf7sp_text_widgets = maybe_unserialize( $wpcf7sp_widget_results->option_value );
// Prepare search string to be searched in result.
$serach_expression = '/\[' . $wpcf7sp_search_string . '/';
$widget_ids = [];
foreach ( $wpcf7sp_text_widgets as $key => $value ) {
if ( is_array( $value ) ) {
// Check if the value is set and not empty and match with the search expression.
if ( isset( $value['text'] ) && ! empty( $value['text'] ) && preg_match( $serach_expression, $value['text'] ) ) {
// Append 'text-' to make it comparable in later in_array condition.
$widget_ids[] = 'text-' . $key;
}
}
}
// Query for the sidebars with the above found text widgets.
$widget_resp_sidebar_query = "SELECT * FROM `$wpcf7sp_table` WHERE `option_name` = 'sidebars_widgets'";
$widget_resp_sidebar_res = $wpdb->get_results( $widget_resp_sidebar_query );
// Unserialize data which contains all the sidebars.
$widget_resp_sidebar_res = maybe_unserialize( $widget_resp_sidebar_res[0]->option_value );
$side_bar_ids = [];
foreach ( $widget_resp_sidebar_res as $key => $value ) {
if ( ! empty( $value ) && is_array( $value ) ) {
for ( $i = 0; $i < count( $value ); $i ++ ) {
// Check if the above widget_ids is in the recently found array.
if ( in_array( $value[ $i ], $widget_ids ) ) {
$side_bar_ids[] = $key;
}
}
}
}
// Removing any repeating sidebar id.
$side_bar_ids = array_unique( $side_bar_ids );
?>
<h4><?php _e( 'Lists of widgets using this form.', 'wpcf7sp' ); ?></h4>
<?php if ( ! is_null( $wpcf7sp_text_widgets ) ): ?>
<table class="wpcf7sp" style="width: 50%;">
<tbody>
<tr>
<th><?php _e( 'Widget: Text', 'wpcf7sp' ); ?></th>
</tr>
<?php
foreach ( $side_bar_ids as $value ) {
global $wp_registered_sidebars;
if ( isset( $wp_registered_sidebars[ $value ] ) ) {
echo '<tr><td>' . esc_html( $wp_registered_sidebars[ $value ]['name'] ) . '</td></tr>';
}
}
?>
</tbody>
</table>
<?php endif; ?>
<?php } else { ?>
<h4><?php _e( 'No "Text widgets" uses this form right now.', 'wpcf7sp' ); ?></h4>
<?php }
}
/**
Search on text widget.
*/
function wpcf7sp_search_on_custom_html_widget( $form_id ) {
$wpcf7sp_search_string = wpcf7sp_search_string( $form_id );
// Query for the text widgets with the contact form.
global $wpdb;
// Get prefixed table name.
$wpcf7sp_table = $wpdb->prefix . 'options';
// Prepare query which searches for option name with widget_text and also verify for the empty and no form used condition.
$wpcf7sp_widget_query = $wpdb->prepare( "SELECT * FROM `$wpcf7sp_table` WHERE `option_name` LIKE '%%widget_custom_html%%' AND `option_value` LIKE '%%%s%%'", $wpcf7sp_search_string );
$wpcf7sp_widget_results = $wpdb->get_results( $wpcf7sp_widget_query );
if ( isset( $wpcf7sp_widget_results[0] )) {
$wpcf7sp_widget_results = $wpcf7sp_widget_results[0];
// Unserialize data which contains all the text widgets found.
$wpcf7sp_text_widgets = maybe_unserialize( $wpcf7sp_widget_results->option_value );
// Prepare search string to be searched in result.
$serach_expression = '/\[' . $wpcf7sp_search_string . '/';
$widget_ids = [];
foreach ( $wpcf7sp_text_widgets as $key => $value ) {
if ( is_array( $value ) ) {
// Check if the value is set and not empty and match with the search expression.
if ( isset( $value['content'] ) && ! empty( $value['content'] ) && preg_match( $serach_expression, $value['content'] ) ) {
// Append 'text-' to make it comparable in later in_array condition.
$widget_ids[] = 'custom_html-' . $key;
}
}
}
// Query for the sidebars with the above found text widgets.
$widget_resp_sidebar_query = "SELECT * FROM `$wpcf7sp_table` WHERE `option_name` = 'sidebars_widgets'";
$widget_resp_sidebar_res = $wpdb->get_results( $widget_resp_sidebar_query );
// Unserialize data which contains all the sidebars.
$widget_resp_sidebar_res = maybe_unserialize( $widget_resp_sidebar_res[0]->option_value );
$side_bar_ids = [];
foreach ( $widget_resp_sidebar_res as $key => $value ) {
if ( ! empty( $value ) && is_array( $value ) ) {
for ( $i = 0; $i < count( $value ); $i ++ ) {
// Check if the above widget_ids is in the recently found array.
if ( in_array( $value[ $i ], $widget_ids ) ) {
$side_bar_ids[] = $key;
}
}
}
}
// Removing any repeating sidebar id.
$side_bar_ids = array_unique( $side_bar_ids );
?>
<?php if ( ! is_null( $wpcf7sp_text_widgets ) ): ?>
<table class="wpcf7sp" style="width: 50%;">
<tbody>
<tr>
<th><?php _e( 'Widget: Custom HTML', 'wpcf7sp' ); ?></th>
</tr>
<?php
foreach ( $side_bar_ids as $value ) {
global $wp_registered_sidebars;
if ( isset( $wp_registered_sidebars[ $value ] ) ) {
echo '<tr><td>' . esc_html( $wp_registered_sidebars[ $value ]['name'] ) . '</td></tr>';
}
}
?>
</tbody>
</table>
<?php endif; ?>
<?php } else { ?>
<h4><?php _e( 'No "Custom HTML" widgets uses this form right now.', 'wpcf7sp' ); ?></h4>
<?php }
}
/**
* Show the panel itself
*
*/
function wpcf7sp_editor_panel_cf7_show_page( $form_id ) {
?>
<h2><?php echo esc_html( __( 'Contact Form 7 - Show Page', 'wpcf7sp' ) ); ?></h2>
<?php
wpcf7sp_search_on_posttypes( $form_id );
wpcf7sp_search_on_text_widget( $form_id );
wpcf7sp_search_on_custom_html_widget( $form_id );
}

View File

@@ -0,0 +1,37 @@
.wpcf7sp_panel h4 {
margin: 1.33em 0 .5em 0;
}
table.wpcf7sp {
width: 100%;
border: 1px inset #fff;
padding: 10px;
margin-top: 5px;
font-size: small;
}
table.wpcf7sp tr {
}
table.wpcf7sp th {
text-align: left;
padding: 10px 5px;
background: #e5e5e5;
border: 1px solid #dedede;
}
table.wpcf7sp td {
text-align: left;
padding: 10px;
}
.wpcf7sp-opt {
text-align: right !important;
}
a.wpcf7sp-alink {
background: #0085ba ;
color: #fff;
padding: 5px 10px;
border-radius: 3px;
text-decoration: none;
font-size: small;
}
table.wpcf7sp tr:nth-child( odd ) {
background: #f0f0f0;
}

View File

@@ -0,0 +1,79 @@
=== Contact Form 7 - Show Page ===
Contributors: ugene, sachyya-sachet
Donate link: #
Tags: Contact Form 7, form, forms, contactform7, contact form, find contact form, show page contact form 7, where contact form
Requires at least: 4.5
Tested up to: 4.9
Stable tag: 1.0.3
License: GPLv3
License URI: https://www.gnu.org/licenses/gpl-3.0.en.html
A simple WordPress plugin that helps you to know which contact forms are used in the site.
== Description ==
You don't need this plugin but hey, you might need this to quickly check where the contact forms are used. If you have good memory then you will good without it. But there is chance to forget it right?
So here below are the scenarios where you will find this plugin helpful:
1. You have multiple contact forms used in various pages and posts or may be used in widgets. To edit the one you like meaning find it first. This plugin will help you showing the post/page name with a link to view or edit that post or page. For the widget case, it will tell you whether the current form is used in the widget or not.
2. This is quite useful in this condition. Lets say you are a developer and you've come across the site where there are multiple contact forms. You might have to clean it up. This plugin will help you find and know if the contact form is used or not, meaning you are on your own far from the fear of mistakenly deleting the used one forms.
By default this plugin only supports the search in default post types (post/page). But you can extend the search in custom post types of your own further by using a quick filter hook like below:
`function extend_posttype_support ( $support ) {
return array( 'book', 'movie' );
}
add_filter( 'wpcf7sp_support_posttypes', 'extend_posttype_support' );`
== Usages ==
Backend
1. After installing the plugin, you will find a CF7 Show pages menu under each contact form edit page.
2. No settings, just view where the form is used. It wil list the name of post, pages in the table with a link to view and edit.
3. For other custom post types, filter is provided.
== Notes ==
1. [Contact Form 7](https://wordpress.org/plugins/contact-form-7/) must be activated.
== Installation ==
1. In your admin panel, go to Appearance > Plugins and click the Add New button.
2. Click Upload Theme and Choose File, then select the theme's .zip file. Click Install Now.
3. Click Activate to use your new theme right away.
== Frequently Asked Questions ==
= Do I have to activate contact form 7 plugin? =
Yes, this plugin is the extension to the famous Contact Form 7 plugin and thus Contact Form 7 is must.
== Screenshots ==
1. Overview
== Changelog ==
= 1.0.3 Dec 4 2018 =
* Upgrade: Search on **Custom HTML** widget too.
* Refactor code
* Add TGM Plugin Activation PHP library
= 1.0.2 =
* Add message when post types or widgets do not use the Contact Form.
= 1.0.1 =
* Extend plugin to search in widgets too but works only on **Text Widget** for now.
* Remove default private post types.
* Improve filter by checking for string and array only.
= 1.0 =
* Initial Release

View File

@@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/>
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
{description}
Copyright (C) {year} {fullname}
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
{signature of Ty Coon}, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

View File

@@ -0,0 +1,166 @@
<?php
/**
* This file represents an example of the code that themes would use to register
* the required plugins.
*
* It is expected that theme authors would copy and paste this code into their
* functions.php file, and amend to suit.
*
* @see http://tgmpluginactivation.com/configuration/ for detailed documentation.
*
* @package TGM-Plugin-Activation
* @subpackage Example
* @version 2.6.1 for plugin Wpcf7sp
* @author Thomas Griffin, Gary Jones, Juliette Reinders Folmer
* @copyright Copyright (c) 2011, Thomas Griffin
* @license http://opensource.org/licenses/gpl-2.0.php GPL v2 or later
* @link https://github.com/TGMPA/TGM-Plugin-Activation
*/
/**
* Include the TGM_Plugin_Activation class.
*
* Depending on your implementation, you may want to change the include call:
*
* Parent Theme:
* require_once get_template_directory() . '/path/to/class-tgm-plugin-activation.php';
*
* Child Theme:
* require_once get_stylesheet_directory() . '/path/to/class-tgm-plugin-activation.php';
*
* Plugin:
* require_once dirname( __FILE__ ) . '/path/to/class-tgm-plugin-activation.php';
*/
require_once dirname( __FILE__ ) . '/class-tgm-plugin-activation.php';
add_action( 'tgmpa_register', 'wpcf7sp_register_required_plugins' );
/**
* Register the required plugins for this theme.
*
* In this example, we register five plugins:
* - one included with the TGMPA library
* - two from an external source, one from an arbitrary source, one from a GitHub repository
* - two from the .org repo, where one demonstrates the use of the `is_callable` argument
*
* The variables passed to the `tgmpa()` function should be:
* - an array of plugin arrays;
* - optionally a configuration array.
* If you are not changing anything in the configuration array, you can remove the array and remove the
* variable from the function call: `tgmpa( $plugins );`.
* In that case, the TGMPA default settings will be used.
*
* This function is hooked into `tgmpa_register`, which is fired on the WP `init` action on priority 10.
*/
function wpcf7sp_register_required_plugins() {
/*
* Array of plugin arrays. Required keys are name and slug.
* If the source is NOT from the .org repo, then source is also required.
*/
$plugins = array(
// This is an example of how to include a plugin from the WordPress Plugin Repository.
array(
'name' => 'Contact Form 7',
'slug' => 'contact-form-7',
'required' => true,
),
);
/*
* Array of configuration settings. Amend each line as needed.
*
* TGMPA will start providing localized text strings soon. If you already have translations of our standard
* strings available, please help us make TGMPA even better by giving us access to these translations or by
* sending in a pull-request with .po file(s) with the translations.
*
* Only uncomment the strings in the config array if you want to customize the strings.
*/
$config = array(
'id' => 'wpcf7sp', // Unique ID for hashing notices for multiple instances of TGMPA.
'default_path' => '', // Default absolute path to bundled plugins.
'menu' => 'tgmpa-install-plugins', // Menu slug.
'parent_slug' => 'plugins.php', // Parent menu slug.
'capability' => 'manage_options', // Capability needed to view plugin install page, should be a capability associated with the parent menu used.
'has_notices' => true, // Show admin notices or not.
'dismissable' => true, // If false, a user cannot dismiss the nag message.
'dismiss_msg' => '', // If 'dismissable' is false, this message will be output at top of nag.
'is_automatic' => false, // Automatically activate plugins after installation or not.
'message' => '', // Message to output right before the plugins table.
'strings' => array(
'page_title' => __( 'Install Required Plugins', 'wpcf7sp' ),
'menu_title' => __( 'Install Plugins', 'wpcf7sp' ),
'installing' => __( 'Installing Plugin: %s', 'wpcf7sp' ),
'notice_can_install_required' => _n_noop(
'%1$s plugin is required for "Contact Form 7 - Show Page" to work.',
'%1$s plugin is required "Contact Form 7 - Show Page" to work.',
'wpcf7sp'
),
/* translators: %s: plugin name. * /
'updating' => __( 'Updating Plugin: %s', 'wpcf7sp' ),
'oops' => __( 'Something went wrong with the plugin API.', 'wpcf7sp' ),
'notice_can_install_recommended' => _n_noop(
/* translators: 1: plugin name(s). * /
'This theme recommends the following plugin: %1$s.',
'This theme recommends the following plugins: %1$s.',
'wpcf7sp'
),
'notice_ask_to_update' => _n_noop(
/* translators: 1: plugin name(s). * /
'The following plugin needs to be updated to its latest version to ensure maximum compatibility with this theme: %1$s.',
'The following plugins need to be updated to their latest version to ensure maximum compatibility with this theme: %1$s.',
'wpcf7sp'
),
'notice_ask_to_update_maybe' => _n_noop(
/* translators: 1: plugin name(s). * /
'There is an update available for: %1$s.',
'There are updates available for the following plugins: %1$s.',
'wpcf7sp'
),
'notice_can_activate_required' => _n_noop(
/* translators: 1: plugin name(s). * /
'The following required plugin is currently inactive: %1$s.',
'The following required plugins are currently inactive: %1$s.',
'wpcf7sp'
),
'notice_can_activate_recommended' => _n_noop(
/* translators: 1: plugin name(s). * /
'The following recommended plugin is currently inactive: %1$s.',
'The following recommended plugins are currently inactive: %1$s.',
'wpcf7sp'
),
'install_link' => _n_noop(
'Begin installing plugin',
'Begin installing plugins',
'wpcf7sp'
),
'update_link' => _n_noop(
'Begin updating plugin',
'Begin updating plugins',
'wpcf7sp'
),
'activate_link' => _n_noop(
'Begin activating plugin',
'Begin activating plugins',
'wpcf7sp'
),
'return' => __( 'Return to Required Plugins Installer', 'wpcf7sp' ),
'plugin_activated' => __( 'Plugin activated successfully.', 'wpcf7sp' ),
'activated_successfully' => __( 'The following plugin was activated successfully:', 'wpcf7sp' ),
/* translators: 1: plugin name. * /
'plugin_already_active' => __( 'No action taken. Plugin %1$s was already active.', 'wpcf7sp' ),
/* translators: 1: plugin name. * /
'plugin_needs_higher_version' => __( 'Plugin not activated. A higher version of %s is needed for this theme. Please update the plugin.', 'wpcf7sp' ),
/* translators: 1: dashboard link. * /
'complete' => __( 'All plugins installed and activated successfully. %1$s', 'wpcf7sp' ),
'dismiss' => __( 'Dismiss this notice', 'wpcf7sp' ),
'notice_cannot_install_activate' => __( 'There are one or more required or recommended plugins to install, update or activate.', 'wpcf7sp' ),
'contact_admin' => __( 'Please contact the administrator of this site for help.', 'wpcf7sp' ),
'nag_type' => '', // Determines admin notice type - can only be one of the typical WP notice classes, such as 'updated', 'update-nag', 'notice-warning', 'notice-info' or 'error'. Some of which may not work as expected in older WP versions.
*/
),
);
tgmpa( $plugins, $config );
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,400 @@
### WordPress - Web publishing software
Copyright 2011-2019 by the contributors
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
This program incorporates work covered by the following copyright and
permission notices:
b2 is (c) 2001, 2002 Michel Valdrighi - m@tidakada.com -
http://tidakada.com
Wherever third party code has been used, credit has been given in the code's
comments.
b2 is released under the GPL
and
WordPress - Web publishing software
Copyright 2003-2010 by the contributors
WordPress is released under the GPL
---
### GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
### Preamble
The licenses for most software are designed to take away your freedom
to share and change it. By contrast, the GNU General Public License is
intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if
you distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on,
we want its recipients to know that what they have is not the
original, so that any problems introduced by others will not reflect
on the original authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at
all.
The precise terms and conditions for copying, distribution and
modification follow.
### TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
**0.** This License applies to any program or other work which
contains a notice placed by the copyright holder saying it may be
distributed under the terms of this General Public License. The
"Program", below, refers to any such program or work, and a "work
based on the Program" means either the Program or any derivative work
under copyright law: that is to say, a work containing the Program or
a portion of it, either verbatim or with modifications and/or
translated into another language. (Hereinafter, translation is
included without limitation in the term "modification".) Each licensee
is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the Program
(independent of having been made by running the Program). Whether that
is true depends on what the Program does.
**1.** You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a
fee.
**2.** You may modify your copy or copies of the Program or any
portion of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
**a)** You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
**b)** You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any part
thereof, to be licensed as a whole at no charge to all third parties
under the terms of this License.
**c)** If the modified program normally reads commands interactively
when run, you must cause it, when started running for such interactive
use in the most ordinary way, to print or display an announcement
including an appropriate copyright notice and a notice that there is
no warranty (or else, saying that you provide a warranty) and that
users may redistribute the program under these conditions, and telling
the user how to view a copy of this License. (Exception: if the
Program itself is interactive but does not normally print such an
announcement, your work based on the Program is not required to print
an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
**3.** You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
**a)** Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections 1
and 2 above on a medium customarily used for software interchange; or,
**b)** Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your cost of
physically performing source distribution, a complete machine-readable
copy of the corresponding source code, to be distributed under the
terms of Sections 1 and 2 above on a medium customarily used for
software interchange; or,
**c)** Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is allowed
only for noncommercial distribution and only if you received the
program in object code or executable form with such an offer, in
accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
**4.** You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt otherwise
to copy, modify, sublicense or distribute the Program is void, and
will automatically terminate your rights under this License. However,
parties who have received copies, or rights, from you under this
License will not have their licenses terminated so long as such
parties remain in full compliance.
**5.** You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
**6.** Each time you redistribute the Program (or any work based on
the Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
**7.** If, as a consequence of a court judgment or allegation of
patent infringement or for any other reason (not limited to patent
issues), conditions are imposed on you (whether by court order,
agreement or otherwise) that contradict the conditions of this
License, they do not excuse you from the conditions of this License.
If you cannot distribute so as to satisfy simultaneously your
obligations under this License and any other pertinent obligations,
then as a consequence you may not distribute the Program at all. For
example, if a patent license would not permit royalty-free
redistribution of the Program by all those who receive copies directly
or indirectly through you, then the only way you could satisfy both it
and this License would be to refrain entirely from distribution of the
Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
**8.** If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
**9.** The Free Software Foundation may publish revised and/or new
versions of the General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Program does not specify a
version number of this License, you may choose any version ever
published by the Free Software Foundation.
**10.** If you wish to incorporate parts of the Program into other
free programs whose distribution conditions are different, write to
the author to ask for permission. For software which is copyrighted by
the Free Software Foundation, write to the Free Software Foundation;
we sometimes make exceptions for this. Our decision will be guided by
the two goals of preserving the free status of all derivatives of our
free software and of promoting the sharing and reuse of software
generally.
**NO WARRANTY**
**11.** BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
**12.** IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
### END OF TERMS AND CONDITIONS
### How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these
terms.
To do so, attach the following notices to the program. It is safest to
attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
one line to give the program's name and an idea of what it does.
Copyright (C) yyyy name of author
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Also add information on how to contact you by electronic and paper
mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details
type `show w'. This is free software, and you are welcome
to redistribute it under certain conditions; type `show c'
for details.
The hypothetical commands \`show w' and \`show c' should show the
appropriate parts of the General Public License. Of course, the
commands you use may be called something other than \`show w' and
\`show c'; they could even be mouse-clicks or menu items--whatever
suits your program.
You should also get your employer (if you work as a programmer) or
your school, if any, to sign a "copyright disclaimer" for the program,
if necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright
interest in the program `Gnomovision'
(which makes passes at compilers) written
by James Hacker.
signature of Ty Coon, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library,
you may consider it more useful to permit linking proprietary
applications with the library. If this is what you want to do, use the
[GNU Lesser General Public
License](http://www.gnu.org/licenses/lgpl.html) instead of this
License.

View File

@@ -0,0 +1,977 @@
<?php
/**
* Classic Editor
*
* Plugin Name: Classic Editor
* Plugin URI: https://wordpress.org/plugins/classic-editor/
* Description: Enables the WordPress classic editor and the old-style Edit Post screen with TinyMCE, Meta Boxes, etc. Supports the older plugins that extend this screen.
* Version: 1.6.3
* Author: WordPress Contributors
* Author URI: https://github.com/WordPress/classic-editor/
* License: GPLv2 or later
* License URI: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* Text Domain: classic-editor
* Domain Path: /languages
* Requires at least: 4.9
* Requires PHP: 5.2.4
*
* This program is free software; you can redistribute it and/or modify it under the terms of the GNU
* General Public License version 2, as published by the Free Software Foundation. You may NOT assume
* that you can use any other version of the GPL.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
if ( ! defined( 'ABSPATH' ) ) {
die( 'Invalid request.' );
}
if ( ! class_exists( 'Classic_Editor' ) ) :
class Classic_Editor {
private static $settings;
private static $supported_post_types = array();
private function __construct() {}
public static function init_actions() {
$block_editor = has_action( 'enqueue_block_assets' );
$gutenberg = function_exists( 'gutenberg_register_scripts_and_styles' );
register_activation_hook( __FILE__, array( __CLASS__, 'activate' ) );
$settings = self::get_settings();
if ( is_multisite() ) {
add_action( 'wpmu_options', array( __CLASS__, 'network_settings' ) );
add_action( 'update_wpmu_options', array( __CLASS__, 'save_network_settings' ) );
}
if ( ! $settings['hide-settings-ui'] ) {
// Add a link to the plugin's settings and/or network admin settings in the plugins list table.
add_filter( 'plugin_action_links', array( __CLASS__, 'add_settings_link' ), 10, 2 );
add_filter( 'network_admin_plugin_action_links', array( __CLASS__, 'add_settings_link' ), 10, 2 );
add_action( 'admin_init', array( __CLASS__, 'register_settings' ) );
if ( $settings['allow-users'] ) {
// User settings.
add_action( 'personal_options_update', array( __CLASS__, 'save_user_settings' ) );
add_action( 'profile_personal_options', array( __CLASS__, 'user_settings' ) );
}
}
// Always remove the "Try Gutenberg" dashboard widget. See https://core.trac.wordpress.org/ticket/44635.
remove_action( 'try_gutenberg_panel', 'wp_try_gutenberg_panel' );
if ( ! $block_editor && ! $gutenberg ) {
return;
}
if ( $settings['allow-users'] ) {
// Also used in Gutenberg.
add_filter( 'use_block_editor_for_post', array( __CLASS__, 'choose_editor' ), 100, 2 );
if ( $gutenberg ) {
// Support older Gutenberg versions.
add_filter( 'gutenberg_can_edit_post', array( __CLASS__, 'choose_editor' ), 100, 2 );
if ( $settings['editor'] === 'classic' ) {
self::remove_gutenberg_hooks( 'some' );
}
}
add_filter( 'get_edit_post_link', array( __CLASS__, 'get_edit_post_link' ) );
add_filter( 'redirect_post_location', array( __CLASS__, 'redirect_location' ) );
add_action( 'edit_form_top', array( __CLASS__, 'add_redirect_helper' ) );
add_action( 'admin_head-edit.php', array( __CLASS__, 'add_edit_php_inline_style' ) );
add_action( 'edit_form_top', array( __CLASS__, 'remember_classic_editor' ) );
if ( version_compare( $GLOBALS['wp_version'], '5.8', '>=' ) ) {
add_filter( 'block_editor_settings_all', array( __CLASS__, 'remember_block_editor' ), 10, 2 );
} else {
add_filter( 'block_editor_settings', array( __CLASS__, 'remember_block_editor' ), 10, 2 );
}
// Post state (edit.php)
add_filter( 'display_post_states', array( __CLASS__, 'add_post_state' ), 10, 2 );
// Row actions (edit.php)
add_filter( 'page_row_actions', array( __CLASS__, 'add_edit_links' ), 15, 2 );
add_filter( 'post_row_actions', array( __CLASS__, 'add_edit_links' ), 15, 2 );
// Switch editors while editing a post
add_action( 'add_meta_boxes', array( __CLASS__, 'add_meta_box' ), 10, 2 );
add_action( 'enqueue_block_editor_assets', array( __CLASS__, 'enqueue_block_editor_scripts' ) );
} else {
if ( $settings['editor'] === 'classic' ) {
// Also used in Gutenberg.
// Consider disabling other Block Editor functionality.
add_filter( 'use_block_editor_for_post_type', '__return_false', 100 );
if ( $gutenberg ) {
// Support older Gutenberg versions.
add_filter( 'gutenberg_can_edit_post_type', '__return_false', 100 );
self::remove_gutenberg_hooks();
}
} else {
// $settings['editor'] === 'block', nothing to do :)
return;
}
}
if ( $block_editor ) {
// Move the Privacy Page notice back under the title.
add_action( 'admin_init', array( __CLASS__, 'on_admin_init' ) );
}
if ( $gutenberg ) {
// These are handled by this plugin. All are older, not used in 5.3+.
remove_action( 'admin_init', 'gutenberg_add_edit_link_filters' );
remove_action( 'admin_print_scripts-edit.php', 'gutenberg_replace_default_add_new_button' );
remove_filter( 'redirect_post_location', 'gutenberg_redirect_to_classic_editor_when_saving_posts' );
remove_filter( 'display_post_states', 'gutenberg_add_gutenberg_post_state' );
remove_action( 'edit_form_top', 'gutenberg_remember_classic_editor_when_saving_posts' );
}
}
public static function remove_gutenberg_hooks( $remove = 'all' ) {
remove_action( 'admin_menu', 'gutenberg_menu' );
remove_action( 'admin_init', 'gutenberg_redirect_demo' );
if ( $remove !== 'all' ) {
return;
}
// Gutenberg 5.3+
remove_action( 'wp_enqueue_scripts', 'gutenberg_register_scripts_and_styles' );
remove_action( 'admin_enqueue_scripts', 'gutenberg_register_scripts_and_styles' );
remove_action( 'admin_notices', 'gutenberg_wordpress_version_notice' );
remove_action( 'rest_api_init', 'gutenberg_register_rest_widget_updater_routes' );
remove_action( 'admin_print_styles', 'gutenberg_block_editor_admin_print_styles' );
remove_action( 'admin_print_scripts', 'gutenberg_block_editor_admin_print_scripts' );
remove_action( 'admin_print_footer_scripts', 'gutenberg_block_editor_admin_print_footer_scripts' );
remove_action( 'admin_footer', 'gutenberg_block_editor_admin_footer' );
remove_action( 'admin_enqueue_scripts', 'gutenberg_widgets_init' );
remove_action( 'admin_notices', 'gutenberg_build_files_notice' );
remove_filter( 'load_script_translation_file', 'gutenberg_override_translation_file' );
remove_filter( 'block_editor_settings', 'gutenberg_extend_block_editor_styles' );
remove_filter( 'default_content', 'gutenberg_default_demo_content' );
remove_filter( 'default_title', 'gutenberg_default_demo_title' );
remove_filter( 'block_editor_settings', 'gutenberg_legacy_widget_settings' );
remove_filter( 'rest_request_after_callbacks', 'gutenberg_filter_oembed_result' );
// Previously used, compat for older Gutenberg versions.
remove_filter( 'wp_refresh_nonces', 'gutenberg_add_rest_nonce_to_heartbeat_response_headers' );
remove_filter( 'get_edit_post_link', 'gutenberg_revisions_link_to_editor' );
remove_filter( 'wp_prepare_revision_for_js', 'gutenberg_revisions_restore' );
remove_action( 'rest_api_init', 'gutenberg_register_rest_routes' );
remove_action( 'rest_api_init', 'gutenberg_add_taxonomy_visibility_field' );
remove_filter( 'registered_post_type', 'gutenberg_register_post_prepare_functions' );
remove_action( 'do_meta_boxes', 'gutenberg_meta_box_save' );
remove_action( 'submitpost_box', 'gutenberg_intercept_meta_box_render' );
remove_action( 'submitpage_box', 'gutenberg_intercept_meta_box_render' );
remove_action( 'edit_page_form', 'gutenberg_intercept_meta_box_render' );
remove_action( 'edit_form_advanced', 'gutenberg_intercept_meta_box_render' );
remove_filter( 'redirect_post_location', 'gutenberg_meta_box_save_redirect' );
remove_filter( 'filter_gutenberg_meta_boxes', 'gutenberg_filter_meta_boxes' );
remove_filter( 'body_class', 'gutenberg_add_responsive_body_class' );
remove_filter( 'admin_url', 'gutenberg_modify_add_new_button_url' ); // old
remove_action( 'admin_enqueue_scripts', 'gutenberg_check_if_classic_needs_warning_about_blocks' );
remove_filter( 'register_post_type_args', 'gutenberg_filter_post_type_labels' );
// phpcs:disable Squiz.PHP.CommentedOutCode.Found
// Keep
// remove_filter( 'wp_kses_allowed_html', 'gutenberg_kses_allowedtags', 10, 2 ); // not needed in 5.0
// remove_filter( 'bulk_actions-edit-wp_block', 'gutenberg_block_bulk_actions' );
// remove_filter( 'wp_insert_post_data', 'gutenberg_remove_wpcom_markdown_support' );
// remove_filter( 'the_content', 'do_blocks', 9 );
// remove_action( 'init', 'gutenberg_register_post_types' );
// Continue to manage wpautop for posts that were edited in Gutenberg.
// remove_filter( 'wp_editor_settings', 'gutenberg_disable_editor_settings_wpautop' );
// remove_filter( 'the_content', 'gutenberg_wpautop', 8 );
// phpcs:enable Squiz.PHP.CommentedOutCode.Found
}
private static function get_settings( $refresh = 'no' ) {
/**
* Can be used to override the plugin's settings. Always hides the settings UI when used (as users cannot change the settings).
*
* Has to return an associative array with two keys.
* The defaults are:
* 'editor' => 'classic', // Accepted values: 'classic', 'block'.
* 'allow-users' => false,
*
* @param boolean To override the settings return an array with the above keys.
*/
$settings = apply_filters( 'classic_editor_plugin_settings', false );
if ( is_array( $settings ) ) {
return array(
'editor' => ( isset( $settings['editor'] ) && $settings['editor'] === 'block' ) ? 'block' : 'classic',
'allow-users' => ! empty( $settings['allow-users'] ),
'hide-settings-ui' => true,
);
}
if ( ! empty( self::$settings ) && $refresh === 'no' ) {
return self::$settings;
}
if ( is_multisite() ) {
$defaults = array(
'editor' => get_network_option( null, 'classic-editor-replace' ) === 'block' ? 'block' : 'classic',
'allow-users' => false,
);
/**
* Filters the default network options.
*
* @param array $defaults The default options array. See `classic_editor_plugin_settings` for supported keys and values.
*/
$defaults = apply_filters( 'classic_editor_network_default_settings', $defaults );
if ( get_network_option( null, 'classic-editor-allow-sites' ) !== 'allow' ) {
// Per-site settings are disabled. Return default network options nad hide the settings UI.
$defaults['hide-settings-ui'] = true;
return $defaults;
}
// Override with the site options.
$editor_option = get_option( 'classic-editor-replace' );
$allow_users_option = get_option( 'classic-editor-allow-users' );
if ( $editor_option ) {
$defaults['editor'] = $editor_option;
}
if ( $allow_users_option ) {
$defaults['allow-users'] = ( $allow_users_option === 'allow' );
}
$editor = ( isset( $defaults['editor'] ) && $defaults['editor'] === 'block' ) ? 'block' : 'classic';
$allow_users = ! empty( $defaults['allow-users'] );
} else {
$allow_users = ( get_option( 'classic-editor-allow-users' ) === 'allow' );
$option = get_option( 'classic-editor-replace' );
// Normalize old options.
if ( $option === 'block' || $option === 'no-replace' ) {
$editor = 'block';
} else {
// empty( $option ) || $option === 'classic' || $option === 'replace'
$editor = 'classic';
}
}
// Override the defaults with the user options.
if ( ( ! isset( $GLOBALS['pagenow'] ) || $GLOBALS['pagenow'] !== 'options-writing.php' ) && $allow_users ) {
$user_options = get_user_option( 'classic-editor-settings' );
if ( $user_options === 'block' || $user_options === 'classic' ) {
$editor = $user_options;
}
}
self::$settings = array(
'editor' => $editor,
'hide-settings-ui' => false,
'allow-users' => $allow_users,
);
return self::$settings;
}
private static function is_classic( $post_id = 0 ) {
if ( ! $post_id ) {
$post_id = self::get_edited_post_id();
}
if ( $post_id ) {
$settings = self::get_settings();
if ( $settings['allow-users'] && ! isset( $_GET['classic-editor__forget'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$which = get_post_meta( $post_id, 'classic-editor-remember', true );
if ( $which ) {
// The editor choice will be "remembered" when the post is opened in either the classic or the block editor.
if ( 'classic-editor' === $which ) {
return true;
} elseif ( 'block-editor' === $which ) {
return false;
}
}
return ( ! self::has_blocks( $post_id ) );
}
}
if ( isset( $_GET['classic-editor'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
return true;
}
return false;
}
/**
* Get the edited post ID (early) when loading the Edit Post screen.
*/
private static function get_edited_post_id() {
// phpcs:disable WordPress.Security.NonceVerification.Recommended
if (
! empty( $_GET['post'] ) &&
! empty( $_GET['action'] ) &&
$_GET['action'] === 'edit' &&
! empty( $GLOBALS['pagenow'] ) &&
$GLOBALS['pagenow'] === 'post.php'
) {
return (int) $_GET['post']; // post_ID
}
// phpcs:enable WordPress.Security.NonceVerification.Recommended
return 0;
}
public static function register_settings() {
// Add an option to Settings -> Writing
register_setting( 'writing', 'classic-editor-replace', array(
'sanitize_callback' => array( __CLASS__, 'validate_option_editor' ),
) );
register_setting( 'writing', 'classic-editor-allow-users', array(
'sanitize_callback' => array( __CLASS__, 'validate_option_allow_users' ),
) );
$allowed_options = array(
'writing' => array(
'classic-editor-replace',
'classic-editor-allow-users'
),
);
if ( function_exists( 'add_allowed_options' ) ) {
add_allowed_options( $allowed_options );
} else {
add_option_whitelist( $allowed_options );
}
$heading_1 = __( 'Default editor for all users', 'classic-editor' );
$heading_2 = __( 'Allow users to switch editors', 'classic-editor' );
add_settings_field( 'classic-editor-1', $heading_1, array( __CLASS__, 'settings_1' ), 'writing' );
add_settings_field( 'classic-editor-2', $heading_2, array( __CLASS__, 'settings_2' ), 'writing' );
}
public static function save_user_settings( $user_id ) {
if (
isset( $_POST['classic-editor-user-settings'] ) &&
isset( $_POST['classic-editor-replace'] ) &&
wp_verify_nonce( $_POST['classic-editor-user-settings'], 'allow-user-settings' ) // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
) {
$user_id = (int) $user_id;
if ( $user_id !== get_current_user_id() && ! current_user_can( 'edit_user', $user_id ) ) {
return;
}
$editor = self::validate_option_editor( $_POST['classic-editor-replace'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
update_user_option( $user_id, 'classic-editor-settings', $editor );
}
}
/**
* Validate
*/
public static function validate_option_editor( $value ) {
if ( $value === 'block' ) {
return 'block';
}
return 'classic';
}
public static function validate_option_allow_users( $value ) {
if ( $value === 'allow' ) {
return 'allow';
}
return 'disallow';
}
public static function settings_1() {
$settings = self::get_settings( 'refresh' );
?>
<div class="classic-editor-options">
<p>
<input type="radio" name="classic-editor-replace" id="classic-editor-classic" value="classic"<?php if ( $settings['editor'] === 'classic' ) echo ' checked'; ?> />
<label for="classic-editor-classic"><?php _ex( 'Classic editor', 'Editor Name', 'classic-editor' ); ?></label>
</p>
<p>
<input type="radio" name="classic-editor-replace" id="classic-editor-block" value="block"<?php if ( $settings['editor'] !== 'classic' ) echo ' checked'; ?> />
<label for="classic-editor-block"><?php _ex( 'Block editor', 'Editor Name', 'classic-editor' ); ?></label>
</p>
</div>
<script>
jQuery( 'document' ).ready( function( $ ) {
if ( window.location.hash === '#classic-editor-options' ) {
$( '.classic-editor-options' ).closest( 'td' ).addClass( 'highlight' );
}
} );
</script>
<?php
}
public static function settings_2() {
$settings = self::get_settings( 'refresh' );
?>
<div class="classic-editor-options">
<p>
<input type="radio" name="classic-editor-allow-users" id="classic-editor-allow" value="allow"<?php if ( $settings['allow-users'] ) echo ' checked'; ?> />
<label for="classic-editor-allow"><?php _e( 'Yes', 'classic-editor' ); ?></label>
</p>
<p>
<input type="radio" name="classic-editor-allow-users" id="classic-editor-disallow" value="disallow"<?php if ( ! $settings['allow-users'] ) echo ' checked'; ?> />
<label for="classic-editor-disallow"><?php _e( 'No', 'classic-editor' ); ?></label>
</p>
</div>
<?php
}
/**
* Shown on the Profile page when allowed by admin.
*/
public static function user_settings() {
global $user_can_edit;
$settings = self::get_settings( 'update' );
if (
! defined( 'IS_PROFILE_PAGE' ) ||
! IS_PROFILE_PAGE ||
! $user_can_edit ||
! $settings['allow-users']
) {
return;
}
?>
<table class="form-table">
<tr class="classic-editor-user-options">
<th scope="row"><?php _e( 'Default Editor', 'classic-editor' ); ?></th>
<td>
<?php wp_nonce_field( 'allow-user-settings', 'classic-editor-user-settings' ); ?>
<?php self::settings_1(); ?>
</td>
</tr>
</table>
<script>jQuery( 'tr.user-rich-editing-wrap' ).before( jQuery( 'tr.classic-editor-user-options' ) );</script>
<?php
}
public static function network_settings() {
$editor = get_network_option( null, 'classic-editor-replace' );
$is_checked = ( get_network_option( null, 'classic-editor-allow-sites' ) === 'allow' );
?>
<h2 id="classic-editor-options"><?php _e( 'Editor Settings', 'classic-editor' ); ?></h2>
<table class="form-table">
<?php wp_nonce_field( 'allow-site-admin-settings', 'classic-editor-network-settings' ); ?>
<tr>
<th scope="row"><?php _e( 'Default editor for all sites', 'classic-editor' ); ?></th>
<td>
<p>
<input type="radio" name="classic-editor-replace" id="classic-editor-classic" value="classic"<?php if ( $editor !== 'block' ) echo ' checked'; ?> />
<label for="classic-editor-classic"><?php _ex( 'Classic Editor', 'Editor Name', 'classic-editor' ); ?></label>
</p>
<p>
<input type="radio" name="classic-editor-replace" id="classic-editor-block" value="block"<?php if ( $editor === 'block' ) echo ' checked'; ?> />
<label for="classic-editor-block"><?php _ex( 'Block editor', 'Editor Name', 'classic-editor' ); ?></label>
</p>
</td>
</tr>
<tr>
<th scope="row"><?php _e( 'Change settings', 'classic-editor' ); ?></th>
<td>
<input type="checkbox" name="classic-editor-allow-sites" id="classic-editor-allow-sites" value="allow"<?php if ( $is_checked ) echo ' checked'; ?>>
<label for="classic-editor-allow-sites"><?php _e( 'Allow site admins to change settings', 'classic-editor' ); ?></label>
<p class="description"><?php _e( 'By default the block editor is replaced with the classic editor and users cannot switch editors.', 'classic-editor' ); ?></p>
</td>
</tr>
</table>
<?php
}
public static function save_network_settings() {
if (
isset( $_POST['classic-editor-network-settings'] ) &&
current_user_can( 'manage_network_options' ) &&
wp_verify_nonce( $_POST['classic-editor-network-settings'], 'allow-site-admin-settings' ) // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
) {
if ( isset( $_POST['classic-editor-replace'] ) && $_POST['classic-editor-replace'] === 'block' ) {
update_network_option( null, 'classic-editor-replace', 'block' );
} else {
update_network_option( null, 'classic-editor-replace', 'classic' );
}
if ( isset( $_POST['classic-editor-allow-sites'] ) && $_POST['classic-editor-allow-sites'] === 'allow' ) {
update_network_option( null, 'classic-editor-allow-sites', 'allow' );
} else {
update_network_option( null, 'classic-editor-allow-sites', 'disallow' );
}
}
}
/**
* Add a hidden field in edit-form-advanced.php
* to help redirect back to the classic editor on saving.
*/
public static function add_redirect_helper() {
?>
<input type="hidden" name="classic-editor" value="" />
<?php
}
/**
* Remember when the classic editor was used to edit a post.
*/
public static function remember_classic_editor( $post ) {
$post_type = get_post_type( $post );
if ( $post_type && post_type_supports( $post_type, 'editor' ) ) {
self::remember( $post->ID, 'classic-editor' );
}
}
/**
* Remember when the block editor was used to edit a post.
*/
public static function remember_block_editor( $editor_settings, $context ) {
if ( is_a( $context, 'WP_Post' ) ) {
$post = $context;
} elseif ( ! empty( $context->post ) ) {
$post = $context->post;
} else {
return $editor_settings;
}
$post_type = get_post_type( $post );
if ( $post_type && self::can_edit_post_type( $post_type ) ) {
self::remember( $post->ID, 'block-editor' );
}
return $editor_settings;
}
private static function remember( $post_id, $editor ) {
if ( get_post_meta( $post_id, 'classic-editor-remember', true ) !== $editor ) {
update_post_meta( $post_id, 'classic-editor-remember', $editor );
}
}
/**
* Choose which editor to use for a post.
*
* Passes through `$which_editor` for block editor (it's sets to `true` but may be changed by another plugin).
*
* @uses `use_block_editor_for_post` filter.
*
* @param boolean $use_block_editor True for block editor, false for classic editor.
* @param WP_Post $post The post being edited.
* @return boolean True for block editor, false for classic editor.
*/
public static function choose_editor( $use_block_editor, $post ) {
$settings = self::get_settings();
$editors = self::get_enabled_editors_for_post( $post );
// If no editor is supported, pass through `$use_block_editor`.
if ( ! $editors['block_editor'] && ! $editors['classic_editor'] ) {
return $use_block_editor;
}
// Open the default editor when no $post and for "Add New" links,
// or the alternate editor when the user is switching editors.
// phpcs:disable WordPress.Security.NonceVerification.Recommended
if ( empty( $post->ID ) || $post->post_status === 'auto-draft' ) {
if (
( $settings['editor'] === 'classic' && ! isset( $_GET['classic-editor__forget'] ) ) || // Add New
( isset( $_GET['classic-editor'] ) && isset( $_GET['classic-editor__forget'] ) ) // Switch to classic editor when no draft post.
) {
$use_block_editor = false;
}
} elseif ( self::is_classic( $post->ID ) ) {
$use_block_editor = false;
}
// phpcs:enable WordPress.Security.NonceVerification.Recommended
// Enforce the editor if set by plugins.
if ( $use_block_editor && ! $editors['block_editor'] ) {
$use_block_editor = false;
} elseif ( ! $use_block_editor && ! $editors['classic_editor'] && $editors['block_editor'] ) {
$use_block_editor = true;
}
return $use_block_editor;
}
/**
* Keep the `classic-editor` query arg through redirects when saving posts.
*/
public static function redirect_location( $location ) {
if (
isset( $_REQUEST['classic-editor'] ) || // phpcs:ignore WordPress.Security.NonceVerification.Recommended
( isset( $_POST['_wp_http_referer'] ) && strpos( $_POST['_wp_http_referer'], '&classic-editor' ) !== false ) // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification.Missing
) {
$location = add_query_arg( 'classic-editor', '', $location );
}
return $location;
}
/**
* Keep the `classic-editor` query arg when looking at revisions.
*/
public static function get_edit_post_link( $url ) {
$settings = self::get_settings();
if ( isset( $_REQUEST['classic-editor'] ) || $settings['editor'] === 'classic' ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$url = add_query_arg( 'classic-editor', '', $url );
}
return $url;
}
public static function add_meta_box( $post_type, $post ) {
$editors = self::get_enabled_editors_for_post( $post );
if ( ! $editors['block_editor'] || ! $editors['classic_editor'] ) {
// Editors cannot be switched.
return;
}
$id = 'classic-editor-switch-editor';
$title = __( 'Editor', 'classic-editor' );
$callback = array( __CLASS__, 'do_meta_box' );
$args = array(
'__back_compat_meta_box' => true,
);
add_meta_box( $id, $title, $callback, null, 'side', 'default', $args );
}
public static function do_meta_box( $post ) {
$edit_url = get_edit_post_link( $post->ID, 'raw' );
// Switching to block editor.
$edit_url = remove_query_arg( 'classic-editor', $edit_url );
// Forget the previous value when going to a specific editor.
$edit_url = add_query_arg( 'classic-editor__forget', '', $edit_url );
?>
<p style="margin: 1em 0;">
<a href="<?php echo esc_url( $edit_url ); ?>"><?php _e( 'Switch to block editor', 'classic-editor' ); ?></a>
</p>
<?php
}
public static function enqueue_block_editor_scripts() {
// get_enabled_editors_for_post() needs a WP_Post or post_ID.
if ( empty( $GLOBALS['post'] ) ) {
return;
}
$editors = self::get_enabled_editors_for_post( $GLOBALS['post'] );
if ( ! $editors['classic_editor'] ) {
// Editor cannot be switched.
return;
}
wp_enqueue_script(
'classic-editor-plugin',
plugins_url( 'js/block-editor-plugin.js', __FILE__ ),
array( 'wp-element', 'wp-components', 'lodash' ),
'1.4',
true
);
wp_localize_script(
'classic-editor-plugin',
'classicEditorPluginL10n',
array( 'linkText' => __( 'Switch to classic editor', 'classic-editor' ) )
);
}
/**
* Add a link to the settings on the Plugins screen.
*/
public static function add_settings_link( $links, $file ) {
$settings = self::get_settings();
if ( $file === 'classic-editor/classic-editor.php' && ! $settings['hide-settings-ui'] && current_user_can( 'manage_options' ) ) {
if ( current_filter() === 'plugin_action_links' ) {
$url = admin_url( 'options-writing.php#classic-editor-options' );
} else {
$url = admin_url( '/network/settings.php#classic-editor-options' );
}
// Prevent warnings in PHP 7.0+ when a plugin uses this filter incorrectly.
$links = (array) $links;
$links[] = sprintf( '<a href="%s">%s</a>', $url, __( 'Settings', 'classic-editor' ) );
}
return $links;
}
private static function can_edit_post_type( $post_type ) {
$can_edit = false;
if ( function_exists( 'gutenberg_can_edit_post_type' ) ) {
$can_edit = gutenberg_can_edit_post_type( $post_type );
} elseif ( function_exists( 'use_block_editor_for_post_type' ) ) {
$can_edit = use_block_editor_for_post_type( $post_type );
}
return $can_edit;
}
/**
* Checks which editors are enabled for the post type.
*
* @param string $post_type The post type.
* @return array Associative array of the editors and whether they are enabled for the post type.
*/
private static function get_enabled_editors_for_post_type( $post_type ) {
if ( isset( self::$supported_post_types[ $post_type ] ) ) {
return self::$supported_post_types[ $post_type ];
}
$classic_editor = post_type_supports( $post_type, 'editor' );
$block_editor = self::can_edit_post_type( $post_type );
$editors = array(
'classic_editor' => $classic_editor,
'block_editor' => $block_editor,
);
/**
* Filters the editors that are enabled for the post type.
*
* @param array $editors Associative array of the editors and whether they are enabled for the post type.
* @param string $post_type The post type.
*/
$editors = apply_filters( 'classic_editor_enabled_editors_for_post_type', $editors, $post_type );
self::$supported_post_types[ $post_type ] = $editors;
return $editors;
}
/**
* Checks which editors are enabled for the post.
*
* @param WP_Post $post The post object.
* @return array Associative array of the editors and whether they are enabled for the post.
*/
private static function get_enabled_editors_for_post( $post ) {
$post_type = get_post_type( $post );
if ( ! $post_type ) {
return array(
'classic_editor' => false,
'block_editor' => false,
);
}
$editors = self::get_enabled_editors_for_post_type( $post_type );
/**
* Filters the editors that are enabled for the post.
*
* @param array $editors Associative array of the editors and whether they are enabled for the post.
* @param WP_Post $post The post object.
*/
return apply_filters( 'classic_editor_enabled_editors_for_post', $editors, $post );
}
/**
* Adds links to the post/page screens to edit any post or page in
* the classic editor or block editor.
*
* @param array $actions Post actions.
* @param WP_Post $post Edited post.
* @return array Updated post actions.
*/
public static function add_edit_links( $actions, $post ) {
// This is in Gutenberg, don't duplicate it.
if ( array_key_exists( 'classic', $actions ) ) {
unset( $actions['classic'] );
}
if ( ! array_key_exists( 'edit', $actions ) ) {
return $actions;
}
$edit_url = get_edit_post_link( $post->ID, 'raw' );
if ( ! $edit_url ) {
return $actions;
}
$editors = self::get_enabled_editors_for_post( $post );
// Do not show the links if only one editor is available.
if ( ! $editors['classic_editor'] || ! $editors['block_editor'] ) {
return $actions;
}
// Forget the previous value when going to a specific editor.
$edit_url = add_query_arg( 'classic-editor__forget', '', $edit_url );
// Build the edit actions. See also: WP_Posts_List_Table::handle_row_actions().
$title = _draft_or_post_title( $post->ID );
// Link to the block editor.
$url = remove_query_arg( 'classic-editor', $edit_url );
$text = _x( 'Edit (block editor)', 'Editor Name', 'classic-editor' );
/* translators: %s: post title */
$label = sprintf( __( 'Edit &#8220;%s&#8221; in the block editor', 'classic-editor' ), $title );
$edit_block = sprintf( '<a href="%s" aria-label="%s">%s</a>', esc_url( $url ), esc_attr( $label ), $text );
// Link to the classic editor.
$url = add_query_arg( 'classic-editor', '', $edit_url );
$text = _x( 'Edit (classic editor)', 'Editor Name', 'classic-editor' );
/* translators: %s: post title */
$label = sprintf( __( 'Edit &#8220;%s&#8221; in the classic editor', 'classic-editor' ), $title );
$edit_classic = sprintf( '<a href="%s" aria-label="%s">%s</a>', esc_url( $url ), esc_attr( $label ), $text );
$edit_actions = array(
'classic-editor-block' => $edit_block,
'classic-editor-classic' => $edit_classic,
);
// Insert the new Edit actions instead of the Edit action.
$edit_offset = array_search( 'edit', array_keys( $actions ), true );
array_splice( $actions, $edit_offset, 1, $edit_actions );
return $actions;
}
/**
* Show the editor that will be used in a "post state" in the Posts list table.
*/
public static function add_post_state( $post_states, $post ) {
if ( get_post_status( $post ) === 'trash' ) {
return $post_states;
}
$editors = self::get_enabled_editors_for_post( $post );
if ( ! $editors['classic_editor'] && ! $editors['block_editor'] ) {
return $post_states;
} elseif ( $editors['classic_editor'] && ! $editors['block_editor'] ) {
// Forced to classic editor.
$state = '<span class="classic-editor-forced-state">' . _x( 'classic editor', 'Editor Name', 'classic-editor' ) . '</span>';
} elseif ( ! $editors['classic_editor'] && $editors['block_editor'] ) {
// Forced to block editor.
$state = '<span class="classic-editor-forced-state">' . _x( 'block editor', 'Editor Name', 'classic-editor' ) . '</span>';
} else {
$last_editor = get_post_meta( $post->ID, 'classic-editor-remember', true );
if ( $last_editor ) {
$is_classic = ( $last_editor === 'classic-editor' );
} elseif ( ! empty( $post->post_content ) ) {
$is_classic = ! self::has_blocks( $post->post_content );
} else {
$settings = self::get_settings();
$is_classic = ( $settings['editor'] === 'classic' );
}
$state = $is_classic ? _x( 'Classic editor', 'Editor Name', 'classic-editor' ) : _x( 'Block editor', 'Editor Name', 'classic-editor' );
}
// Fix PHP 7+ warnings if another plugin returns unexpected type.
$post_states = (array) $post_states;
$post_states['classic-editor-plugin'] = $state;
return $post_states;
}
public static function add_edit_php_inline_style() {
?>
<style>
.classic-editor-forced-state {
font-style: italic;
font-weight: 400;
color: #72777c;
font-size: small;
}
</style>
<?php
}
public static function on_admin_init() {
global $pagenow;
if ( $pagenow !== 'post.php' ) {
return;
}
$settings = self::get_settings();
$post_id = self::get_edited_post_id();
if ( $post_id && ( $settings['editor'] === 'classic' || self::is_classic( $post_id ) ) ) {
// Move the Privacy Policy help notice back under the title field.
remove_action( 'admin_notices', array( 'WP_Privacy_Policy_Content', 'notice' ) );
add_action( 'edit_form_after_title', array( 'WP_Privacy_Policy_Content', 'notice' ) );
}
}
// Need to support WP < 5.0
private static function has_blocks( $post = null ) {
if ( ! is_string( $post ) ) {
$wp_post = get_post( $post );
if ( $wp_post instanceof WP_Post ) {
$post = $wp_post->post_content;
}
}
return false !== strpos( (string) $post, '<!-- wp:' );
}
/**
* Set defaults on activation.
*/
public static function activate() {
register_uninstall_hook( __FILE__, array( __CLASS__, 'uninstall' ) );
if ( is_multisite() ) {
add_network_option( null, 'classic-editor-replace', 'classic' );
add_network_option( null, 'classic-editor-allow-sites', 'disallow' );
}
add_option( 'classic-editor-replace', 'classic' );
add_option( 'classic-editor-allow-users', 'disallow' );
}
/**
* Delete the options on uninstall.
*/
public static function uninstall() {
if ( is_multisite() ) {
delete_network_option( null, 'classic-editor-replace' );
delete_network_option( null, 'classic-editor-allow-sites' );
}
delete_option( 'classic-editor-replace' );
delete_option( 'classic-editor-allow-users' );
}
}
add_action( 'plugins_loaded', array( 'Classic_Editor', 'init_actions' ) );
endif;

View File

@@ -0,0 +1,23 @@
( function( wp ) {
if ( ! wp ) {
return;
}
wp.plugins.registerPlugin( 'classic-editor-plugin', {
render: function() {
var createElement = wp.element.createElement;
var PluginMoreMenuItem = wp.editPost.PluginMoreMenuItem;
var url = wp.url.addQueryArgs( document.location.href, { 'classic-editor': '', 'classic-editor__forget': '' } );
var linkText = lodash.get( window, [ 'classicEditorPluginL10n', 'linkText' ] ) || 'Switch to classic editor';
return createElement(
PluginMoreMenuItem,
{
icon: 'editor-kitchensink',
href: url,
},
linkText
);
},
} );
} )( window.wp );

View File

@@ -0,0 +1,138 @@
=== Classic Editor ===
Contributors: wordpressdotorg, azaozz, melchoyce, chanthaboune, alexislloyd, pento, youknowriad, desrosj, luciano-croce
Tags: gutenberg, disable, disable gutenberg, editor, classic editor, block editor
Requires at least: 4.9
Tested up to: 6.2
Stable tag: 1.6.3
Requires PHP: 5.2.4
License: GPLv2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Enables the previous "classic" editor and the old-style Edit Post screen with TinyMCE, Meta Boxes, etc. Supports all plugins that extend this screen.
== Description ==
Classic Editor is an official plugin maintained by the WordPress team that restores the previous ("classic") WordPress editor and the "Edit Post" screen. It makes it possible to use plugins that extend that screen, add old-style meta boxes, or otherwise depend on the previous editor.
Classic Editor is an official WordPress plugin, and will be fully supported and maintained until 2024, or as long as is necessary.
At a glance, this plugin adds the following:
* Administrators can select the default editor for all users.
* Administrators can allow users to change their default editor.
* When allowed, the users can choose which editor to use for each post.
* Each post opens in the last editor used regardless of who edited it last. This is important for maintaining a consistent experience when editing content.
In addition, the Classic Editor plugin includes several filters that let other plugins control the settings, and the editor choice per post and per post type.
By default, this plugin hides all functionality available in the new block editor ("Gutenberg").
== Changelog ==
= 1.6.3 =
* Added some WPCS fixes, props NicktheGeek on GitHub.
* Updated "Tested up to" in the readme and removed it from classic-editor.php. This should fix false positive errors in security plugins in the future.
= 1.6.2 =
* Fixed bug that was preventing saving of the last used editor.
= 1.6.1 =
* Fixed a warning on the block editor based widgets screen.
* Fixed use of a deprecated filter.
= 1.6 =
* Updated for WordPress 5.5.
* Fixed minor issues with calling deprecated functions, needlessly registering uninstall hook, and capitalization of some strings.
= 1.5 =
* Updated for WordPress 5.2 and Gutenberg 5.3.
* Enhanced and fixed the "open posts in the last editor used to edit them" logic.
* Fixed adding post state so it can easily be accessed from other plugins.
= 1.4 =
* On network installations removed the restriction for only network activation.
* Added support for network administrators to choose the default network-wide editor.
* Fixed the settings link in the warning on network About screen.
* Properly added the "Switch to classic editor" menu item to the block editor menu.
= 1.3 =
* Fixed removal of the "Try Gutenberg" dashboard widget.
* Fixed condition for displaying of the after upgrade notice on the "What's New" screen. Shown when the classic editor is selected and users cannot switch editors.
= 1.2 =
* Fixed switching editors from the Add New (post) screen before a draft post is saved.
* Fixed typo that was appending the edit URL to the `classic-editor` query var.
* Changed detecting of WordPress 5.0 to not use version check. Fixes a bug when testing 5.1-alpha.
* Changed the default value of the option to allow users to switch editors to false.
* Added disabling of the Gutenberg plugin and lowered the required WordPress version to 4.9.
* Added `classic_editor_network_default_settings` filter.
= 1.1 =
Fixed a bug where it may attempt to load the block editor for post types that do not support editor when users are allowed to switch editors.
= 1.0 =
* Updated for WordPress 5.0.
* Changed all "Gutenberg" names/references to "block editor".
* Refreshed the settings UI.
* Removed disabling of the Gutenberg plugin. This was added for testing in WordPress 4.9. Users who want to continue following the development of Gutenberg in WordPress 5.0 and beyond will not need another plugin to disable it.
* Added support for per-user settings of default editor.
* Added support for admins to set the default editor for the site.
* Added support for admins to allow users to change their default editor.
* Added support for network admins to prevent site admins from changing the default settings.
* Added support to store the last editor used for each post and open it next time. Enabled when users can choose default editor.
* Added "post editor state" in the listing of posts on the Posts screen. Shows the editor that will be opened for the post. Enabled when users can choose default editor.
* Added `classic_editor_enabled_editors_for_post` and `classic_editor_enabled_editors_for_post_type` filters. Can be used by other plugins to control or override the editor used for a particular post of post type.
* Added `classic_editor_plugin_settings` filter. Can be used by other plugins to override the settings and disable the settings UI.
= 0.5 =
* Updated for Gutenberg 4.1 and WordPress 5.0-beta1.
* Removed some functionality that now exists in Gutenberg.
* Fixed redirecting back to the classic editor after looking at post revisions.
= 0.4 =
* Fixed removing of the "Try Gutenberg" call-out when the Gutenberg plugin is not activated.
* Fixed to always show the settings and the settings link in the plugins list table.
* Updated the readme text.
= 0.3 =
* Updated the option from a checkbox to couple of radio buttons, seems clearer. Thanks to @designsimply for the label text suggestions.
* Some general updates and cleanup.
= 0.2 =
* Update for Gutenberg 1.9.
* Remove warning and automatic deactivation when Gutenberg is not active.
= 0.1 =
Initial release.
== Frequently Asked Questions ==
= Default settings =
When activated and when using a classic (non-block) theme, this plugin will restore the previous ("classic") WordPress editor and hide the new block editor ("Gutenberg").
These settings can be changed at the Settings => Writing screen.
= Default settings for network installation =
There are two options:
* When network-activated and when using a classic (non-block) theme, this plugin will set the classic editor as default and prevent site administrators and users from changing editors.
The settings can be changed and default network-wide editor can be selected on the Network Settings screen.
* When not network-activated each site administrator will be able to activate the plugin and choose options for their users.
= Cannot find the "Switch to classic editor" link =
It is in the main block editor menu, see this [screenshot](https://ps.w.org/classic-editor/assets/screenshot-7.png?rev=2023480).
= Does this work with full site editing and block themes? =
No, as block themes rely on blocks. [See Block themes article](https://wordpress.org/support/article/block-themes/) for more information.
== Screenshots ==
1. Admin settings on the Settings -> Writing screen.
2. User settings on the Profile screen. Visible when the users are allowed to switch editors.
3. "Action links" to choose alternative editor. Visible when the users are allowed to switch editors.
4. Link to switch to the block editor while editing a post in the classic editor. Visible when the users are allowed to switch editors.
5. Link to switch to the classic editor while editing a post in the block editor. Visible when the users are allowed to switch editors.
6. Network settings to select the default editor for the network and allow site admins to change it.
7. The "Switch to classic editor" link.

View File

@@ -0,0 +1,31 @@
(function($) {
'use strict';
if (typeof wpcf7 === 'undefined' || wpcf7 === null) {
return;
}
window.wpcf7dtx = window.wpcf7dtx || {};
wpcf7dtx.taggen = {};
wpcf7dtx.taggen.escapeRegExp = function(str) {
return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
};
wpcf7dtx.taggen.replaceAll = function(input, f, r, no_escape) {
if (input !== undefined && input !== null && typeof(input) == 'string' && input.trim() !== '' && input.indexOf(f) > -1) {
var rexp = new RegExp(wpcf7dtx.taggen.escapeRegExp(f), 'g');
if (no_escape) { rexp = new RegExp(f, 'g'); }
return input.replace(rexp, r);
}
return input;
};
wpcf7dtx.taggen.updateOption = function(e) {
var $this = $(e.currentTarget),
value = encodeURIComponent(wpcf7dtx.taggen.replaceAll($this.val(), "'", '&#39;'));
$this.siblings('input[type="hidden"].option').val(value);
};
$(function() {
$('form.tag-generator-panel input.dtx-option').on('change keyup', wpcf7dtx.taggen.updateOption);
});
})(jQuery);

View File

@@ -0,0 +1,7 @@
.tag-generator-panel table.form-table th {
width: 130px;
}
.tag-generator-panel .control-box input.oneline {
width: 100%;
}

View File

@@ -0,0 +1,216 @@
<?php
/**
* Plugin Name: Contact Form 7 - Dynamic Text Extension
* Plugin URI: https://sevenspark.com/goods/contact-form-7-dynamic-text-extension
* Description: This plugin extends Contact Form 7 by adding dynamic form fields that accept any shortcode to generate default values and placeholder text. Requires Contact Form 7.
* Version: 3.2
* Author: SevenSpark, AuRise Creative
* Author URI: https://sevenspark.com
* License: GPL2
* Requires at least: 5.5
* Requires PHP: 7.4
* Text Domain: contact-form-7-dynamic-text-extension
*/
/*
Copyright 2010-2023 Chris Mavricos, SevenSpark <https://sevenspark.com>
Copyright 2022-2023 Tessa Watkins, AuRise Creative <https://aurisecreative.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
// Define current version
define('WPCF7DTX_VERSION', '3.2');
// Define root directory
defined('WPCF7DTX_DIR') || define('WPCF7DTX_DIR', __DIR__);
// Define root file
defined('WPCF7DTX_FILE') || define('WPCF7DTX_FILE', __FILE__);
/**
* Initialise Plugin
*
* @return void
*/
function wpcf7dtx_init()
{
add_action('wpcf7_init', 'wpcf7dtx_add_shortcode_dynamictext'); // Add custom form tags to CF7
add_filter('wpcf7_validate_dynamictext*', 'wpcf7dtx_dynamictext_validation_filter', 10, 2); // Validate custom form tags
}
add_action('plugins_loaded', 'wpcf7dtx_init', 20);
/**
* Add Custom Shortcodes to Contact Form 7
*
* @return void
*/
function wpcf7dtx_add_shortcode_dynamictext()
{
//Add the dynamic text and hidden form fields
wpcf7_add_form_tag(
array(
'dynamictext', 'dynamictext*',
'dynamichidden', 'dynamichidden*' //Required hidden fields do nothing
),
'wpcf7dtx_dynamictext_shortcode_handler', //Callback
array('name-attr' => true) //Features
);
}
/**
* Form Tag Handler
*
* @param WPCF7_FormTag $tag
* @return string HTML output of the shortcode
*/
function wpcf7dtx_dynamictext_shortcode_handler($tag)
{
$tag = new WPCF7_FormTag($tag);
if (empty($tag->name)) {
return '';
}
//Validate
$validation_error = wpcf7_get_validation_error($tag->name);
//Configure classes
$class = wpcf7_form_controls_class($tag->type, 'wpcf7dtx-dynamictext');
if ($validation_error) {
$class .= ' wpcf7-not-valid';
}
//Configure input attributes
$atts = array();
$atts['name'] = $tag->name;
$atts['id'] = $tag->get_id_option();
$atts['class'] = $tag->get_class_option($class);
$atts['tabindex'] = $tag->get_option('tabindex', 'int', true);
$atts['size'] = $tag->get_size_option('40');
$atts['maxlength'] = $tag->get_maxlength_option();
$atts['minlength'] = $tag->get_minlength_option();
$atts['aria-invalid'] = $validation_error ? 'true' : 'false';
switch ($tag->basetype) {
case 'dynamichidden':
$atts['type'] = 'hidden'; //Override type as hidden
break;
default: // Includes `dynamictext`
$atts['type'] = 'text'; //Override type as text
break;
}
if ($atts['maxlength'] && $atts['minlength'] && $atts['maxlength'] < $atts['minlength']) {
unset($atts['maxlength'], $atts['minlength']);
}
if ($tag->has_option('readonly')) {
$atts['readonly'] = 'readonly';
}
if ($tag->is_required() && $atts['type'] !== 'hidden') {
$atts['aria-required'] = 'true';
}
// Evaluate the dynamic value
$value = wpcf7_get_hangover($tag->name, $tag->get_default_option(strval(reset($tag->values)))); // Input value
$scstr = '[' . $value . ']';
$scval = do_shortcode($scstr); //Shortcode value
if ($scval !== $scstr) {
$value = $scval; //Set the input value to the evaluated shortcode
}
// Identify placeholder
if ($tag->has_option('placeholder') || $tag->has_option('watermark')) {
//Reverse engineer what JS did (converted quotes to HTML entities --> URL encode) then sanitize
$placeholder = sanitize_text_field(html_entity_decode(urldecode(implode('', (array)$tag->get_option('placeholder'))), ENT_QUOTES));
if ($placeholder) {
$scpstr = '[' . $placeholder . ']';
$scpval = do_shortcode($scpstr); //Shortcode value
if ($scpval !== $scpstr) {
$placeholder = $scpval; //Set the placeholder value to the evaluated shortcode
}
//If a different placeholder text has been specified, set both attributes
$atts['placeholder'] = $placeholder;
$atts['value'] = $value;
} else {
//Default behavior of using the value as the placeholder
$atts['placeholder'] = $value;
}
} else {
$atts['value'] = $value;
}
//Output the HTML
return sprintf(
'<span class="wpcf7-form-control-wrap %s"><input %s />%s</span>',
sanitize_html_class($tag->name),
wpcf7_format_atts($atts), //This function already escapes attribute values
$validation_error
);
}
/**
* Validate Required Dynamic Text Field
*
* @param mixed $result
* @param WPCF7_FormTag $tag
*
* @return mixed
*/
function wpcf7dtx_dynamictext_validation_filter($result, $tag)
{
$tag = new WPCF7_FormTag($tag);
//Sanitize value
$value = empty($_POST[$tag->name]) ? '' : sanitize_text_field(trim(strval($_POST[$tag->name])));
//Validate
if ('dynamictext' == $tag->basetype) {
if ($tag->is_required() && '' == $value) {
$result->invalidate($tag, wpcf7_get_message('invalid_required'));
}
}
if (!empty($value)) {
$maxlength = $tag->get_maxlength_option();
$minlength = $tag->get_minlength_option();
if ($maxlength && $minlength && $maxlength < $minlength) {
$maxlength = $minlength = null;
}
$code_units = wpcf7_count_code_units($value);
if (false !== $code_units) {
if ($maxlength && $maxlength < $code_units) {
$result->invalidate($tag, wpcf7_get_message('invalid_too_long'));
} elseif ($minlength && $code_units < $minlength) {
$result->invalidate($tag, wpcf7_get_message('invalid_too_short'));
}
}
}
return $result;
}
/**
* Include Utility Functions
*/
include_once(WPCF7DTX_DIR . '/includes/utilities.php');
if (is_admin()) {
/**
* Include the Admin Stuff
*/
include_once(WPCF7DTX_DIR . '/includes/admin.php');
}
/**
* Included Shortcodes
*/
include_once(WPCF7DTX_DIR . '/includes/shortcodes.php');

View File

@@ -0,0 +1,221 @@
<?php
/**
* Admin Scripts and Styles
*
* Enqueue scripts and styles to be used on the admin pages
*
* @since 3.1.0
*
* @param string $hook Hook suffix for the current admin page
*/
function wpcf7dtx_enqueue_admin_assets($hook)
{
//Only load on CF7 Form pages
if ($hook == 'toplevel_page_wpcf7') {
$prefix = 'wpcf7dtx-';
$url = plugin_dir_url(WPCF7DTX_FILE);
$path = plugin_dir_path(WPCF7DTX_FILE);
wp_enqueue_style(
$prefix . 'admin', //Handle
$url . 'assets/styles/tag-generator.css', //Source
array('contact-form-7-admin'), //Dependencies
@filemtime($path . 'assets/styles/tag-generator.css') //Version
);
//Plugin Scripts
wp_enqueue_script(
$prefix . 'taggenerator', //Handle
$url . 'assets/scripts/tag-generator.js', //Source
array('jquery', 'wpcf7-admin-taggenerator'), //Dependencies
@filemtime($path . 'assets/scripts/tag-generator.js'), //Version
true //In footer
);
}
}
add_action('admin_enqueue_scripts', 'wpcf7dtx_enqueue_admin_assets'); //Enqueue styles/scripts for admin page
/**
* Create Tag Generators
*
* @return void
*/
function wpcf7dtx_add_tag_generator_dynamictext()
{
if (!class_exists('WPCF7_TagGenerator')) {
return;
}
$tag_generator = WPCF7_TagGenerator::get_instance();
//Dynamic Text Field
$tag_generator->add(
'dynamictext', //id
__('dynamic text', 'contact-form-7-dynamic-text-extension'), //title
'wpcf7dtx_tag_generator_dynamictext', //callback
array('placeholder', 'readonly') //options
);
//Dynamic Hidden Field
$tag_generator->add(
'dynamichidden', //id
__('dynamic hidden', 'contact-form-7-dynamic-text-extension'), //title
'wpcf7dtx_tag_generator_dynamictext' //callback
);
}
add_action('wpcf7_admin_init', 'wpcf7dtx_add_tag_generator_dynamictext', 100);
/**
* Echo HTML for Dynamic Tag Generator
*
* @param WPCF7_ContactForm $contact_form
* @param array $options
* @return void
*/
function wpcf7dtx_tag_generator_dynamictext($contact_form, $options = '')
{
$options = wp_parse_args($options);
$type = $options['id'];
switch ($type) {
case 'dynamichidden': //hiden
$description = __('Generate a form-tag for a hidden input field, with a dynamically generated default value.', 'contact-form-7-dynamic-text-extension');
break;
default:
$description = __('Generate a form-tag for a single-line plain text input field, with a dynamically generated default value.', 'contact-form-7-dynamic-text-extension');
break;
}
$utm_source = urlencode(home_url());
$description .= sprintf(
' %s <a href="https://aurisecreative.com/docs/contact-form-7-dynamic-text-extension/?utm_source=%s&utm_medium=link&utm_campaign=contact-form-7-dynamic-text-extension&utm_content=form-tag-generator-%s" target="_blank" rel="noopener">%s</a>.',
__('For more details, see', 'contact-form-7-dynamic-text-extension'),
esc_attr($utm_source), //UTM source
esc_attr($type), //UTM content
__('DTX knowledge base', 'contact-form-7-dynamic-text-extension')
);
//Open Form-Tag Generator
printf(
'<div class="control-box"><fieldset><legend>%s</legend><table class="form-table"><tbody>',
wp_kses($description, 'a') //Tag generator description
);
//Input field - Required checkbox (not available for hidden fields)
if ($type != 'dynamichidden') {
printf(
'<tr><th scope="row"><label for="%s">%s</label></th><td><label><input %s />%s</label></td></tr>',
esc_attr($options['content'] . '-required'), // field id
esc_html__('Field type', 'contact-form-7-dynamic-text-extension'), // field Label
wpcf7_format_atts(array(
'type' => 'checkbox',
'name' => 'required',
'id' => $options['content'] . '-required'
)),
esc_html__('Required field', 'contact-form-7-dynamic-text-extension') // checkbox label
);
}
//Input field - Field Name
printf(
'<tr><th scope="row"><label for="%s">%s</label></th><td><input %s /></td></tr>',
esc_attr($options['content'] . '-name'), // field id
esc_html__('Name', 'contact-form-7-dynamic-text-extension'), // field label
wpcf7_format_atts(array(
'type' => 'text',
'name' => 'name',
'id' => $options['content'] . '-name',
'class' => 'tg-name oneline'
))
);
//Input field - Dynamic value
printf(
'<tr><th scope="row"><label for="%s">%s</label></th><td><input %s /><br /><small>%s <a href="https://aurisecreative.com/docs/contact-form-7-dynamic-text-extension/shortcodes/?utm_source=%s&utm_medium=link&utm_campaign=contact-form-7-dynamic-text-extension&utm_content=form-tag-generator-%s" target="_blank" rel="noopener">%s</a></small></td></tr>',
esc_attr($options['content'] . '-values'), // field id
esc_html__('Dynamic value', 'contact-form-7-dynamic-text-extension'), // field label
wpcf7_format_atts(array(
'type' => 'text',
'name' => 'values',
'id' => $options['content'] . '-values',
'class' => 'oneline',
'placeholder' => "CF7_GET key='foo'"
)),
esc_html__('Can be static text or a shortcode.', 'contact-form-7-dynamic-text-extension'),
esc_attr($utm_source), //UTM source
esc_attr($type), //UTM content
esc_html__('View DTX shortcode syntax documentation', 'contact-form-7-dynamic-text-extension') //Link label
);
//Input field - Dynamic placeholder (not available for hidden fields)
if ($type != 'dynamichidden') {
printf(
'<tr><th scope="row"><label for="%s">%s</label></th><td><input %s /><input %s /><br /><small>%s <a href="https://aurisecreative.com/docs/contact-form-7-dynamic-text-extension/shortcodes/dtx-attribute-placeholder/?utm_source=%s&utm_medium=link&utm_campaign=contact-form-7-dynamic-text-extension&utm_content=form-tag-generator-%s" target="_blank" rel="noopener">%s</a></small></td></tr>',
esc_attr($options['content'] . '-placeholder'), // field id
esc_html__('Dynamic placeholder', 'contact-form-7-dynamic-text-extension'), // field label
wpcf7_format_atts(array(
'type' => 'hidden',
'name' => 'placeholder',
'class' => 'option'
)),
wpcf7_format_atts(array(
'type' => 'text',
'name' => 'dtx-placeholder',
'id' => $options['content'] . '-placeholder', // field id
'class' => 'oneline dtx-option',
'placeholder' => 'CF7_get_post_var key=\'post_title\''
)),
esc_html__('Can be static text or a shortcode.', 'contact-form-7-dynamic-text-extension'),
esc_attr($utm_source), //UTM source
esc_attr($type), //UTM content
esc_html__('View DTX placeholder documentation', 'contact-form-7-dynamic-text-extension') //Link label
);
}
//Input field - ID attribute
printf(
'<tr><th scope="row"><label for="%s">%s</label></th><td><input %s /></td></tr>',
esc_attr($options['content'] . '-id'), // field id
esc_html__('Id attribute', 'contact-form-7-dynamic-text-extension'), // field label
wpcf7_format_atts(array(
'type' => 'text',
'name' => 'id',
'id' => $options['content'] . '-id', // field id
'class' => 'idvalue oneline option'
))
);
//Input field - Class attribute
printf(
'<tr><th scope="row"><label for="%s">%s</label></th><td><input %s /></td></tr>',
esc_attr($options['content'] . '-class'), // field id
esc_html__('Class attribute', 'contact-form-7-dynamic-text-extension'), // field label
wpcf7_format_atts(array(
'type' => 'text',
'name' => 'class',
'id' => $options['content'] . '-class', // field id
'class' => 'classvalue oneline option'
))
);
//Input field - Readonly attribute (not available for hidden fields)
if ($type != 'dynamichidden') {
printf(
'<tr><th scope="row"><label for="%s">%s</label></th><td><label><input %s />%s</label></td></tr>',
esc_attr($options['content'] . '-readonly'), // field id
esc_html__('Read only attribute', 'contact-form-7-dynamic-text-extension'), // field Label
wpcf7_format_atts(array(
'type' => 'checkbox',
'name' => 'readonly',
'id' => $options['content'] . '-readonly',
'class' => 'readonlyvalue option'
)),
esc_html__('Do not let users edit this field', 'contact-form-7-dynamic-text-extension') // checkbox label
);
}
//Close Form-Tag Generator
printf(
'</tbody></table></fieldset></div><div class="insert-box"><input type="text" name="%s" class="tag code" readonly="readonly" onfocus="this.select()" /><div class="submitbox"><input type="button" class="button button-primary insert-tag" value="%s" /></div><br class="clear" /></div>',
esc_attr($type),
esc_html__('Insert Tag', 'contact-form-7-dynamic-text-extension')
);
}

View File

@@ -0,0 +1,358 @@
<?php
/*****************************************************
* Included Shortcodes
*
* See documentation for usage:
* https://aurisecreative.com/docs/contact-form-7-dynamic-text-extension/shortcodes/
*
*****************************************************/
/**
* Initialise DTX included shortcodes
*
* Hooked to `init`
*
* @return void
*/
function wpcf7dtx_init_shortcodes()
{
add_shortcode('CF7_GET', 'wpcf7dtx_get');
add_shortcode('CF7_POST', 'wpcf7dtx_post');
add_shortcode('CF7_URL', 'wpcf7dtx_url');
add_shortcode('CF7_referrer', 'wpcf7dtx_referrer');
add_shortcode('CF7_bloginfo', 'wpcf7dtx_bloginfo');
add_shortcode('CF7_get_post_var', 'wpcf7dtx_get_post_var');
add_shortcode('CF7_get_custom_field', 'wpcf7dtx_get_custom_field');
add_shortcode('CF7_get_current_user', 'wpcf7dtx_get_current_user');
add_shortcode('CF7_get_attachment', 'wpcf7dtx_get_attachment');
add_shortcode('CF7_guid', 'wpcf7dtx_guid');
}
add_action('init', 'wpcf7dtx_init_shortcodes'); //Add init hook to add shortcodes
/**
* Get Variable from $_GET Array
*
* @param array $atts Optional. An associative array of shortcode attributes. Default is an empty array.
* @param string $content Optional. A string of content between the opening and closing tags. Default is an empty string.
* @param string $tag Optional. The shortcode tag. Default is an empty string.
*
* @return string Output of the shortcode
*/
function wpcf7dtx_get($atts = array(), $content = '', $tag = '')
{
extract(shortcode_atts(array(
'key' => 0,
'obfuscate' => ''
), array_change_key_case((array)$atts, CASE_LOWER)));
$valid_key = (is_numeric($key) && intval($key) > -1) || (is_string($key) && !empty($key));
if ($valid_key && is_array($_GET) && count($_GET) && array_key_exists($key, $_GET) && !empty($_GET[$key])) {
$value = sanitize_text_field(strval($_GET[$key]));
if ($obfuscate && !empty($value)) {
return wpcf7dtx_obfuscate($value);
}
return $value;
}
return '';
}
/**
* Get Variable from $_POST Array
*
* @param array $atts Optional. An associative array of shortcode attributes. Default is an empty array.
* @param string $content Optional. A string of content between the opening and closing tags. Default is an empty string.
* @param string $tag Optional. The shortcode tag. Default is an empty string.
*
* @return string Output of the shortcode
*/
function wpcf7dtx_post($atts = array(), $content = '', $tag = '')
{
extract(shortcode_atts(array(
'key' => '',
'obfuscate' => ''
), array_change_key_case((array)$atts, CASE_LOWER)));
$valid_key = (is_numeric($key) && intval($key) > -1) || (is_string($key) && !empty($key));
if ($valid_key && is_array($_POST) && count($_POST) && array_key_exists($key, $_POST) && !empty($_POST[$key])) {
$value = sanitize_text_field(strval($_POST[$key]));
if ($obfuscate && !empty($value)) {
return wpcf7dtx_obfuscate($value);
}
return $value;
}
return '';
}
/**
* Get the Current URL
*
* @param array $atts Optional. An associative array of shortcode attributes. Default is an empty array.
* @param string $content Optional. A string of content between the opening and closing tags. Default is an empty string.
* @param string $tag Optional. The shortcode tag. Default is an empty string.
*
* @return string Output of the shortcode
*/
function wpcf7dtx_url($atts = array(), $content = '', $tag = '') {
extract(shortcode_atts(array(
'allowed_protocols' => 'http,https',
'obfuscate' => '',
'part' => '',
), array_change_key_case((array)$atts, CASE_LOWER)));
$allowed_protocols = explode(',', sanitize_text_field($allowed_protocols));
// Build the full URL from the $_SERVER array
$url = sprintf('http%s://', is_ssl() ? 's' : '');
if (!empty($_SERVER['SERVER_PORT']) && intval($_SERVER['SERVER_PORT']) !== 80) {
$url = $url . $_SERVER['SERVER_NAME'] . ':' . $_SERVER['SERVER_PORT'] . $_SERVER['REQUEST_URI'];
} else {
$url = $url . $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI'];
}
// Determine the value to return
$value = '';
// If an individual part is requested, get that specific value using parse_url()
if( $part ){
$part_constant_map = [
'host' => PHP_URL_HOST,
'query' => PHP_URL_QUERY,
'path' => PHP_URL_PATH,
// 'fragment' => PHP_URL_FRAGMENT, // Can't get fragment because it's not part of the $_SERVER array
];
if( isset( $part_constant_map[$part] ) ) {
$value = sanitize_text_field(parse_url($url, $part_constant_map[$part]));
}
}
// No part requested, return the whole thing
else {
$value = sanitize_url($url, $allowed_protocols);
}
// Obfuscate if requested
if ($obfuscate && !empty($value)) {
return wpcf7dtx_obfuscate($value);
}
return $value;
}
/**
* Get Referrer
*
* @param array $atts Optional. An associative array of shortcode attributes. Default is an empty array.
* @param string $content Optional. A string of content between the opening and closing tags. Default is an empty string.
* @param string $tag Optional. The shortcode tag. Default is an empty string.
*
* @return string Output of the shortcode
*/
function wpcf7dtx_referrer($atts = array(), $content = '', $tag = '')
{
extract(shortcode_atts(array(
'allowed_protocols' => 'http,https',
'obfuscate' => ''
), array_change_key_case((array)$atts, CASE_LOWER)));
$allowed_protocols = explode(',', sanitize_text_field($allowed_protocols));
$value = empty($_SERVER['HTTP_REFERER']) ? '' : sanitize_url($_SERVER['HTTP_REFERER'], $allowed_protocols);
if ($obfuscate && !empty($value)) {
return wpcf7dtx_obfuscate($value);
}
return $value;
}
/**
* Get Variable from Bloginfo
*
* See possible values: https://developer.wordpress.org/reference/functions/get_bloginfo/
*
* @param array $atts Optional. An associative array of shortcode attributes. Default is an empty array.
* @param string $content Optional. A string of content between the opening and closing tags. Default is an empty string.
* @param string $tag Optional. The shortcode tag. Default is an empty string.
*
* @return string Output of the shortcode
*/
function wpcf7dtx_bloginfo($atts = array(), $content = '', $tag = '')
{
extract(shortcode_atts(array(
'show' => 'name', //Backwards compatibility
'key' => 'name',
'obfuscate' => ''
), array_change_key_case((array)$atts, CASE_LOWER)));
$key = $show != $key && $show != 'name' ? $show : $key; //Use old value of "show" if not set to default value
$value = sanitize_text_field(strval(get_bloginfo($key)));
if ($obfuscate && !empty($value)) {
return wpcf7dtx_obfuscate($value);
}
return $value;
}
/**
* Get Variable from a Post Object
*
* @param array $atts Optional. An associative array of shortcode attributes. Default is an empty array.
* @param string $content Optional. A string of content between the opening and closing tags. Default is an empty string.
* @param string $tag Optional. The shortcode tag. Default is an empty string.
*
* @return string Output of the shortcode
*/
function wpcf7dtx_get_post_var($atts = array(), $content = '', $tag = '')
{
extract(shortcode_atts(array(
'key' => 'post_title',
'post_id' => '',
'obfuscate' => ''
), array_change_key_case((array)$atts, CASE_LOWER)));
switch ($key) {
case 'slug':
$key = 'post_name';
break;
case 'title':
$key = 'post_title';
break;
default:
break;
}
$post_id = wpcf7dtx_get_post_id($post_id);
if ($post_id && is_string($key) && !empty($key)) {
$value = sanitize_text_field(trim(strval(get_post_field($key, $post_id))));
if ($obfuscate && !empty($value)) {
return wpcf7dtx_obfuscate($value);
}
return $value;
}
return '';
}
/**
* Get Value from Post Meta Field
*
* @param array $atts Optional. An associative array of shortcode attributes. Default is an empty array.
* @param string $content Optional. A string of content between the opening and closing tags. Default is an empty string.
* @param string $tag Optional. The shortcode tag. Default is an empty string.
*
* @return string Output of the shortcode
*/
function wpcf7dtx_get_custom_field($atts = array(), $content = '', $tag = '')
{
extract(shortcode_atts(array(
'key' => '',
'post_id' => '',
'obfuscate' => ''
), array_change_key_case((array)$atts, CASE_LOWER)));
$post_id = wpcf7dtx_get_post_id($post_id);
if ($post_id && is_string($key) && !empty($key)) {
$value = get_post_meta($post_id, $key, true);
if ($obfuscate && !empty($value)) {
return wpcf7dtx_obfuscate($value);
}
return $value;
}
return '';
}
/**
* Get Value from Current User
*
* Retreives data from the `users` and `usermeta` tables.
* Documentation: https://developer.wordpress.org/reference/classes/wp_user/get/
*
* @param array $atts Optional. An associative array of shortcode attributes. Default is an empty array.
* @param string $content Optional. A string of content between the opening and closing tags. Default is an empty string.
* @param string $tag Optional. The shortcode tag. Default is an empty string.
*
* @return string Output of the shortcode
*/
function wpcf7dtx_get_current_user($atts = array(), $content = '', $tag = '')
{
extract(shortcode_atts(array(
'key' => 'user_login',
'obfuscate' => ''
), array_change_key_case((array)$atts, CASE_LOWER)));
if (is_user_logged_in()) {
$user = wp_get_current_user();
$value = $user->get($key);
if ($obfuscate && !empty($value)) {
return wpcf7dtx_obfuscate($value);
}
return $value;
}
return '';
}
/**
* Get Attachment
*
* Retreives an attachment ID or absolute URL depending on attributes
*
* @since 3.1.0
*
* @param array $atts Optional. An associative array of shortcode attributes. Default is an empty array.
* @param string $content Optional. A string of content between the opening and closing tags. Default is an empty string.
* @param string $tag Optional. The shortcode tag. Default is an empty string.
*
* @return string Output of the shortcode
*/
function wpcf7dtx_get_attachment($atts = array(), $content = '', $tag = '')
{
extract(shortcode_atts(array(
'id' => '', //Get attachment by ID
'size' => 'full', //Define attachment size
'post_id' => '', //If attachment ID is empty but post ID is not, get the featured image
'return' => 'url', //Options are `id` or `url`
'obfuscate' => ''
), array_change_key_case((array)$atts, CASE_LOWER)));
//No attachment ID was provided, check for post ID to get it's featured image
if (empty($id)) {
if ($post_id = sanitize_text_field(strval($post_id))) {
//If a post ID was provided, get it's featured image
if (is_numeric($post_id) && (int)$post_id > 0) {
$id = get_post_thumbnail_id($post_id);
}
} else {
//If no post ID was provided, get current featured image
global $post;
if (isset($post) && property_exists($post, 'ID') && is_numeric($post->ID)) {
$id = get_post_thumbnail_id(intval($post->ID));
}
}
}
//Get the value
$value = '';
if ($id) {
$id = intval(sanitize_text_field(strval($id)));
switch ($return) {
case 'id': //Return the attachment ID
$value = esc_attr($id);
break;
default: //Return attachment URL
$url = wp_get_attachment_image_url(intval($id), sanitize_text_field(strval($size)));
$value = $url ? esc_url($url) : '';
break;
}
if ($obfuscate && !empty($value)) {
return wpcf7dtx_obfuscate($value);
}
}
return $value;
}
/**
* GUID Field
*
* @since 3.1.0
*
* @param array $atts Optional. An associative array of shortcode attributes. Default is an empty array.
* @param string $content Optional. A string of content between the opening and closing tags. Default is an empty string.
* @param string $tag Optional. The shortcode tag. Default is an empty string.
*
* @return string Output of the shortcode
*/
function wpcf7dtx_guid()
{
if (function_exists('com_create_guid') === true) {
return trim(com_create_guid(), '{}');
}
return sprintf('%04X%04X-%04X-%04X-%04X-%04X%04X%04X', mt_rand(0, 65535), mt_rand(0, 65535), mt_rand(0, 65535), mt_rand(16384, 20479), mt_rand(32768, 49151), mt_rand(0, 65535), mt_rand(0, 65535), mt_rand(0, 65535));
}

View File

@@ -0,0 +1,181 @@
<?php
/**
* Obfuscate a value
*
* @param mixed $value
* @return string obfuscated value
*/
function wpcf7dtx_obfuscate($value = '')
{
$return = '';
$value = strval($value); //Force value to be string
if (!empty($value)) {
foreach (str_split($value) as $letter) {
$return .= '&#' . ord($letter) . ';';
}
}
return sanitize_text_field(trim($return));
}
/**
* Get Post ID
*
* @param mixed $post_id
* @return int An integer value of the passed post ID or the post ID of the current `$post` global object. 0 on Failure.
*/
function wpcf7dtx_get_post_id($post_id)
{
$post_id = is_numeric($post_id) && (int)$post_id > 0 ? intval($post_id) : 0;
if (!$post_id) {
//No post ID was provided, look it up
global $post;
if (isset($post) && property_exists($post, 'ID')) {
$post_id = $post->ID;
}
}
return $post_id;
}
/**
* Mark a shortcode as deprecated and inform when it has been used.
*
* The current behavior is to trigger a user error if WP_DEBUG is true.
*
* This function is to be used in every function that is deprecated.
*
* @since 3.1.0
* @access private
*
* @param string $tag The tag of the shortcode that was called.
* @param string $version The version of the plugin that deprecated the shortcode.
* @param string $replacement Optional. The shortcode that should have been used. Default null.
*/
function wpcf7dtx_deprecated_shortcode($tag, $version, $replacement = null, $documentation = null)
{
/**
* Filter whether to trigger an error for deprecated shortcodes.
*
* @since 3.1.0
*
* @param bool $trigger Whether to trigger the error for deprecated functions. Default true.
*/
if (WP_DEBUG && apply_filters('deprecated_function_trigger_error', true)) {
if (!is_null($replacement)) {
if (!is_null($documentation)) {
trigger_error(sprintf(
__('%1$s is <strong>deprecated</strong> since version %2$s! Use Contact Form 7\'s built-in attribute "%3$s" instead. Contact Form 7 Documentation: %4$s', 'contact-form-7-dynamic-text-extension'),
$tag,
$version,
$replacement,
$documentation
));
} else {
trigger_error(sprintf(
__('%1$s is <strong>deprecated</strong> since version %2$s! Use Contact Form 7\'s built-in attribute "%3$s" instead.', 'contact-form-7-dynamic-text-extension'),
$tag,
$version,
$replacement
));
}
} else {
trigger_error(sprintf(
__('%1$s is <strong>deprecated</strong> since version %2$s with no alternative currently available.', 'contact-form-7-dynamic-text-extension'),
$tag,
$version
));
}
}
}
/**
* Parse Content for Specified Shortcodes
*
* Parse a string of content for a specific shortcode to retrieve its attributes and content
*
* @since 3.1.0
*
* @param string $content The content to parse
* @param string $tag The shortcode tag
*
* @return array An associative array with `tag` (string) and `shortcodes` (sequential array). If shortcodes were discovered, each one has keys for `atts` (associative array) and `content` (string)
*/
function wpcf7dtx_get_shortcode_atts($content)
{
$return = array(
'tag' => '',
'atts' => array()
);
//Search for shortcodes with attributes
if (false !== ($start = strpos($content, ' '))) {
$return['tag'] = substr($content, 0, $start); //Opens the start tag, assumes there are attributes because of the space
//Parse for shortcode attributes: `shortcode att1='foo' att2='bar'`
//Chop only the attributes e.g. `att1="foo" att2="bar"`
$atts_str = trim(str_replace($return['tag'], '', $content));
if (strpos($atts_str, "'") !== false) {
$atts = explode("' ", substr(
$atts_str,
0,
-1 //Clip off the last character, which is a single quote
));
if (is_array($atts) && count($atts)) {
foreach ($atts as $att_str) {
$pair = explode("='", $att_str);
if (is_array($pair) && count($pair) > 1) {
$key = sanitize_key(trim($pair[0])); //Validate & normalize the key
if (!empty($key)) {
$return['atts'][$key] = sanitize_text_field(html_entity_decode($pair[1]));
}
}
}
}
}
}
return $return;
}
/**
* Array Key Exists and Has Value
*
* @since 3.1.0
*
* @param string|int $key The key to search for in the array.
* @param array $array The array to search.
* @param mixed $default The default value to return if not found or is empty. Default is an empty string.
*
* @return mixed The value of the key found in the array if it exists or the value of `$default` if not found or is empty.
*/
function wpcf7dtx_array_has_key($key, $array = array(), $default = '')
{
//Check if this key exists in the array
$valid_key = (is_string($key) && !empty($key)) || is_numeric($key);
$valid_array = is_array($array) && count($array);
if ($valid_key && $valid_array && array_key_exists($key, $array)) {
//Always return if it's a boolean or number, otherwise only return it if it has any value
if ($array[$key] || is_bool($array[$key]) || is_numeric($array[$key])) {
return $array[$key];
}
}
return $default;
}
if (!function_exists('array_key_first')) {
/**
* Gets the first key of an array
*
* Gets the first key of the given array without affecting the internal array pointer.
*
* @param array $array
* @return int|string|null
*/
function array_key_first($array = array())
{
foreach ($array as $key => $value) {
return $key;
}
return null;
}
}

View File

@@ -0,0 +1,363 @@
=== Contact Form 7 - Dynamic Text Extension ===
Contributors: sevenspark, tessawatkinsllc
Donate link: https://just1voice.com/donate/
Tags: Contact Form 7, contact, contact form, dynamic, text, input, GET, POST, title, slug, autofill, auto-fill, prepopulate, pre-populate, form field
Tested up to: 6.1.1
Stable tag: 3.2
This plugin provides additional form tags for the Contact Form 7 plugin. It allows dynamic generation of content for text or hidden input fields using any shortcode.
== Description ==
Contact Form 7 is an excellent WordPress plugin and one of the top choices of free WordPress plugins for contact forms. Contact Form 7 - Dynamic Text Extension (DTX) makes it even more awesome by adding dynamic content capabilities. While default values in Contact Form 7 are static, DTX lets you create pre-populated fields based on other values. Some examples might include:
* Auto-filling a URL
* Auto-filling a post ID, title, or slug
* Pre-populating a product number
* Referencing other content on the site
* Populating with post info
* Populating with user info
* Populating with custom fields
* Generating unique identifiers for support tickets
* Any value using custom shortcodes
The possibilities are endless!
= WHAT DOES IT DO? =
DTX comes with several built-in shortcodes that will allow the contact form to be populated from HTTPS GET variable or any info from the `get_bloginfo()` function, among others. See below for included shortcodes.
Don't see the shortcode you need on the list? You can write a [custom one](https://aurisecreative.com/docs/contact-form-7-dynamic-text-extension/shortcodes/custom-shortcodes/?utm_source=wordpress.org&utm_medium=link&utm_campaign=contact-form-7-dynamic-text-extension&utm_content=readme)! Any shortcode that returns a string or numeric value can be used here. The included shortcodes just cover the most common scenarios, but DTX provides the flexibility for you to grab any value you have access to programmatically.
= HOW TO USE IT =
After installing and activating the plugin, you will have 2 new tag types to select from when creating or editing a Contact Form 7 form: the dynamic text field and dynamic hidden field. Most of the options in their tag generators will be familiar to Contact Form 7 users but there have been some upgrades.
**Dynamic Value**
This fields can take a shortcode, with two important provisions:
1. The shortcode should NOT include the normal square brackets (`[` and `]`). So, instead of `[CF7_GET key='value']` you would use `CF7_GET key='value'`.
1. Any parameters in the shortcode must use single quotes. That is: `CF7_GET key='value'` and not `CF7_GET key="value"`
**Dynamic placeholder**
Only available for the dynamic text form tag, this field can take static text or a shortcode. If using a shortcode, the same syntax applies from the dynamic value field. However, this field also has a few more needs:
1. The text/shortcode must first have apostrophes converted to it's HTML entity code, `&#39;`
1. After that, it must be URL encoded so that spaces become `%20` and other non-alphanumeric characters are converted.
**Read Only Attribute**
Only available for the dynamic text form tag, simply check this box if you do not want to let users edit this field. It will add the `readonly` attribute to your form field.
= INCLUDED SHORTCODES =
The plugin includes several shortcodes for use with the Dynamic Text Extension right out of the box. You can write your own as well—any self-closing shortcode will work, even with attributes!
**Current URL or Current URL Part**
Retrieve the current URL: `CF7_URL`
Your Contact Form 7 Tag would look like: `[dynamictext dynamicname "CF7_URL"]`
Optional parameter: `part`, which will return a parsed part of the URL. Valid values are `host`, `query`, and `path`
Host: Just the domain name and tld
`[dynamictext host "CF7_URL part='host'"]`
Query: The query string after the ?, if one exists
`[dynamictext query "CF7_URL part='query'"]`
Path: The URL path, for example, /contact, if one exists
`[dynamictext path "CF7_URL part='path'"]`
**Referrer URL**
Get the referral URL, if it exists. Note that this is not necessarily reliable as not all browsers send this data.
CF7 Tag: `[dynamictext dynamicname "CF7_referrer"]`
**Post/Page Info**
Retrieve information about the current post or page that the contact form is displayed on. The shortcode works as follows:
`CF7_get_post_var key='title'` <-- retrieves the Post's Title
`CF7_get_post_var key='slug'` <-- retrieves the Post's Slug
You can also retrieve any parameter from the global `$post` object. Just set that as the `key` value, for example `post_date`
The Contact Form 7 Tag would look like: `[dynamictext dynamicname "CF7_get_post_var key='title'"]`
Need to pull data from a _different_ post/page? Not a problem! Just specify it's post ID like this:
Dynamic value: `CF7_get_post_var key='title' post_id='245'`
Contact Form 7 Tag: `[dynamictext dynamicname "CF7_get_post_var key='title' post_id='245'"]`
**Post Meta & Custom Fields**
Retrieve custom fields from the current post/page. Just set the custom field as the key in the shortcode.
The dynamic value input becomes: `CF7_get_custom_field key='my_custom_field'`
And the tag looks like this: `[dynamictext dynamicname "CF7_get_custom_field key='my_custom_field'"]`
For the purposes of including an email address, you can obfuscate the custom field value by setting obfuscate='on' in the shortcode like this:
`[dynamictext dynamicname "CF7_get_custom_field key='my_custom_field' obfuscate='on'"]`
**Featured Images & Media Attachments**
Retrieve the current post's featured image, the featured image of a different page, or any attachment from the Media Library with this shortcode!
The base shortcode is simply: `CF7_get_attachment` which returns the absolute URL of the current page's featured image.
By setting the `post_id` attribute to a post ID, you can get the featured image of another page.
By setting the `id` attribute to an attachment ID, you can get the absolute URL of any image uploaded to your WordPress website.
By setting the `size` attribute to any size registered on your website, you can get a specific image size.
Want to return the attachment ID instead of the URL? Also not a problem! Just set `return='id'` in the shortcode.
Most of the optional attributes can be used at the same time. For example, if I wanted to retrieve the attachment ID of a featured image for a different post, then the dynamic text form tag would look like this:
`[dynamictext input_name "CF7_get_attachment post_id='123' return='id'"]`
If I wanted to get a specific image at a specific size, I can use this:
`[dynamictext input_name "CF7_get_attachment id='123' size='thumbnail'"]`
The only two attributes that cant play together is `id` and `post_id`. If both are specified, it will get the attachment specified by `id` and completely ignore the `post_id` attribute. If neither are specified, then it looks to the current featured image assigned to the global `$post` object.
**Current User Info & User Meta**
Get data about the current logged-in user.
Dynamic value: `CF7_get_current_user key='user_displayname'`
CF7 Tag: `[dynamictext dynamicname "CF7_get_current_user"]`
Valid values for `key` include:
* `ID`
* `user_login`
* `display_name`
* `user_email`
* `user_firstname`
* `user_lastname`
* `user_description`
But also custom meta user keys!
For the purposes of including an email address, you can obfuscate the value by setting obfuscate='on' in the shortcode like this:
`[dynamictext dynamicname "CF7_get_current_user key='user_email' obfuscate='on'"]`
**Site/Blog Info**
Want to grab some information from your blog like the URL or the site name? Use the `CF7_bloginfo` shortcode. For example, to get the site's URL:
Enter the following into the "Dynamic Value" input: `CF7_bloginfo show='url'`
Your Content Form 7 Tag will look something like this: `[dynamictext dynamicname "CF7_bloginfo show='url'"]`
Your form's dynamicname text input will then be pre-populated with your site's URL
**HTTP GET Variables**
Want to use a variable from the PHP `$_GET` array? Just use the `CF7_GET` shortcode. For example, if you want to get the foo parameter from the url
`http://mysite.com?foo=bar`
Enter the following into the "Dynamic Value" input: `CF7_GET key='foo'`
Your Content Form 7 Tag will look something like this: `[dynamictext dynamicname "CF7_GET key='foo'"]`
Your form's dynamicname text input will then be pre-populated with the value of `foo`, in this case, `bar`
**HTTP POST Variables**
Grab variables from the PHP `$_POST` array. The shortcode is much like the GET shortcode:
Dynamic value: `CF7_POST key='foo'`
Your Content Form 7 Tag will look something like this: `[dynamictext dynamicname "CF7_POST key='foo'"]`
**GUID**
Generate a globally unique identifier (GUID) in a form field. This is a great utility shortcode for forms that need unique identifiers for support tickets, receipts, reference numbers, etc., without having to expose personally identifiable information (PII). This shortcode takes no parameters: `CF7_guid`
Your Contact Form 7 Tag would look like: `[dynamictext dynamicname "CF7_guid"]`
**Shortcode attribute: obfuscate**
All of the included shortcodes have an `obfuscate` attribute that you can set to any truthy value to provide an additional layer of security for sensitive data.
== Installation ==
There are three (3) ways to install my plugin: automatically, upload, or manually.
= Install Method 1: Automatic Installation =
Automatic installation is the easiest option as WordPress handles the file transfers itself and you dont need to leave your web browser.
1. Log in to your WordPress dashboard.
1. Navigate to **Plugins > Add New**.
1. Where it says “Keyword” in a dropdown, change it to “Author”
1. In the search form, type “TessaWatkinsLLC” (results may begin populating as you type but my plugins will only show when the full name is there)
1. Once youve found my plugin in the search results that appear, click the **Install Now** button and wait for the installation process to complete.
1. Once the installation process is completed, click the **Activate** button to activate my plugin.
= Install Method 2: Upload via WordPress Admin =
This method involves is a little more involved. You dont need to leave your web browser, but youll need to download and then upload the files yourself.
1. [Download my plugin](https://wordpress.org/plugins/contact-form-7-dynamic-text-extension/) from WordPress.org; it will be in the form of a zip file.
1. Log in to your WordPress dashboard.
1. Navigate to **Plugins > Add New**.
1. Click the **Upload Plugin** button at the top of the screen.
1. Select the zip file from your local file system that was downloaded in step 1.
1. Click the **Install Now** button and wait for the installation process to complete.
1. Once the installation process is completed, click the **Activate** button to activate my plugin.
= Install Method 3: Manual Installation =
This method is the most involved as it requires you to be familiar with the process of transferring files using an SFTP client.
1. [Download my plugin](https://wordpress.org/plugins/contact-form-7-dynamic-text-extension/) from WordPress.org; it will be in the form of a zip file.
1. Unzip the contents; you should have a single folder named `contact-form-7-dynamic-text-extension`.
1. Connect to your WordPress server with your favorite SFTP client.
1. Copy the folder from step 2 to the `/wp-content/plugins/` folder in your WordPress directory. Once the folder and all of its files are there, installation is complete.
1. Now log in to your WordPress dashboard.
1. Navigate to **Plugins > Installed Plugins**. You should now see my plugin in your list.
1. Click the **Activate** button under my plugin to activate it.
== Screenshots ==
1. A screenshot of the form-tag generator for the dynamic text field.
== Frequently Asked Questions ==
Please check out the [FAQ on our website](https://aurisecreative.com/docs/contact-form-7-dynamic-text-extension/frequently-asked-questions/?utm_source=wordpress.org&utm_medium=link&utm_campaign=contact-form-7-dynamic-text-extension&utm_content=readme).
== Upgrade Notice ==
* 3.1.3 Fixed the syntax error that reappeared in 3.1.2. My apologies!
== Changelog ==
= 3.2 =
* Feature: Add optional 'part' parameter to CF7_URL shortcode to retrieve Host, Query, or Path from current URL
* Updated minimum PHP requirement to 7.4 moving forward
* Update branding assets
* Update Tested Up To to 6.1.1
* Plugin will now be jointly maintained by SevenSpark and AuRise Creative
= 3.1.3 =
* Fix: Fixed the syntax error that reappeared in 3.1.2.
= 3.1.2 =
**Release Date: January 27, 2023**
* Fix: updated the text domain to match the plugin slug
* Fix: updated all of the translated strings to match
= 3.1.1 =
**Release Date: January 26, 2023**
* Fix: Fixed the syntax error: Parse error: syntax error, unexpected `)` in /wp-content/plugins/contact-form-7-dynamic-text extension/includes/admin.php on line 212
= 3.1.0 =
**Release Date: January 25, 2023**
* Feature: Added the `CF7_get_attachment` shortcode. For usage details, see the [knowledge base](https://aurisecreative.com/docs/contact-form-7-dynamic-text-extension/shortcodes/dtx-shortcode-media-attachment/?utm_source=wordpress.org&utm_medium=link&utm_campaign=contact-form-7-dynamic-text-extension&utm_content=readme)
* Feature: Added the `CF7_guid` shortcode. For usage details, see the [knowledge base](https://aurisecreative.com/docs/contact-form-7-dynamic-text-extension/shortcodes/dtx-shortcode-guid/?utm_source=wordpress.org&utm_medium=link&utm_campaign=contact-form-7-dynamic-text-extension&utm_content=readme).
* Feature: Added the dynamic placeholder option to the dynamic form tags that allows you to specify dynamic or static placeholder content while also setting dynamic values. For usage details, see the [knowledge base](https://aurisecreative.com/docs/contact-form-7-dynamic-text-extension/shortcodes/dtx-attribute-placeholder/?utm_source=wordpress.org&utm_medium=link&utm_campaign=contact-form-7-dynamic-text-extension&utm_content=readme)
* Feature: Added a "required" dynamic hidden tag (e.g., `[dynamichidden* ...]`). It is identical to the original dynamic hidden tag (as in the field is not actually validated as required because it is hidden); it just doesn't break your website if you use it. This feature was requested by a user.
* Feature: Added the `obfuscate` attribute to all included shortcodes
= 3.0.0 =
**Release Date: January 17, 2023**
* Major: Plugin was adopted by AuRise Creative
* Major: All functions use the `wpcf7dtx_` prefix
* Feature: Added a `post_id` key for the `CF7_get_post_var` shortcode so you can specify a different post
* Feature: Updated the `CF7_get_current_user` shortcode to be able to pull data from user metadata too
* Feature: Added the "obfuscate" option to `CF7_get_custom_field` shortcode
* Feature: Added the "placeholder" checkbox option to the `dynamictext` tag
* Fix: Added additional validation for post ID input
* Fix: Added additional validation for the `key` attribute in the `CF7_GET` and `CF7_POST` shortcodes
* Fix: Shortcode keys are normalized into lowercase before processing
* Security: Sanitizing URLs for the `CF7_URL` and `CF7_referrer` shortcode outputs
* Feature/Security: Added a `allowed_protocols` attribute to the `CF7_URL` and `CF7_referrer` shortcodes that defaults to `http,https`
= 2.0.3 =
* Security: [Fix Reflected XSS](https://web.archive.org/web/20230121180428/https://sevenspark.com/docs/cf7-dtx-security-2019-07-24)
= 2.0.2.1 =
* Update changelog properly for 2.0.2 changes:
= 2.0.2 =
* Update deprecated `get_currentuserinfo()` function to `wp_get_current_user()`
* Update deprecated functions from `WPCF7_add_shortcode` to `WPCF7_add_formtag` and class from `WPCF7_Shortcode` to `WPCF7_FormTag` to comply with CF7 4.6 changes
= 2.0.1 =
* Hook change to guarantee the plugin only runs when Contact Form 7 is present in the admin (avoids errors if Contact Form 7 is disabled, or if there is a plugin sequencing issue)
= 2.0 =
* Complete rewrite for Compatibility with Contact Form 7 v4
= 1.2 =
* Compatibility update for Contact Form 7 v3.9
= 1.1.0.2 =
* Updated to work with Contact Form 7 v3.7.x
= 1.1.0.1 =
* Removed undefined variable warning
= 1.1 =
* Updated for compatibility with Contact Form 7 v3.6
* Added Referrer shortcode
= 1.0.4.2 =
* Fixed a bug that created repeating square brackets around dynamic text values in cases where the form doesn't validate and JavaScript is deactivated.
= 1.0.4.1 =
* Removed trailing whitespace to fix "Headers already sent" errors
= 1.0.4 =
* Added Current User Info shortcode
* Added Post Custom Field shortcode (with obfuscation support)
* Added Hidden Field capability
= 1.0.3 =
* Added $_POST shortcode
* Added current post/page variable shortcode
* Added current URL shortcode
= 1.0.2 =
* Fixed administrative control panel dependency issue
= 1.0.1 =
* Fixed dependency issue.

View File

@@ -0,0 +1,367 @@
<?php
/*
Plugin Name: Contact Form 7 Modules: Hidden Fields
Plugin URI: https://katz.co/contact-form-7-hidden-fields/
Description: Add hidden fields to the popular Contact Form 7 plugin.
Author: Katz Web Services, Inc.
Author URI: http://www.katz.co
Version: 2.0.2
Text Domain: cf7_modules
Domain Path: languages
License: GPLv2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
*/
add_action('plugins_loaded', 'contact_form_7_hidden_fields', 11);
function contact_form_7_hidden_fields() {
global $pagenow;
if ( class_exists( 'WPCF7_Shortcode' ) || class_exists('WPCF7_FormTag') ) {
if ( function_exists( 'wpcf7_add_form_tag' ) ) {
wpcf7_add_form_tag( array( 'hidden', 'hidden*' ), 'wpcf7_hidden_shortcode_handler', true );
} else {
wpcf7_add_shortcode( array( 'hidden', 'hidden*' ), 'wpcf7_hidden_shortcode_handler', true );
}
} else {
if ( $pagenow != 'plugins.php' ) {
return;
}
add_action( 'admin_notices', 'contact_form_7_hidden_fields_error' );
add_action( 'admin_enqueue_scripts', 'contact_form_7_hidden_fields_scripts' );
}
}
function contact_form_7_hidden_fields_error() {
$out = '<div class="error" id="messages"><p>';
if ( @ file_exists( WP_PLUGIN_DIR . '/contact-form-7/wp-contact-form-7.php' ) ) {
$out .= esc_html__( 'The Contact Form 7 is installed, but you must activate Contact Form 7 below for the Hidden Fields Module to work.', 'cf7_modules' );
} else {
$out .= esc_html__( 'The Contact Form 7 plugin must be installed for the Hidden Fields Module to work.', 'cf7_modules' );
$install_url = esc_url_raw( admin_url( 'plugin-install.php?tab=plugin-information&plugin=contact-form-7&from=plugins&TB_iframe=true&width=600&height=550' ) );
$out .= sprintf( ' <a href="%s" class="thickbox" title="Contact Form 7">%s</a>', $install_url, esc_html__( 'Install Now.', 'cf7_modules' ) );
}
$out .= '</p></div>';
echo $out;
}
function contact_form_7_hidden_fields_scripts() {
wp_enqueue_script('thickbox');
}
/**
** A base module for [hidden] and [hidden*]
**/
/* Shortcode handler */
add_filter('wpcf7_form_elements', 'wpcf7_form_elements_strip_paragraphs_and_brs');
/**
* Strip paragraph tags being wrapped around the field
* @param $form
*
* @return mixed
*/
function wpcf7_form_elements_strip_paragraphs_and_brs($form) {
return preg_replace_callback( '/<p>(<input\stype="hidden"(?:.*?))<\/p>/ism', 'wpcf7_form_elements_strip_paragraphs_and_brs_callback', $form );
}
function wpcf7_form_elements_strip_paragraphs_and_brs_callback($matches = array()) {
return "\n" . '<!-- CF7 Modules -->' . "\n" . '<div style=\'display:none;\'>' . str_replace( '<br>', '', str_replace( '<br />', '', stripslashes_deep( $matches[1] ) ) ) . '</div>' . "\n" . '<!-- End CF7 Modules -->' . "\n";
}
/**
** A base module for [hidden], [hidden*]
**/
/* Shortcode handler */
function wpcf7_hidden_shortcode_handler( $tag ) {
if ( class_exists( 'WPCF7_FormTag' ) ) {
$tag = new WPCF7_FormTag( $tag );
} else {
$tag = new WPCF7_Shortcode( $tag );
}
if ( empty( $tag->name ) ) {
return '';
}
$validation_error = wpcf7_get_validation_error( $tag->name );
$class = wpcf7_form_controls_class( $tag->type, 'wpcf7-hidden' );
if ( $validation_error ) {
$class .= ' wpcf7-not-valid';
}
$class .= ' wpcf7-hidden';
if ( 'hidden*' === $tag->type ) {
$class .= ' wpcf7-validates-as-required';
}
$value = (string) reset( $tag->values );
$placeholder = '';
if ( $tag->has_option( 'placeholder' ) || $tag->has_option( 'watermark' ) ) {
$placeholder = $value;
$value = '';
}
$default_value = $tag->get_default_option( $value );
$value = contact_form_7_hidden_fields_fill_post_data( $value, $tag );
// Post data hasn't filled yet. No arrays.
if ( $default_value === $value ) {
$value = contact_form_7_hidden_fields_fill_user_data( $value );
}
// Arrays get imploded.
$value = is_array( $value ) ? implode( apply_filters( 'wpcf7_hidden_field_implode_glue', ', ' ), $value ) : $value;
// Make sure we're using a string. Objects get JSON-encoded.
if ( ! is_string( $value ) ) {
$value = json_encode( $value );
}
$value = apply_filters( 'wpcf7_hidden_field_value', apply_filters( 'wpcf7_hidden_field_value_' . $tag->get_id_option(), $value ) );
$value = wpcf7_get_hangover( $tag->name, $value );
$atts = array(
'type' => 'hidden',
'class' => $tag->get_class_option( $class ),
'id' => $tag->get_id_option(),
'name' => $tag->name,
'tabindex' => $tag->get_option( 'tabindex', 'int', true ),
'placeholder' => $placeholder,
'value' => $value,
);
$atts = wpcf7_format_atts( $atts );
$html = sprintf( '<input %1$s />%2$s', $atts, $validation_error );
return $html;
}
/**
* Fill data based on user information.
*
* @param string $value Existing value, if any
*
* @return mixed
*/
function contact_form_7_hidden_fields_fill_user_data( $value ) {
$return = $value;
// Process user stuff
if ( preg_match( '/user/ism', strtolower( trim( $value ) ) ) && is_user_logged_in() ) {
$current_user = wp_get_current_user();
switch ( $value ) {
case 'user_name':
$return = $current_user->user_login;
break;
case 'user_id':
$return = $current_user->ID;
break;
case 'caps':
$return = $current_user->caps;
break;
case 'allcaps':
$return = $current_user->allcaps;
break;
case 'user_roles':
$return = $current_user->roles;
break;
default:
// Gets the values for `user_email`, others that have `user_` prefix.
if ( $current_user->has_prop( $value ) ) {
$return = $current_user->get( $value );
} else {
// Define some other item in the WP_User object using the `user_[what you want to get]` format
// This works for the `user_display_name` setting
$user_key = preg_replace( '/user[_-](.+)/ism', '$1', $value );
if ( $current_user->has_prop( $user_key ) ) {
$return = $current_user->get( $user_key );
}
}
break;
}
}
return $return;
}
/**
* Fill data based on user information.
*
* @param string $value Existing value, if any
* @param WPCF7_Shortcode $tag Tag
*
* @return mixed
*/
function contact_form_7_hidden_fields_fill_post_data( $value = '', $tag ) {
global $post;
$return = $value;
if ( is_object( $post ) ) {
switch ( strtolower( trim( $value ) ) ) {
case 'post_title':
case 'post-title':
$return = $post->post_title;
break;
case 'page_url':
case 'post_url':
$return = get_permalink( $post->ID );
if ( empty( $return ) && isset( $post->guid ) ) {
$return = $post->guid;
}
$return = esc_url( $return );
break;
case 'post_category':
$categories = get_the_category( $post->ID );
$catnames = array();
// Get the category names
foreach ( $categories as $cat ) {
$catnames[] = $cat->cat_name;
}
$return = implode( ', ', $catnames );
break;
case 'post_author_id':
$return = $post->post_author;
break;
case 'post_author':
$user = get_userdata( $post->post_author );
$return = $user->display_name;
break;
default:
// You want post_modified? just use [hidden hidden-123 "post_modified"]
if ( isset( $post->{ $value } ) ) {
$return = $post->{ $value };
}
break;
}
if ( preg_match( '/^custom_field\-(.*?)$/ism', $value ) ) {
$custom_field = preg_replace( '/custom_field\-(.*?)/ism', '$1', $value );
$return = get_post_meta( $post->ID, $custom_field, false ) ? get_post_meta( $post->ID, $custom_field, false ) : '';
}
}
return $return;
}
/* Tag generator */
if ( is_admin() ) {
add_action( 'admin_init', 'wpcf7_add_tag_generator_hidden', 30 );
}
function wpcf7_add_tag_generator_hidden() {
if ( class_exists( 'WPCF7_TagGenerator' ) ) {
$tag_generator = WPCF7_TagGenerator::get_instance();
$tag_generator->add( 'hidden', _x( 'hidden', 'the name of the field button in CF7', 'cf7_modules' ), 'wpcf7_tg_pane_hidden' );
}
}
function wpcf7_tg_pane_hidden( $contact_form, $args = '' ) {
$args = wp_parse_args( $args, array() );
$description = __( "Generate a form tag for a hidden field. For more details, see %s.", 'contact-form-7' );
$desc_link = wpcf7_link( 'https://wordpress.org/plugins/contact-form-7-modules/', __( 'the plugin page on WordPress.org', 'contact-form-7' ), array( 'target' => '_blank' ) );
?>
<div class="control-box">
<fieldset>
<legend><?php printf( esc_html( $description ), $desc_link ); ?></legend>
<table class="form-table">
<tbody>
<tr>
<th scope="row"><label
for="<?php echo esc_attr( $args['content'] . '-name' ); ?>"><?php echo esc_html( __( 'Name', 'contact-form-7' ) ); ?></label>
</th>
<td><input type="text" name="name" class="tg-name oneline"
id="<?php echo esc_attr( $args['content'] . '-name' ); ?>"/></td>
</tr>
<tr>
<th scope="row"><label
for="<?php echo esc_attr( $args['content'] . '-id' ); ?>"><?php echo esc_html( __( 'ID attribute', 'contact-form-7' ) ); ?>
(<?php echo esc_html( __( 'optional', 'cf7_modules' ) ); ?>)</label></th>
<td><input type="text" name="id" class="idvalue oneline option"
id="<?php echo esc_attr( $args['content'] . '-id' ); ?>"/></td>
</tr>
<tr>
<th scope="row">
<?php _e( 'Value', 'cf7_modules' ); ?>
</th>
<td>
<input type="text" name="values" class="oneline"/>
<div>
<input type="checkbox" name="watermark"
class="option"/>&nbsp;<?php echo esc_html( __( 'Use this text as watermark?', 'cf7_modules' ) ); ?>
</div>
</td>
</tr>
<tr>
<th scope="row">
<?php _e( 'Dynamic Values', 'cf7_modules' ); ?>
</th>
<td>
<span class="howto"
style="font-size:1em;"><?php _e( 'To use dynamic data from the post or page the form is embedded on, you can use the following values:', 'cf7_modules' ); ?></span>
<ul>
<li><?php _e( '<code>post_title</code>: The title of the post/page', 'cf7_modules' ); ?></li>
<li><?php _e( '<code>post_url</code>: The URL of the post/page', 'cf7_modules' ); ?></li>
<li><?php _e( '<code>post_category</code>: The categories the post is in, comma-separated', 'cf7_modules' ); ?></li>
<li><?php _e( '<code>post_date</code>: The date the post/page was created', 'cf7_modules' ); ?></li>
<li><?php _e( '<code>post_author</code>: The name of the author of the post/page', 'cf7_modules' ); ?></li>
</ul>
<span class="howto"><?php _e( 'The following values will be replaced if an user is logged in:', 'cf7_modules' ); ?></span>
<ul>
<li><?php _e( '<code>user_name</code>: User Login', 'cf7_modules' ); ?></li>
<li><?php _e( '<code>user_id</code>: User ID', 'cf7_modules' ); ?></li>
<li><?php _e( '<code>user_email</code>: User Email Address', 'cf7_modules' ); ?></li>
<li><?php _e( '<code>user_display_name</code>: Display Name (Generally the first and last name of the user)', 'cf7_modules' ); ?></li>
</ul>
</td>
</tr>
</tbody>
</table>
</fieldset>
</div>
<div class="insert-box">
<input type="text" name="hidden" class="tag code" readonly="readonly" onfocus="this.select()"/>
<div class="submitbox">
<input type="button" class="button button-primary insert-tag"
value="<?php echo esc_attr( __( 'Insert Tag', 'contact-form-7' ) ); ?>"/>
</div>
<br class="clear"/>
<p class="description mail-tag"><label
for="<?php echo esc_attr( $args['content'] . '-mailtag' ); ?>"><?php echo sprintf( esc_html( __( "To use the value input through this field in a mail field, you need to insert the corresponding mail-tag (%s) into the field on the Mail tab.", 'contact-form-7' ) ), '<strong><span class="mail-tag"></span></strong>' ); ?>
<input type="text" class="mail-tag code hidden" readonly="readonly"
id="<?php echo esc_attr( $args['content'] . '-mailtag' ); ?>"/></label></p>
</div>
<?php
}

View File

@@ -0,0 +1,133 @@
msgid ""
msgstr ""
"Project-Id-Version: Contact Form 7 Modules: Send All Fields\n"
"POT-Creation-Date: 2017-02-01 18:49-0700\n"
"PO-Revision-Date: 2017-02-01 18:49-0700\n"
"Last-Translator: Katz Web Services, Inc. <support@katz.co>\n"
"Language-Team: Zack Katz <support@katz.co>\n"
"Language: en_US\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 1.8.5\n"
"X-Poedit-Basepath: ..\n"
"X-Poedit-SourceCharset: UTF-8\n"
"X-Poedit-KeywordsList: __;_e;_n:1,2;_x:1,2c;_ex:1,2c;_nx:4c,1,2;esc_attr__;"
"esc_attr_e;esc_attr_x:1,2c;esc_html__;esc_html_e;esc_html_x:1,2c;"
"_n_noop:1,2;_nx_noop:3c,1,2;__ngettext_noop:1,2\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Poedit-SearchPath-0: .\n"
#: hidden.php:38
msgid ""
"The Contact Form 7 is installed, but you must activate Contact Form 7 below "
"for the Hidden Fields Module to work."
msgstr ""
#: hidden.php:40
msgid ""
"The Contact Form 7 plugin must be installed for the Hidden Fields Module to "
"work."
msgstr ""
#: hidden.php:42
msgid "Install Now."
msgstr ""
#: hidden.php:277
msgctxt "the name of the field button in CF7"
msgid "hidden"
msgstr ""
#: hidden.php:286
#, php-format
msgid "Generate a form tag for a hidden field. For more details, see %s."
msgstr ""
#: hidden.php:287
msgid "the plugin page on WordPress.org"
msgstr ""
#: hidden.php:297
msgid "Name"
msgstr ""
#: hidden.php:305
msgid "ID attribute"
msgstr ""
#: hidden.php:306
msgid "optional"
msgstr ""
#: hidden.php:312
msgid "Value"
msgstr ""
#: hidden.php:318
msgid "Use this text as watermark?"
msgstr ""
#: hidden.php:324
msgid "Dynamic Values"
msgstr ""
#: hidden.php:328
msgid ""
"To use dynamic data from the post or page the form is embedded on, you can "
"use the following values:"
msgstr ""
#: hidden.php:331
msgid "<code>post_title</code>: The title of the post/page"
msgstr ""
#: hidden.php:332
msgid "<code>post_url</code>: The URL of the post/page"
msgstr ""
#: hidden.php:333
msgid ""
"<code>post_category</code>: The categories the post is in, comma-separated"
msgstr ""
#: hidden.php:334
msgid "<code>post_date</code>: The date the post/page was created"
msgstr ""
#: hidden.php:335
msgid "<code>post_author</code>: The name of the author of the post/page"
msgstr ""
#: hidden.php:337
msgid "The following values will be replaced if an user is logged in:"
msgstr ""
#: hidden.php:339
msgid "<code>user_name</code>: User Login"
msgstr ""
#: hidden.php:340
msgid "<code>user_id</code>: User ID"
msgstr ""
#: hidden.php:341
msgid "<code>user_email</code>: User Email Address"
msgstr ""
#: hidden.php:342
msgid ""
"<code>user_display_name</code>: Display Name (Generally the first and last "
"name of the user)"
msgstr ""
#: hidden.php:356
msgid "Insert Tag"
msgstr ""
#: hidden.php:362
#, php-format
msgid ""
"To use the value input through this field in a mail field, you need to "
"insert the corresponding mail-tag (%s) into the field on the Mail tab."
msgstr ""

View File

@@ -0,0 +1,256 @@
=== Contact Form 7 Modules ===
Tags: Contact Form 7, cf7, Contact Forms 7, hidden fields, all fields
Requires at least: 2.8
Tested up to: 4.7.2
Stable tag: trunk
Contributors: katzwebdesign, katzwebservices
Donate link: https://katz.co/contact-form-7-hidden-fields/
License: GPLv2 or later
Contact Form 7 - Add useful modules such as hidden fields and "send all fields" to the Contact Form 7 plugin
== Description ==
### Add Hidden Fields to Contact Form 7
The Contact Form 7 plugin has over <em>1 million</em> active installations, yet the great plugin still lacks a simple feature: <strong>hidden fields</strong>. This plugin adds hidden fields to Contact Form 7 once and for all.
#### Inserting dynamic values
You can also choose to have the value of the hidden field dynamically populated in your form when you are contacted. To do so, choose the "Default value" to be:
* `post_title` - Inserts the title of the post/page
* `post_category` - The categories of the post or page
* `post_url` - The URL of the post or page
* `post_author` - The author of the post or page
* `custom_field-[Name]` - The value of a post or page's custom field. If you had a custom field "Foo", you would use the following as the hidden field value: `custom_field-Foo`
The following values will be replaced if an user is logged in:
* `user_name`: User Login
* `user_id`: User ID
* `user_email`: User Email Address
* `user_display_name`: Display Name (Generally the first and last name of the user)
* `user_url`: User Website
And you can also use it for user custom meta data using the format of `user-{field}`:
* `user-aim`: AIM
* `user-jabber`: Jabber / Google Talk
* `user-description`: User Bio
<strong>You can also use a filter:</strong> hook into the `wpcf7_hidden_field_value` filter to modify the value of the hidden field using <a href="http://codex.wordpress.org/Function_Reference/add_filter" rel="nofollow"><code>add_filter()</code></a>. If you know the ID of the input, you can also use the `wpcf7_hidden_field_value_[#ID]` filter.
Now, when someone contacts you using your Contact Form 7 contact form, you can have lots more information about their visit - and you'll see it when you receive the email that tells you you've been contacted.
### Easily Send All Submitted Fields At Once
####Save time setting up your form emails...and never miss a field!
One of the limitations of Contact Form 7 is that you need to manually add each field to generated emails. This means that if you update the form with a new field and forget to add it to your email message, you won't receive it in your email. <strong>No longer.</strong>.
Using the <strong>Send All Fields</strong> module, you simply need to add `[all-fields]` to your message, and you will receive every field submitted. If you use HTML formatting, the formatting even looks nice.
<h4>Visit the official <a href="https://katz.co/contact-form-7-hidden-fields/">Contact Form 7 Modules plugin page</a> for more support & additional information</h4>
== Screenshots ==
1. The Hidden fields tag generator
2. The `[all-fields]` Mail tag
== Installation ==
1. Upload plugin files to your plugins folder, or install using WordPress' built-in Add New Plugin installer
1. Activate the plugin
1. Edit a form in Contact Form 7
1. Choose "Hidden field" from the Generate Tag dropdown
1. Follow the instructions on the page
== Frequently Asked Questions ==
= How do I turn off formatting the key in the `[all-fields]` output? =
Add the following to your theme's `functions.php` file:
`
add_filter('wpcf7_send_all_fields_format_key', '__return_false');
`
= How do I set non-standard user data as hidden field values? =
Starting with Version 1.4, you can access user data, including meta data.
You need to set the default value as: `user-{meta_key}` where `{meta_key}` is the key of the meta field you want the value of.
To get the values of WordPress default profile fields, for example, you would use:
* `user-aim` - AOL
* `user-jabber` - Jabber / Google Talk
* `user-description` - Biographical description
= What is the plugin license? =
* This plugin is released under a GPL license.
= How do I send empty values with the `[all-fields]` shortcode? =
Add this to your `functions.php` file: `add_filter('wpcf7_send_all_fields_send_empty_fields', '__return_true');`
= How do I modify the output of the `[all-fields]` shortcode? =
* `wpcf7_send_all_fields_format_before` - Before the loop of fields (`<dl>` for HTML output)
* `$value` _string_ Previous output
* `$format` _string_ Either "html" or "text"
* `wpcf7_send_all_fields_format_item` - Change each item output. Passes four arguments:
* `$value` _string_ Previous output
* `$k` _string_ Field label
* `$v` _string_ Value of the field
* `$format` _string_ Either "html" or "text"
* `wpcf7_send_all_fields_format_after` - After the loop of fields (`</dl>` for HTML output). Passes two arguments:
* `$value` _string_ Previous output
* `$format` _string_ Either "html" or "text"
== Changelog ==
= 2.0.1 & 2.0.2 on February 1, 2017 =
* Confirmed compatibility with WordPress 4.7.2
* Updated to work with Contact Form 7 4.6
* Fixed: `[hidden]` shortcodes not being replaced in emails
* Fixed: PHP warning related to deprecated function
* Fixed: Removed use of deprecated `get_currentuserinfo()` function
* Updated translations
= 2.0 on June 28, 2015 =
* **Requires Contact Form 7 4.2 or higher**
* Updated to work with latest Contact Form 7
* Removed Contact Form 7 Newsletter plugin promotion
= 1.4.2 on March 25, 2014 =
* Added: `[all-fields]` shortcode now skips sending data for empty fields
* Added `wpcf7_send_all_fields_send_empty_fields` filter to override the setting. See the FAQ.
* Added: `[all-fields]` shortcode output filters (see the FAQ item "How do I modify the output...")
* `wpcf7_send_all_fields_format_before`
* `wpcf7_send_all_fields_format_item`
* `wpcf7_send_all_fields_format_after`
= 1.4 & 1.4.1 on March 15, 2014 =
* Added: Internationalization support. [Help translate the plugin!](https://www.transifex.com/projects/p/contact-form-7-modules/)
__The below updates apply only to the Hidden Fields module.__
* Added: Support for retrieving other user data by using the field name `user_{data you want}`. See the FAQ "How do I set non-standard user data as hidden field values?"
* Added: `wpcf7_hidden_field_implode_glue` filter. If you want to modify how arrays of data get combined into a string (default is CSV), use this filter.
* Fixed: `$post` global no longer needs to be defined for user data to be successfully passed.
* Fixed: Now supports multiple post `custom_field` data values, instead of only fetching one
* Modified: Added callback function to format the hidden field instead of relying on depricated PHP
* Modified: Improved include path for `functions.php` file
* Modified: Added text to support additional localization
= 1.3.3 =
* Hidden Fields: Fixed issue that broke the plugin with WordPress 3.8.
= 1.3.2 =
* Hidden Fields: Fixed PHP notice caused by improper adding of script in administration
* Hidden Fields: Fixed double inputs that were the exact same (<a href="http://wordpress.org/support/topic/render-the-fields-twice">as reported here</a>)
= 1.3.1 =
* Fixed: issue in Hidden Fields where the `[hidden-###]` shortcode no longer worked and only `[post_title]` format worked.
* Added: Hidden fields now support both formats: `[hidden-123]` and `[post_title]` as long as they're in the form itself.
* Fixed: issue in Send All Fields where the <a href="http://wordpress.org/support/topic/post_title-hidden-field-no-longer-working#post-3708463">HTML was showing as text</a>.
* Added `wpcf7_send_all_fields_format_key` filter to Send All Fields plugin to turn on or off formatting of the key (replacing `example-key` with `Example Key` in output). See "How do I turn off formatting the key in the `[all-fields]` output?" in the FAQ.
= 1.3 =
* Fixed: Hidden field now supports new Contact Form 7 format; post fields will work again.
* Fixed: Send All Fields no longer causes spinning form submission in WordPress 3.5
* Added: access any of the <a href="http://www.rlmseo.com/blog/wordpress-post-variable-quick-reference/" rel='nofollow'>data in `$post` object</a> by using the variable name. Example: You want `post_modified`? Use `[hidden hidden-123 "post_modified"]`
* Added: If an user is logged in, you can now use `user_name`, `user_id`, `user_email`, `user_display_name` replacement values
* Added/Improved: `post_author` will now return the author's Display Name. Use `post_author_id` for the post author's ID.
* Added: Inline instructions on the Hidden field module
* Improved: In Send All Fields, the name of the field now has dashes replaced with spaces. This will show "your name", rather than "your-name". Thanks, <a href="http://wordpress.org/support/topic/sending-all-fields-with-content-code-provided">@hitolonen</a>
= 1.2.2 =
* Removed `_wpnonce` field from `[all-fields]` output
* Fixed a conflict when using "Send All Fields" module alongside "Hidden Fields" module (<a href="http://wordpress.org/support/topic/plugin-contact-form-7-modules-all-fields-doesn´t-work-wit-wordpress-33">as reported here</a>)
= 1.2.1 =
* Added support for checkboxes with Send All Fields (`[all-fields]`)
= 1.2 =
* Hidden fields are now displayed inside a hidden `<div>` instead of Contact Form 7's default `<p>`. This makes hidden fields more hidden :-)
* Added brand-new module: Send All Fields. Allows you to add a `[all-fields]` tag to your email message that includes every submitted field in one tag.
= 1.1.1 =
* Fixed `Parameter 1 to wpcf7_add_tag_generator_hidden() expected to be a reference, value given` error, <a href="http://www.seodenver.com/contact-form-7-hidden-fields/#comment-116384456"> as reported by BDN Online</a>
= 1.1 =
* Added support for using post titles as hidden fields
* Added support for using custom field values as hidden fields
* Added `wpcf7_hidden_field_value` filter to hook into using <a href="http://codex.wordpress.org/Function_Reference/add_filter" rel="nofollow"><code>add_filter()</code></a>
= 1.0 =
* Initial plugin release.
== Upgrade Notice ==
= 1.4.2 on March 25, 2014 =
* Added: `[all-fields]` shortcode now skips sending data for empty fields
* Added `wpcf7_send_all_fields_send_empty_fields` filter to override the setting. See the FAQ.
* Added: `[all-fields]` shortcode output filters (see the FAQ item "How do I modify the output...")
* `wpcf7_send_all_fields_format_before`
* `wpcf7_send_all_fields_format_item`
* `wpcf7_send_all_fields_format_after`
= 1.4 & 1.4.1 on March 15, 2014 =
* Added: Internationalization support. [Help translate the plugin!](https://www.transifex.com/projects/p/contact-form-7-modules/)
__The below updates apply only to the Hidden Fields module.__
* Added: Support for retrieving other user data by using the field name `user_{data you want}`. See the FAQ "How do I set non-standard user data as hidden field values?"
* Added: `wpcf7_hidden_field_implode_glue` filter. If you want to modify how arrays of data get combined into a string (default is CSV), use this filter.
* Fixed: `$post` global no longer needs to be defined for user data to be successfully passed.
* Fixed: Now supports multiple post `custom_field` data values, instead of only fetching one
* Modified: Added callback function to format the hidden field instead of relying on depricated PHP
* Modified: Improved include path for `functions.php` file
* Modified: Added text to support additional localization
= 1.3.3 =
* Hidden Fields: Fixed issue that broke the plugin with the WordPress 3.8
= 1.3.2 =
* Hidden Fields: Fixed PHP notice caused by improper adding of script in administration
* Hidden Fields: Fixed double inputs that were the exact same (<a href="http://wordpress.org/support/topic/render-the-fields-twice">as reported here</a>)
= 1.3.1 =
* Fixed: issue in Hidden Fields where the `[hidden-###]` shortcode no longer worked and only `[post_title]` format worked.
* Fixed: issue in Send All Fields where the <a href="http://wordpress.org/support/topic/post_title-hidden-field-no-longer-working#post-3708463">HTML was showing as text</a>.
= 1.3 =
* Fixed: Hidden field now supports new Contact Form 7 format; post fields will work again.
* Fixed: Send All Fields no longer causes spinning form submission in WordPress 3.5
* Added: access any of the <a href="http://www.rlmseo.com/blog/wordpress-post-variable-quick-reference/" rel='nofollow'>data in `$post` object</a> by using the variable name. Example: You want `post_modified`? Use `[hidden hidden-123 "post_modified"]`
* Added: If an user is logged in, you can now use `user_name`, `user_id`, `user_email`, `user_display_name` replacement values
* Added/Improved: `post_author` will now return the author's Display Name. Use `post_author_id` for the post author's ID.
* Added: Inline instructions on the Hidden field module
* Improved: In Send All Fields, the name of the field now has dashes replaced with spaces. This will show "your name", rather than "your-name". Thanks, <a href="http://wordpress.org/support/topic/sending-all-fields-with-content-code-provided">@hitolonen</a>
= 1.2.2 =
* Removed `_wpnonce` field from `[all-fields]` output
* Fixed a conflict when using "Send All Fields" module alongside "Hidden Fields" module (<a href="http://wordpress.org/support/topic/plugin-contact-form-7-modules-all-fields-doesn´t-work-wit-wordpress-33">as reported here</a>)
= 1.2.1 =
* Added support for checkboxes with Send All Fields (`[all-fields]`)
= 1.2 =
* Hidden fields are now displayed inside a hidden `<div>` instead of Contact Form 7's default `<p>`. This makes hidden fields more hidden :-)
* Added brand-new module: Send All Fields. Allows you to add a `[all-fields]` tag to your email message that includes every submitted field in one tag.
= 1.1.1 =
* Fixed `Parameter 1 to wpcf7_add_tag_generator_hidden() expected to be a reference, value given` error, <a href="http://www.seodenver.com/contact-form-7-hidden-fields/#comment-116384456"> as reported by BDN Online</a>
= 1.1 =
* Added support for using post titles as hidden fields
* Added support for using custom field values as hidden fields
* Added `wpcf7_hidden_field_value` filter to hook into using <a href="http://codex.wordpress.org/Function_Reference/add_filter" rel="nofollow"><code>add_filter()</code></a>
= 1.0 =
* Woot!

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

View File

@@ -0,0 +1,111 @@
<?php
/*
Plugin Name: Contact Form 7 Modules: Send All Fields
Plugin URI: https://katz.co/contact-form-7-hidden-fields/
Description: Send all submitted fields in the message body using one simple tag: <code>[all-fields]</code>
Author: Katz Web Services, Inc.
Author URI: http://www.katz.co
Version: 2.0.2
Text Domain: cf7_modules
Domain Path: languages
License: GPLv2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
*/
add_filter('wpcf7_mail_components', 'all_fields_wpcf7_before_send_mail');
function all_fields_wpcf7_before_send_mail($array) {
$debug = false;
if ( $debug ) {
print_r( $array );
}
if ( $debug ) {
print_r( $_POST );
}
$post = $_POST;
$html = false;
if ( wpautop( $array['body'] ) == $array['body'] ) {
$html = true;
}
foreach ( $post as $k => $v ) {
if ( substr( $k, 0, 6 ) == '_wpcf7' || strpos( $k, 'all-fields' ) || $k === '_wpnonce' ) {
unset( $post["{$k}"] );
}
}
if ( $debug ) {
print_r( $post );
}
$postbody = '';
if ( $html ) {
$postbody = apply_filters( 'wpcf7_send_all_fields_format_before', '<dl>', 'html' );
} else {
$postbody = apply_filters( 'wpcf7_send_all_fields_format_before', '', 'text' );
}
foreach ( $post as $k => $v ) {
// Remove dupe content. The Hidden and Values are both sent.
if ( preg_match( '/hidden\-/', $k ) ) {
continue;
}
// If there's no value for the field, don't send it.
if ( empty( $v ) && false === apply_filters( 'wpcf7_send_all_fields_send_empty_fields', false ) ) {
continue;
}
if ( is_array( $v ) ) {
$v = implode( ', ', $v );
}
// Make the fields easier to read. Thanks, @hitolonen
$k = apply_filters( 'wpcf7_send_all_fields_format_key', true ) ? ucwords( str_replace( "-", " ", str_replace( "_", " ", $k ) ) ) : $k;
// Sanitize!
$k = esc_attr( $k );
$v = esc_attr( $v );
if ( $html ) {
$postbody .= apply_filters( 'wpcf7_send_all_fields_format_item', "<dt style='font-size:1.2em;'><font size='3'><strong style='font-weight:bold;'>{$k}</strong>:</font></dt><dd style='padding:0 0 .5em 1.5em; margin:0;'>{$v}</dd>", $k, $v, 'html' );
} else {
$postbody .= apply_filters( 'wpcf7_send_all_fields_format_item', "{$k}: {$v}\n", $k, $v, 'text' );
}
}
if ( $html ) {
$postbody .= apply_filters( 'wpcf7_send_all_fields_format_after', '</dl>', 'html' );
} else {
$postbody .= apply_filters( 'wpcf7_send_all_fields_format_after', '', 'text' );
}
if ( $debug ) {
print_r( $postbody );
}
$array['body'] = str_replace( '<p>[all-fields]</p>', $postbody, str_replace( '[all-fields]', $postbody, $array['body'] ) );
if ( $debug ) {
die();
} else {
return $array;
}
}
add_filter('wpcf7_collect_mail_tags', 'wpcf7_collect_mail_tags_add_all_fields_tag');
/**
* Add a all-fields option to the Mail tab's merge tags
* @since 2.0
* @param array $mailtags
*/
function wpcf7_collect_mail_tags_add_all_fields_tag( $mailtags = array() ) {
$mailtags[] = 'all-fields';
return $mailtags;
}

View File

@@ -0,0 +1,24 @@
<?php
/*
Plugin Name: Contact Form 7 Shortcode Enabler
Plugin URI: #
Description: This plugin enables the usage of external shortcuts inside Contact Form 7 Forms.
Version: 1.1
Author: Tobias Zimpel (TZ Media)
Author URI: http://www.tobias-zimpel.de
License: GPLv2 or later.
*/
function wpcf7_shortcode_enabler_activate() {
if ( ! is_plugin_active( 'contact-form-7/wp-contact-form-7.php' ) and current_user_can( 'activate_plugins' ) ) {
// Stop activation redirect and show error
wp_die('Sorry, but this plugin requires the <a href="https://wordpress.org/plugins/contact-form-7/">Contact Form 7</a> Plugin to be installed and active. <br><a href="' . admin_url( 'plugins.php' ) . '">&laquo; Return to Plugins</a>');
}
}
register_activation_hook( __FILE__, 'wpcf7_shortcode_enabler_activate' );
// Activate Shortcode Execution for Contact Form 7
add_filter( 'wpcf7_form_elements', 'do_shortcode' );
?>

View File

@@ -0,0 +1,36 @@
=== Contact Form 7 Shortcode Enabler ===
Contributors: TZ Media
Tags: Contact Form 7, CF7, Shortcode, Shortcodes
Requires at least: 4.0
Tested up to: 4.6.1
Stable tag: 1.1
License: GPLv2 or later.
License URI: http://www.gnu.org/licenses/gpl-2.0.html
This plugin enables the usage of external shortcuts inside Contact Form 7 Forms.
== Description ==
Many themes, as well as other plugins, provide shortcodes for layout options like multi-column-layouts, tabs, etc.
By default, Contact Form 7 forms can not include shortcodes provided by WordPress or third-party-plugins or -themes.
This plugin enables the usage of external shortcodes inside Contact Form 7 Forms.
== Installation ==
1. Upload the entire cf7-enable-shortcode folder to the /wp-content/plugins/ directory.
1. Activate the plugin through the 'Plugins' menu in WordPress.
The Plugin requires no additional configuration.
== Frequently Asked Questions ==
= I'm missing some feature in the plugin =
I'm pretty sure you are missing a feature in Contact Form 7 itself, not in this plugin. Otherwise, please drop me a message and I'll see what I can do.
== Changelog ==
= 1.1 =
* NEW: Added dependency to Contact Form 7 Plugin
= 1.0 =
* NEW: Enables shortcodes inside Contact Form 7 Forms

View File

@@ -0,0 +1,695 @@
<?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 New Contact Form', 'contact-form-7' ),
__( 'Add New', '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/css/styles.css' ),
array(), WPCF7_VERSION, 'all'
);
if ( wpcf7_is_rtl() ) {
wp_enqueue_style( 'contact-form-7-admin-rtl',
wpcf7_plugin_url( 'admin/css/styles-rtl.css' ),
array(), WPCF7_VERSION, 'all'
);
}
wp_enqueue_script( 'wpcf7-admin',
wpcf7_plugin_url( 'admin/js/scripts.js' ),
array( 'jquery', 'jquery-ui-tabs' ),
WPCF7_VERSION, true
);
$args = array(
'apiSettings' => array(
'root' => sanitize_url( rest_url( 'contact-form-7/v1' ) ),
'namespace' => 'contact-form-7/v1',
'nonce' => ( wp_installing() && ! is_multisite() )
? '' : wp_create_nonce( 'wp_rest' ),
),
'pluginUrl' => wpcf7_plugin_url(),
'saveAlert' => __(
"The changes you made will be lost if you navigate away from this page.",
'contact-form-7' ),
'activeTab' => isset( $_GET['active-tab'] )
? (int) $_GET['active-tab'] : 0,
'configValidator' => array(
'errors' => array(),
'howToCorrect' => __( "How to resolve?", 'contact-form-7' ),
'oneError' => __( '1 configuration error detected', 'contact-form-7' ),
'manyErrors' => __( '%d configuration errors detected', 'contact-form-7' ),
'oneErrorInTab' => __( '1 configuration error detected in this tab panel', 'contact-form-7' ),
'manyErrorsInTab' => __( '%d configuration errors detected in this tab panel', 'contact-form-7' ),
'docUrl' => WPCF7_ConfigValidator::get_doc_link(),
/* translators: screen reader text */
'iconAlt' => __( '(configuration error)', 'contact-form-7' ),
),
);
if ( $post = wpcf7_get_current_contact_form()
and current_user_can( 'wpcf7_edit_contact_form', $post->id() )
and wpcf7_validate_configuration() ) {
$config_validator = new WPCF7_ConfigValidator( $post );
$config_validator->restore();
$args['configValidator']['errors'] =
$config_validator->collect_error_messages();
}
wp_localize_script( 'wpcf7-admin', 'wpcf7', $args );
add_thickbox();
wp_enqueue_script( 'wpcf7-admin-taggenerator',
wpcf7_plugin_url( 'admin/js/tag-generator.js' ),
array( 'jquery', 'thickbox', 'wpcf7-admin' ),
WPCF7_VERSION,
true
);
}
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 ) ) {
$result = $value;
}
return $result;
},
10, 3
);
function wpcf7_load_contact_form_admin() {
global $plugin_page;
$action = wpcf7_current_action();
do_action( 'wpcf7_admin_load',
isset( $_GET['page'] ) ? trim( $_GET['page'] ) : '',
$action
);
if ( 'save' == $action ) {
$id = isset( $_POST['post_ID'] ) ? $_POST['post_ID'] : '-1';
check_admin_referer( 'wpcf7-save-contact-form_' . $id );
if ( ! current_user_can( 'wpcf7_edit_contact_form', $id ) ) {
wp_die(
__( "You are not allowed to edit this item.", 'contact-form-7' )
);
}
$args = $_REQUEST;
$args['id'] = $id;
$args['title'] = isset( $_POST['post_title'] )
? $_POST['post_title'] : null;
$args['locale'] = isset( $_POST['wpcf7-locale'] )
? $_POST['wpcf7-locale'] : null;
$args['form'] = isset( $_POST['wpcf7-form'] )
? $_POST['wpcf7-form'] : '';
$args['mail'] = isset( $_POST['wpcf7-mail'] )
? $_POST['wpcf7-mail'] : array();
$args['mail_2'] = isset( $_POST['wpcf7-mail-2'] )
? $_POST['wpcf7-mail-2'] : array();
$args['messages'] = isset( $_POST['wpcf7-messages'] )
? $_POST['wpcf7-messages'] : array();
$args['additional_settings'] = isset( $_POST['wpcf7-additional-settings'] )
? $_POST['wpcf7-additional-settings'] : '';
$contact_form = wpcf7_save_contact_form( $args );
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' => isset( $_POST['active-tab'] )
? (int) $_POST['active-tab'] : 0,
);
if ( ! $contact_form ) {
$query['message'] = 'failed';
} elseif ( -1 == $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 = empty( $_POST['post_ID'] )
? absint( $_REQUEST['post'] )
: absint( $_POST['post_ID'] );
check_admin_referer( 'wpcf7-copy-contact-form_' . $id );
if ( ! current_user_can( 'wpcf7_edit_contact_form', $id ) ) {
wp_die(
__( "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 ) {
if ( ! empty( $_POST['post_ID'] ) ) {
check_admin_referer( 'wpcf7-delete-contact-form_' . $_POST['post_ID'] );
} elseif ( ! is_array( $_REQUEST['post'] ) ) {
check_admin_referer( 'wpcf7-delete-contact-form_' . $_REQUEST['post'] );
} else {
check_admin_referer( 'bulk-posts' );
}
$posts = empty( $_POST['post_ID'] )
? (array) $_REQUEST['post']
: (array) $_POST['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(
__( "You are not allowed to delete this item.", 'contact-form-7' )
);
}
if ( ! $post->delete() ) {
wp_die( __( "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' => isset( $_GET['locale'] ) ? $_GET['locale'] : null,
) );
} elseif ( ! empty( $_GET['post'] ) ) {
$post = WPCF7_ContactForm::get_instance( $_GET['post'] );
}
$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();
?>
<div class="wrap" id="wpcf7-contact-form-list-table">
<h1 class="wp-heading-inline"><?php
echo esc_html( __( 'Contact Forms', 'contact-form-7' ) );
?></h1>
<?php
if ( current_user_can( 'wpcf7_edit_contact_forms' ) ) {
echo wpcf7_link(
menu_page_url( 'wpcf7-new', false ),
__( 'Add New', 'contact-form-7' ),
array( 'class' => 'page-title-action' )
);
}
if ( ! empty( $_REQUEST['s'] ) ) {
echo sprintf(
'<span class="subtitle">'
/* translators: %s: search keywords */
. __( 'Search results for &#8220;%s&#8221;', 'contact-form-7' )
. '</span>',
esc_html( $_REQUEST['s'] )
);
}
?>
<hr class="wp-header-end">
<?php
do_action( 'wpcf7_admin_warnings',
'wpcf7', wpcf7_current_action(), null
);
wpcf7_welcome_panel();
do_action( 'wpcf7_admin_notices',
'wpcf7', wpcf7_current_action(), null
);
?>
<form method="get" action="">
<input type="hidden" name="page" value="<?php echo esc_attr( $_REQUEST['page'] ); ?>" />
<?php $list_table->search_box( __( 'Search Contact Forms', 'contact-form-7' ), 'wpcf7-contact' ); ?>
<?php $list_table->display(); ?>
</form>
</div>
<?php
}
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',
isset( $_GET['page'] ) ? trim( $_GET['page'] ) : '',
wpcf7_current_action()
);
$integration = WPCF7_Integration::get_instance();
if ( isset( $_REQUEST['service'] )
and $integration->service_exists( $_REQUEST['service'] ) ) {
$service = $integration->get_service( $_REQUEST['service'] );
$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 = isset( $_REQUEST['service'] )
? $integration->get_service( $_REQUEST['service'] )
: null;
?>
<div class="wrap" id="wpcf7-integration">
<h1><?php echo esc_html( __( 'Integration with External API', 'contact-form-7' ) ); ?></h1>
<p><?php
echo sprintf(
/* translators: %s: link labeled 'Integration with external APIs' */
esc_html( __( "You can expand the possibilities of your contact forms by integrating them with external services. For details, see %s.", 'contact-form-7' ) ),
wpcf7_link(
__( 'https://contactform7.com/integration-with-external-apis/', 'contact-form-7' ),
__( 'Integration with external APIs', 'contact-form-7' )
)
);
?></p>
<?php
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 = isset( $_REQUEST['message'] ) ? $_REQUEST['message'] : '';
$service->admin_notice( $message );
$integration->list_services( array(
'include' => $_REQUEST['service'],
) );
} else {
$integration->list_services();
}
?>
</div>
<?php
}
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' ) ) ) {
return;
}
if ( empty( $_REQUEST['message'] ) ) {
return;
}
if ( 'created' == $_REQUEST['message'] ) {
$updated_message = __( "Contact form created.", 'contact-form-7' );
} elseif ( 'saved' == $_REQUEST['message'] ) {
$updated_message = __( "Contact form saved.", 'contact-form-7' );
} elseif ( 'deleted' == $_REQUEST['message'] ) {
$updated_message = __( "Contact form deleted.", 'contact-form-7' );
}
if ( ! empty( $updated_message ) ) {
echo sprintf(
'<div id="message" class="notice notice-success"><p>%s</p></div>',
esc_html( $updated_message )
);
return;
}
if ( 'failed' == $_REQUEST['message'] ) {
$updated_message =
__( "There was an error saving the contact form.", 'contact-form-7' );
echo sprintf(
'<div id="message" class="notice notice-error"><p>%s</p></div>',
esc_html( $updated_message )
);
return;
}
if ( 'validated' == $_REQUEST['message'] ) {
$bulk_validate = WPCF7::get_option( 'bulk_validate', array() );
$count_invalid = isset( $bulk_validate['count_invalid'] )
? absint( $bulk_validate['count_invalid'] ) : 0;
if ( $count_invalid ) {
$updated_message = sprintf(
_n(
/* translators: %s: number of contact forms */
"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 )
);
echo sprintf(
'<div id="message" class="notice notice-warning"><p>%s</p></div>',
esc_html( $updated_message )
);
} else {
$updated_message = __( "Configuration validation completed. No invalid contact form was found.", 'contact-form-7' );
echo sprintf(
'<div id="message" class="notice notice-success"><p>%s</p></div>',
esc_html( $updated_message )
);
}
return;
}
}
add_filter( 'plugin_action_links', 'wpcf7_plugin_action_links', 10, 2 );
function wpcf7_plugin_action_links( $links, $file ) {
if ( $file != WPCF7_PLUGIN_BASENAME ) {
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, '<' ) ) {
return;
}
?>
<div class="notice notice-warning">
<p><?php
echo 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' )
);
?></p>
</div>
<?php
}
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() ) ) {
return;
}
$message = __( "You are not allowed to edit this contact form.", 'contact-form-7' );
echo sprintf(
'<div class="notice notice-warning"><p>%s</p></div>',
esc_html( $message )
);
}
add_action( 'wpcf7_admin_warnings', 'wpcf7_outdated_php_warning', 10, 3 );
function wpcf7_outdated_php_warning( $page, $action, $object ) {
if ( ! version_compare( PHP_VERSION, '7.4', '<' ) ) {
return;
}
$message = __( "The next major release of Contact Form 7 will discontinue support for outdated PHP versions. If you don't upgrade PHP, you will not be able to upgrade the plugin.", 'contact-form-7' );
echo sprintf(
'<div class="notice notice-warning"><p>%s</p></div>',
esc_html( $message )
);
}

View File

@@ -0,0 +1,77 @@
/*
* Tabs
*/
#contact-form-editor-tabs {
padding: 9px 10px 0 15px;
}
/*
* Form Tab
*/
.tag-generator-panel {
text-align: right;
}
.tag-generator-panel .control-box > fieldset > legend {
border: 1px solid #dfdfdf;
border-right: 4px solid #00a0d2;
}
.tag-generator-panel .insert-box input.tag {
float: right;
}
.tag-generator-panel .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,512 @@
#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;
}
#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;
}
.keyboard-interaction {
visibility: hidden;
color: #23282d; /* Dark Gray 800 */
}
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;
}
[data-config-field][aria-invalid="true"] {
border-color: #dc3232;
}
#contact-form-editor-tabs li a .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: text-top;
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 15px 0 10px;
margin: 0;
}
#contact-form-editor-tabs li {
display: inline-block;
list-style: none;
border: 1px solid #ccc;
border-bottom: 1px solid #aaa;
padding: 0;
margin: 0 4px -1px;
background-color: #e4e4e4;
}
#contact-form-editor-tabs li:hover {
background-color: #fff;
}
#contact-form-editor-tabs li.ui-tabs-active,
#contact-form-editor-tabs li.ui-tabs-active:hover {
border-top: 1px solid #aaa;
border-right: 1px solid #aaa;
border-left: 1px solid #aaa;
border-bottom: 1px solid #f5f5f5;
background-color: #f5f5f5;
}
#contact-form-editor-tabs li a {
padding: 6px 10px;
font-size: 14px;
font-weight: normal;
line-height: 30px;
color: #333;
text-decoration: none;
}
#contact-form-editor-tabs li.ui-tabs-active a {
color: #000;
font-size: 14px;
font-weight: bold;
}
#contact-form-editor-tabs li a:hover {
color: #000;
}
#contact-form-editor .contact-form-editor-panel > div.config-error {
margin-bottom: 1.4em;
}
#contact-form-editor-tabs li.ui-tabs-active a .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 a.button {
font-size: 12px;
height: 26px;
line-height: 24px;
margin: 2px;
padding: 0 8px 1px;
}
.tag-generator-panel {
height: 495px;
display: flex;
flex-direction: column;
}
.tag-generator-panel .control-box {
padding: 0;
margin: 0;
overflow: auto;
flex-grow: 1;
}
.tag-generator-panel .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;
}
.tag-generator-panel table {
width: 100%;
}
.tag-generator-panel table.form-table th {
width: 120px;
padding: 4px 10px 4px 0;
font-size: 13px;
}
.tag-generator-panel table.form-table td {
padding: 4px 10px;
font-size: 13px;
}
.tag-generator-panel .control-box input.oneline {
width: 200px;
}
.tag-generator-panel .control-box input.large-text {
width: 400px;
}
.tag-generator-panel .control-box textarea.values {
width: 200px;
height: 6em;
}
.tag-generator-panel .control-box input[type="number"],
.tag-generator-panel .control-box input[type="date"] {
width: 88px;
}
.tag-generator-panel .control-box table caption {
text-align: left;
font-size: 110%;
font-weight: bold;
color: #777;
margin: 10px 0 5px;
}
.tag-generator-panel .control-box table.form-table td label {
line-height: 1.1em;
}
.tag-generator-panel .control-box table.form-table td label .description {
line-height: 1.4em;
}
.tag-generator-panel .insert-box {
margin: 0 -15px -15px;
padding: 8px 16px;
background-color: #fcfcfc;
border-top: 1px solid #dfdfdf;
overflow: auto;
}
.tag-generator-panel .insert-box input.tag {
width: 510px;
float: left;
background-color: transparent;
box-shadow: none;
}
.tag-generator-panel .insert-box .submitbox {
padding: 0;
}
.tag-generator-panel .insert-box .submitbox input[type="button"] {
float: right;
}
.tag-generator-panel .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
*/
#ctct-panel table tr.inactive ~ tr,
#sendinblue-panel table tr.inactive ~ tr {
display: none;
}
#ctct-panel .dashicons,
#sendinblue-panel .dashicons {
text-decoration: none;
}
#ctct-panel td p,
#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;
}
.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,301 @@
<?php
// don't load directly
if ( ! defined( 'ABSPATH' ) ) {
die( '-1' );
}
function wpcf7_admin_save_button( $post_id ) {
static $button = '';
if ( ! empty( $button ) ) {
echo $button;
return;
}
$nonce = wp_create_nonce( 'wpcf7-save-contact-form_' . $post_id );
$onclick = sprintf(
"this.form._wpnonce.value = '%s';"
. " this.form.action.value = 'save';"
. " return true;",
$nonce );
$button = sprintf(
'<input type="submit" class="button-primary" name="wpcf7-save" value="%1$s" onclick="%2$s" />',
esc_attr( __( 'Save', 'contact-form-7' ) ),
$onclick );
echo $button;
}
?><div class="wrap" id="wpcf7-contact-form-editor">
<h1 class="wp-heading-inline"><?php
if ( $post->initial() ) {
echo esc_html( __( 'Add New Contact Form', 'contact-form-7' ) );
} else {
echo esc_html( __( 'Edit Contact Form', 'contact-form-7' ) );
}
?></h1>
<?php
if ( ! $post->initial()
and current_user_can( 'wpcf7_edit_contact_forms' ) ) {
echo wpcf7_link(
menu_page_url( 'wpcf7-new', false ),
__( 'Add New', 'contact-form-7' ),
array( 'class' => 'page-title-action' )
);
}
?>
<hr class="wp-header-end">
<?php
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
);
?>
<?php
if ( $post ) :
if ( current_user_can( 'wpcf7_edit_contact_form', $post_id ) ) {
$disabled = '';
} else {
$disabled = ' disabled="disabled"';
}
?>
<form method="post" action="<?php echo esc_url( add_query_arg( array( 'post' => $post_id ), menu_page_url( 'wpcf7', false ) ) ); ?>" id="wpcf7-admin-form-element"<?php do_action( 'wpcf7_post_edit_form_tag' ); ?>>
<?php
if ( current_user_can( 'wpcf7_edit_contact_form', $post_id ) ) {
wp_nonce_field( 'wpcf7-save-contact-form_' . $post_id );
}
?>
<input type="hidden" id="post_ID" name="post_ID" value="<?php echo (int) $post_id; ?>" />
<input type="hidden" id="wpcf7-locale" name="wpcf7-locale" value="<?php echo esc_attr( $post->locale() ); ?>" />
<input type="hidden" id="hiddenaction" name="action" value="save" />
<input type="hidden" id="active-tab" name="active-tab" value="<?php echo isset( $_GET['active-tab'] ) ? (int) $_GET['active-tab'] : '0'; ?>" />
<div id="poststuff">
<div id="post-body" class="metabox-holder columns-2">
<div id="post-body-content">
<div id="titlediv">
<div id="titlewrap">
<label class="screen-reader-text" id="title-prompt-text" for="title"><?php echo esc_html( __( 'Enter title here', 'contact-form-7' ) ); ?></label>
<?php
$posttitle_atts = array(
'type' => 'text',
'name' => 'post_title',
'size' => 30,
'value' => $post->initial() ? '' : $post->title(),
'id' => 'title',
'spellcheck' => 'true',
'autocomplete' => 'off',
'disabled' => ! current_user_can( 'wpcf7_edit_contact_form', $post_id ),
);
echo sprintf( '<input %s />', wpcf7_format_atts( $posttitle_atts ) );
?>
</div><!-- #titlewrap -->
<div class="inside">
<?php
if ( ! $post->initial() ) :
?>
<p class="description">
<label for="wpcf7-shortcode"><?php echo esc_html( __( "Copy this shortcode and paste it into your post, page, or text widget content:", 'contact-form-7' ) ); ?></label>
<span class="shortcode wp-ui-highlight"><input type="text" id="wpcf7-shortcode" onfocus="this.select();" readonly="readonly" class="large-text code" value="<?php echo esc_attr( $post->shortcode() ); ?>" /></span>
</p>
<?php
if ( $old_shortcode = $post->shortcode( array( 'use_old_format' => true ) ) ) :
?>
<p class="description">
<label for="wpcf7-shortcode-old"><?php echo esc_html( __( "You can also use this old-style shortcode:", 'contact-form-7' ) ); ?></label>
<span class="shortcode old"><input type="text" id="wpcf7-shortcode-old" onfocus="this.select();" readonly="readonly" class="large-text code" value="<?php echo esc_attr( $old_shortcode ); ?>" /></span>
</p>
<?php
endif;
endif;
?>
</div>
</div><!-- #titlediv -->
</div><!-- #post-body-content -->
<div id="postbox-container-1" class="postbox-container">
<?php if ( current_user_can( 'wpcf7_edit_contact_form', $post_id ) ) : ?>
<div id="submitdiv" class="postbox">
<h3><?php echo esc_html( __( 'Status', 'contact-form-7' ) ); ?></h3>
<div class="inside">
<div class="submitbox" id="submitpost">
<div id="minor-publishing-actions">
<div class="hidden">
<input type="submit" class="button-primary" name="wpcf7-save" value="<?php echo esc_attr( __( 'Save', 'contact-form-7' ) ); ?>" />
</div>
<?php
if ( ! $post->initial() ) :
$copy_nonce = wp_create_nonce( 'wpcf7-copy-contact-form_' . $post_id );
?>
<input type="submit" name="wpcf7-copy" class="copy button" value="<?php echo esc_attr( __( 'Duplicate', 'contact-form-7' ) ); ?>" <?php echo "onclick=\"this.form._wpnonce.value = '$copy_nonce'; this.form.action.value = 'copy'; return true;\""; ?> />
<?php endif; ?>
</div><!-- #minor-publishing-actions -->
<div id="misc-publishing-actions">
<?php do_action( 'wpcf7_admin_misc_pub_section', $post_id ); ?>
</div><!-- #misc-publishing-actions -->
<div id="major-publishing-actions">
<?php
if ( ! $post->initial() ) :
$delete_nonce = wp_create_nonce( 'wpcf7-delete-contact-form_' . $post_id );
?>
<div id="delete-action">
<input type="submit" name="wpcf7-delete" class="delete submitdelete" value="<?php echo esc_attr( __( 'Delete', 'contact-form-7' ) ); ?>" <?php echo "onclick=\"if (confirm('" . esc_js( __( "You are about to delete this contact form.\n 'Cancel' to stop, 'OK' to delete.", 'contact-form-7' ) ) . "')) {this.form._wpnonce.value = '$delete_nonce'; this.form.action.value = 'delete'; return true;} return false;\""; ?> />
</div><!-- #delete-action -->
<?php endif; ?>
<div id="publishing-action">
<span class="spinner"></span>
<?php wpcf7_admin_save_button( $post_id ); ?>
</div>
<div class="clear"></div>
</div><!-- #major-publishing-actions -->
</div><!-- #submitpost -->
</div>
</div><!-- #submitdiv -->
<?php endif; ?>
<div id="informationdiv" class="postbox">
<h3><?php echo esc_html( __( "Do you need help?", 'contact-form-7' ) ); ?></h3>
<div class="inside">
<p><?php echo esc_html( __( "Here are some available options to help solve your problems.", 'contact-form-7' ) ); ?></p>
<ol>
<li><?php echo sprintf(
/* translators: 1: FAQ, 2: Docs ("FAQ & Docs") */
__( '%1$s and %2$s', 'contact-form-7' ),
wpcf7_link(
__( 'https://contactform7.com/faq/', 'contact-form-7' ),
__( 'FAQ', 'contact-form-7' )
),
wpcf7_link(
__( 'https://contactform7.com/docs/', 'contact-form-7' ),
__( 'docs', 'contact-form-7' )
)
); ?></li>
<li><?php echo wpcf7_link(
__( 'https://wordpress.org/support/plugin/contact-form-7/', 'contact-form-7' ),
__( 'Support forums', 'contact-form-7' )
); ?></li>
<li><?php echo wpcf7_link(
__( 'https://contactform7.com/custom-development/', 'contact-form-7' ),
__( 'Professional services', 'contact-form-7' )
); ?></li>
</ol>
</div>
</div><!-- #informationdiv -->
</div><!-- #postbox-container-1 -->
<div id="postbox-container-2" class="postbox-container">
<div id="contact-form-editor">
<div class="keyboard-interaction"><?php
echo sprintf(
/* translators: 1: ◀ ▶ dashicon, 2: screen reader text for the dashicon */
esc_html( __( '%1$s %2$s keys switch panels', 'contact-form-7' ) ),
'<span class="dashicons dashicons-leftright" aria-hidden="true"></span>',
sprintf(
'<span class="screen-reader-text">%s</span>',
/* translators: screen reader text */
esc_html( __( '(left and right arrow)', 'contact-form-7' ) )
)
);
?></div>
<?php
$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();
?>
</div><!-- #contact-form-editor -->
<?php if ( current_user_can( 'wpcf7_edit_contact_form', $post_id ) ) : ?>
<p class="submit"><?php wpcf7_admin_save_button( $post_id ); ?></p>
<?php endif; ?>
</div><!-- #postbox-container-2 -->
</div><!-- #post-body -->
<br class="clear" />
</div><!-- #poststuff -->
</form>
<?php endif; ?>
</div><!-- .wrap -->
<?php
$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() {
if ( isset( $_REQUEST['action'] ) and -1 != $_REQUEST['action'] ) {
return $_REQUEST['action'];
}
if ( isset( $_REQUEST['action2'] ) and -1 != $_REQUEST['action2'] ) {
return $_REQUEST['action2'];
}
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,243 @@
<?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 ( ! empty( $_REQUEST['s'] ) ) {
$args['s'] = $_REQUEST['s'];
}
if ( ! empty( $_REQUEST['orderby'] ) ) {
if ( 'title' == $_REQUEST['orderby'] ) {
$args['orderby'] = 'title';
} elseif ( 'author' == $_REQUEST['orderby'] ) {
$args['orderby'] = 'author';
} elseif ( 'date' == $_REQUEST['orderby'] ) {
$args['orderby'] = 'date';
}
}
if ( ! empty( $_REQUEST['order'] ) ) {
if ( 'asc' == strtolower( $_REQUEST['order'] ) ) {
$args['order'] = 'ASC';
} elseif ( 'desc' == strtolower( $_REQUEST['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(
_n(
/* translators: %s: number of errors detected */
'%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" . '<span class="shortcode"><input type="text"'
. ' onfocus="this.select();" readonly="readonly"'
. ' value="' . esc_attr( $shortcode ) . '"'
. ' class="large-text code" /></span>';
}
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,141 @@
<?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;
}
$link = wpcf7_link(
add_query_arg(
array( 'action' => 'validate' ),
menu_page_url( 'wpcf7', false )
),
__( 'Validate Contact Form 7 Configuration', 'contact-form-7' )
);
$message = __( "Misconfiguration leads to mail delivery failure or other troubles. Validate your contact forms now.", 'contact-form-7' );
echo sprintf(
'<div class="notice notice-warning"><p>%1$s &raquo; %2$s</p></div>',
esc_html( $message ),
$link
);
}
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' != $_SERVER['REQUEST_METHOD'] ) {
return;
}
check_admin_referer( 'wpcf7-bulk-validate' );
if ( ! current_user_can( 'wpcf7_edit_contact_forms' ) ) {
wp_die( __( "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(
_n(
/* translators: %s: number of contact forms */
"Validate %s contact form now",
"Validate %s contact forms now",
$count, 'contact-form-7'
),
number_format_i18n( $count )
);
?>
<div class="wrap">
<h1><?php echo esc_html( __( 'Validate Configuration', 'contact-form-7' ) ); ?></h1>
<form method="post" action="">
<input type="hidden" name="action" value="validate" />
<?php wp_nonce_field( 'wpcf7-bulk-validate' ); ?>
<p><input type="submit" class="button" value="<?php echo esc_attr( $submit_text ); ?>" /></p>
</form>
<?php
echo wpcf7_link(
__( 'https://contactform7.com/configuration-validator-faq/', 'contact-form-7' ),
__( 'FAQ about Configuration Validator', 'contact-form-7' )
);
?>
</div>
<?php
}

View File

@@ -0,0 +1,263 @@
<?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;
}
echo '<ul id="contact-form-editor-tabs">';
foreach ( $this->panels as $panel_id => $panel ) {
echo sprintf(
'<li id="%1$s-tab"><a href="#%1$s">%2$s</a></li>',
esc_attr( $panel_id ),
esc_html( $panel['title'] )
);
}
echo '</ul>';
foreach ( $this->panels as $panel_id => $panel ) {
echo sprintf(
'<div class="contact-form-editor-panel" id="%1$s">',
esc_attr( $panel_id )
);
if ( is_callable( $panel['callback'] ) ) {
$this->notice( $panel_id, $panel );
call_user_func( $panel['callback'], $this->contact_form );
}
echo '</div>';
}
}
public function notice( $panel_id, $panel ) {
echo '<div class="config-error"></div>';
}
}
function wpcf7_editor_panel_form( $post ) {
$desc_link = wpcf7_link(
__( 'https://contactform7.com/editing-form-template/', 'contact-form-7' ),
__( 'Editing form template', 'contact-form-7' ) );
$description = __( "You can edit the form template here. For details, see %s.", 'contact-form-7' );
$description = sprintf( esc_html( $description ), $desc_link );
?>
<h2><?php echo esc_html( __( 'Form', 'contact-form-7' ) ); ?></h2>
<fieldset>
<legend><?php echo $description; ?></legend>
<?php
$tag_generator = WPCF7_TagGenerator::get_instance();
$tag_generator->print_buttons();
?>
<textarea id="wpcf7-form" name="wpcf7-form" cols="100" rows="24" class="large-text code" data-config-field="form.body"><?php echo esc_textarea( $post->prop( 'form' ) ); ?></textarea>
</fieldset>
<?php
}
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, $args = '' ) {
$args = wp_parse_args( $args, array(
'id' => 'wpcf7-mail',
'name' => 'mail',
'title' => __( 'Mail', 'contact-form-7' ),
'use' => null,
) );
$id = esc_attr( $args['id'] );
$mail = wp_parse_args( $post->prop( $args['name'] ), array(
'active' => false,
'recipient' => '',
'sender' => '',
'subject' => '',
'body' => '',
'additional_headers' => '',
'attachments' => '',
'use_html' => false,
'exclude_blank' => false,
) );
?>
<div class="contact-form-editor-box-mail" id="<?php echo $id; ?>">
<h2><?php echo esc_html( $args['title'] ); ?></h2>
<?php
if ( ! empty( $args['use'] ) ) :
?>
<label for="<?php echo $id; ?>-active"><input type="checkbox" id="<?php echo $id; ?>-active" name="<?php echo $id; ?>[active]" class="toggle-form-table" value="1"<?php echo ( $mail['active'] ) ? ' checked="checked"' : ''; ?> /> <?php echo esc_html( $args['use'] ); ?></label>
<p class="description"><?php echo esc_html( __( "Mail (2) is an additional mail template often used as an autoresponder.", 'contact-form-7' ) ); ?></p>
<?php
endif;
?>
<fieldset>
<legend>
<?php
$desc_link = wpcf7_link(
__( 'https://contactform7.com/setting-up-mail/', 'contact-form-7' ),
__( 'Setting up mail', 'contact-form-7' ) );
$description = __( "You can edit the mail template here. For details, see %s.", 'contact-form-7' );
$description = sprintf( esc_html( $description ), $desc_link );
echo $description;
echo '<br />';
echo esc_html( __( "In the following fields, you can use these mail-tags:",
'contact-form-7' ) );
echo '<br />';
$post->suggest_mail_tags( $args['name'] );
?>
</legend>
<table class="form-table">
<tbody>
<tr>
<th scope="row">
<label for="<?php echo $id; ?>-recipient"><?php echo esc_html( __( 'To', 'contact-form-7' ) ); ?></label>
</th>
<td>
<input type="text" id="<?php echo $id; ?>-recipient" name="<?php echo $id; ?>[recipient]" class="large-text code" size="70" value="<?php echo esc_attr( $mail['recipient'] ); ?>" data-config-field="<?php echo sprintf( '%s.recipient', esc_attr( $args['name'] ) ); ?>" />
</td>
</tr>
<tr>
<th scope="row">
<label for="<?php echo $id; ?>-sender"><?php echo esc_html( __( 'From', 'contact-form-7' ) ); ?></label>
</th>
<td>
<input type="text" id="<?php echo $id; ?>-sender" name="<?php echo $id; ?>[sender]" class="large-text code" size="70" value="<?php echo esc_attr( $mail['sender'] ); ?>" data-config-field="<?php echo sprintf( '%s.sender', esc_attr( $args['name'] ) ); ?>" />
</td>
</tr>
<tr>
<th scope="row">
<label for="<?php echo $id; ?>-subject"><?php echo esc_html( __( 'Subject', 'contact-form-7' ) ); ?></label>
</th>
<td>
<input type="text" id="<?php echo $id; ?>-subject" name="<?php echo $id; ?>[subject]" class="large-text code" size="70" value="<?php echo esc_attr( $mail['subject'] ); ?>" data-config-field="<?php echo sprintf( '%s.subject', esc_attr( $args['name'] ) ); ?>" />
</td>
</tr>
<tr>
<th scope="row">
<label for="<?php echo $id; ?>-additional-headers"><?php echo esc_html( __( 'Additional headers', 'contact-form-7' ) ); ?></label>
</th>
<td>
<textarea id="<?php echo $id; ?>-additional-headers" name="<?php echo $id; ?>[additional_headers]" cols="100" rows="4" class="large-text code" data-config-field="<?php echo sprintf( '%s.additional_headers', esc_attr( $args['name'] ) ); ?>"><?php echo esc_textarea( $mail['additional_headers'] ); ?></textarea>
</td>
</tr>
<tr>
<th scope="row">
<label for="<?php echo $id; ?>-body"><?php echo esc_html( __( 'Message body', 'contact-form-7' ) ); ?></label>
</th>
<td>
<textarea id="<?php echo $id; ?>-body" name="<?php echo $id; ?>[body]" cols="100" rows="18" class="large-text code" data-config-field="<?php echo sprintf( '%s.body', esc_attr( $args['name'] ) ); ?>"><?php echo esc_textarea( $mail['body'] ); ?></textarea>
<p><label for="<?php echo $id; ?>-exclude-blank"><input type="checkbox" id="<?php echo $id; ?>-exclude-blank" name="<?php echo $id; ?>[exclude_blank]" value="1"<?php echo ( ! empty( $mail['exclude_blank'] ) ) ? ' checked="checked"' : ''; ?> /> <?php echo esc_html( __( 'Exclude lines with blank mail-tags from output', 'contact-form-7' ) ); ?></label></p>
<p><label for="<?php echo $id; ?>-use-html"><input type="checkbox" id="<?php echo $id; ?>-use-html" name="<?php echo $id; ?>[use_html]" value="1"<?php echo ( $mail['use_html'] ) ? ' checked="checked"' : ''; ?> /> <?php echo esc_html( __( 'Use HTML content type', 'contact-form-7' ) ); ?></label></p>
</td>
</tr>
<tr>
<th scope="row">
<label for="<?php echo $id; ?>-attachments"><?php echo esc_html( __( 'File attachments', 'contact-form-7' ) ); ?></label>
</th>
<td>
<textarea id="<?php echo $id; ?>-attachments" name="<?php echo $id; ?>[attachments]" cols="100" rows="4" class="large-text code" data-config-field="<?php echo sprintf( '%s.attachments', esc_attr( $args['name'] ) ); ?>"><?php echo esc_textarea( $mail['attachments'] ); ?></textarea>
</td>
</tr>
</tbody>
</table>
</fieldset>
</div>
<?php
}
function wpcf7_editor_panel_messages( $post ) {
$desc_link = wpcf7_link(
__( 'https://contactform7.com/editing-messages/', 'contact-form-7' ),
__( 'Editing messages', 'contact-form-7' ) );
$description = __( "You can edit messages used in various situations here. For details, see %s.", 'contact-form-7' );
$description = sprintf( esc_html( $description ), $desc_link );
$messages = wpcf7_messages();
if ( isset( $messages['captcha_not_match'] )
and ! wpcf7_use_really_simple_captcha() ) {
unset( $messages['captcha_not_match'] );
}
?>
<h2><?php echo esc_html( __( 'Messages', 'contact-form-7' ) ); ?></h2>
<fieldset>
<legend><?php echo $description; ?></legend>
<?php
foreach ( $messages as $key => $arr ) {
$field_id = sprintf( 'wpcf7-message-%s', strtr( $key, '_', '-' ) );
$field_name = sprintf( 'wpcf7-messages[%s]', $key );
?>
<p class="description">
<label for="<?php echo $field_id; ?>"><?php echo esc_html( $arr['description'] ); ?><br />
<input type="text" id="<?php echo $field_id; ?>" name="<?php echo $field_name; ?>" class="large-text" size="70" value="<?php echo esc_attr( $post->message( $key, false ) ); ?>" data-config-field="<?php echo sprintf( 'messages.%s', esc_attr( $key ) ); ?>" />
</label>
</p>
<?php
}
?>
</fieldset>
<?php
}
function wpcf7_editor_panel_additional_settings( $post ) {
$desc_link = wpcf7_link(
__( 'https://contactform7.com/additional-settings/', 'contact-form-7' ),
__( 'Additional settings', 'contact-form-7' ) );
$description = __( "You can add customization code snippets here. For details, see %s.", 'contact-form-7' );
$description = sprintf( esc_html( $description ), $desc_link );
?>
<h2><?php echo esc_html( __( 'Additional Settings', 'contact-form-7' ) ); ?></h2>
<fieldset>
<legend><?php echo $description; ?></legend>
<textarea id="wpcf7-additional-settings" name="wpcf7-additional-settings" cols="100" rows="8" class="large-text" data-config-field="additional_settings.body"><?php echo esc_textarea( $post->prop( 'additional_settings' ) ); ?></textarea>
</fieldset>
<?php
}

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,80 @@
<?php
class WPCF7_TagGenerator {
private static $instance;
private $panels = array();
private function __construct() {}
public static function get_instance() {
if ( empty( self::$instance ) ) {
self::$instance = new self;
}
return self::$instance;
}
public function add( $id, $title, $callback, $options = array() ) {
$id = trim( $id );
if ( '' === $id
or ! wpcf7_is_name( $id ) ) {
return false;
}
$this->panels[$id] = array(
'title' => $title,
'content' => 'tag-generator-panel-' . $id,
'options' => $options,
'callback' => $callback,
);
return true;
}
public function print_buttons() {
echo '<span id="tag-generator-list">';
foreach ( (array) $this->panels as $panel ) {
echo sprintf(
'<a href="#TB_inline?width=900&height=500&inlineId=%1$s" class="thickbox button" title="%2$s">%3$s</a>',
esc_attr( $panel['content'] ),
esc_attr( sprintf(
/* translators: %s: title of form-tag like 'email' or 'checkboxes' */
__( 'Form-tag Generator: %s', 'contact-form-7' ),
$panel['title'] ) ),
esc_html( $panel['title'] )
);
}
echo '</span>';
}
public function print_panels( WPCF7_ContactForm $contact_form ) {
foreach ( (array) $this->panels as $id => $panel ) {
$callback = $panel['callback'];
$options = wp_parse_args( $panel['options'], array() );
$options = array_merge( $options, array(
'id' => $id,
'title' => $panel['title'],
'content' => $panel['content'],
) );
if ( is_callable( $callback ) ) {
echo sprintf( '<div id="%s" class="hidden">',
esc_attr( $options['content'] ) );
echo sprintf(
'<form action="" class="tag-generator-panel" data-id="%s">',
$options['id'] );
call_user_func( $callback, $contact_form, $options );
echo '</form></div>';
}
}
}
}

View File

@@ -0,0 +1,307 @@
<?php
abstract class WPCF7_WelcomePanelColumn {
abstract protected function icon();
abstract protected function title();
abstract protected function content();
public function print_content() {
$icon = sprintf(
'<span class="dashicons dashicons-%s" aria-hidden="true"></span>',
esc_attr( $this->icon() )
);
$title = sprintf(
'<h3>%1$s %2$s</h3>',
$icon,
$this->title()
);
$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 );
echo "\n";
echo '<div class="welcome-panel-column">';
echo $title;
echo $content;
echo '</div>';
}
}
class WPCF7_WelcomePanelColumn_AntiSpam extends WPCF7_WelcomePanelColumn {
protected function icon() {
return 'shield';
}
protected function title() {
return esc_html(
__( "Getting spammed? You have protection.", 'contact-form-7' )
);
}
protected function content() {
return array(
esc_html( __( "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: links labeled 1: 'Akismet', 2: 'reCAPTCHA', 3: 'disallowed list' */
esc_html( __( 'Contact Form 7 supports spam-filtering with %1$s. Intelligent %2$s blocks annoying spambots. Plus, using %3$s, you can block messages containing specified keywords or those sent from specified IP addresses.', 'contact-form-7' ) ),
wpcf7_link(
__( 'https://contactform7.com/spam-filtering-with-akismet/', 'contact-form-7' ),
__( 'Akismet', 'contact-form-7' )
),
wpcf7_link(
__( 'https://contactform7.com/recaptcha/', 'contact-form-7' ),
__( 'reCAPTCHA', 'contact-form-7' )
),
wpcf7_link(
__( 'https://contactform7.com/comment-blacklist/', 'contact-form-7' ),
__( 'disallowed list', 'contact-form-7' )
)
),
);
}
}
class WPCF7_WelcomePanelColumn_Donation extends WPCF7_WelcomePanelColumn {
protected function icon() {
return 'megaphone';
}
protected function title() {
return esc_html(
__( "Contact Form 7 needs your support.", 'contact-form-7' )
);
}
protected function content() {
return array(
esc_html( __( "It is hard to continue development and support for this plugin without contributions from users like you.", 'contact-form-7' ) ),
sprintf(
/* translators: %s: link labeled 'making a donation' */
esc_html( __( 'If you enjoy using Contact Form 7 and find it useful, please consider %s.', 'contact-form-7' ) ),
wpcf7_link(
__( 'https://contactform7.com/donate/', 'contact-form-7' ),
__( 'making a donation', 'contact-form-7' )
)
),
esc_html( __( "Your donation will help encourage and support the plugin&#8217;s continued development and better user support.", 'contact-form-7' ) ),
);
}
}
class WPCF7_WelcomePanelColumn_Flamingo extends WPCF7_WelcomePanelColumn {
protected function icon() {
return 'editor-help';
}
protected function title() {
return esc_html(
__( "Before you cry over spilt mail&#8230;", 'contact-form-7' )
);
}
protected function content() {
return array(
esc_html( __( "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: link labeled 'Flamingo' */
esc_html( __( 'Install a message storage plugin before this happens to you. %s 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' ) ),
wpcf7_link(
__( 'https://contactform7.com/save-submitted-messages-with-flamingo/', 'contact-form-7' ),
__( 'Flamingo', 'contact-form-7' )
)
),
);
}
}
class WPCF7_WelcomePanelColumn_Integration extends WPCF7_WelcomePanelColumn {
protected function icon() {
return 'superhero-alt';
}
protected function title() {
return esc_html(
__( "You have strong allies to back you up.", 'contact-form-7' )
);
}
protected function content() {
return array(
sprintf(
/* translators: 1: link labeled 'Brevo', 2: link labeled 'Constant Contact' */
esc_html( __( '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 (%1$s and %2$s).', 'contact-form-7' ) ),
wpcf7_link(
__( 'https://contactform7.com/sendinblue-integration/', 'contact-form-7' ),
__( 'Brevo', 'contact-form-7' )
),
wpcf7_link(
__( 'https://contactform7.com/constant-contact-integration/', 'contact-form-7' ),
__( 'Constant Contact', 'contact-form-7' )
)
),
sprintf(
/* translators: 1: link labeled 'reCAPTCHA', 2: link labeled 'Stripe' */
esc_html( __( 'With help from cloud-based machine learning, anti-spam services will protect your forms (%1$s). Even payment services are natively supported (%2$s).', 'contact-form-7' ) ),
wpcf7_link(
__( 'https://contactform7.com/recaptcha/', 'contact-form-7' ),
__( 'reCAPTCHA', 'contact-form-7' )
),
wpcf7_link(
__( 'https://contactform7.com/stripe-integration/', 'contact-form-7' ),
__( 'Stripe', '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 );
$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;
}

View File

@@ -0,0 +1,313 @@
( function( $ ) {
'use strict';
if ( typeof wpcf7 === 'undefined' || wpcf7 === null ) {
return;
}
$( function() {
var welcomePanel = $( '#wpcf7-welcome-panel' );
var updateWelcomePanel;
updateWelcomePanel = function( visible ) {
$.post( ajaxurl, {
action: 'wpcf7-update-welcome-panel',
visible: visible,
welcomepanelnonce: $( '#welcomepanelnonce' ).val()
} );
};
$( 'a.welcome-panel-close', welcomePanel ).click( function( event ) {
event.preventDefault();
welcomePanel.addClass( 'hidden' );
updateWelcomePanel( 0 );
$( '#wpcf7-welcome-panel-show' ).prop( 'checked', false );
} );
$( '#wpcf7-welcome-panel-show' ).click( function( event ) {
if ( this.checked ) {
welcomePanel.removeClass( 'hidden' );
updateWelcomePanel( 1 );
} else {
welcomePanel.addClass( 'hidden' );
updateWelcomePanel( 0 );
}
} );
$( '#contact-form-editor' ).tabs( {
active: wpcf7.activeTab,
activate: function( event, ui ) {
$( '#active-tab' ).val( ui.newTab.index() );
}
} );
$( '#contact-form-editor-tabs' ).focusin( function( event ) {
$( '#contact-form-editor .keyboard-interaction' ).css(
'visibility', 'visible' );
} ).focusout( function( event ) {
$( '#contact-form-editor .keyboard-interaction' ).css(
'visibility', 'hidden' );
} );
wpcf7.toggleMail2( 'input:checkbox.toggle-form-table' );
$( 'input:checkbox.toggle-form-table' ).click( function( event ) {
wpcf7.toggleMail2( this );
} );
if ( '' === $( '#title' ).val() ) {
$( '#title' ).focus();
}
wpcf7.titleHint();
$( '.contact-form-editor-box-mail span.mailtag' ).click( function( event ) {
var range = document.createRange();
range.selectNodeContents( this );
window.getSelection().addRange( range );
} );
wpcf7.updateConfigErrors();
$( '[data-config-field]' ).change( function() {
var postId = $( '#post_ID' ).val();
if ( ! postId || -1 == postId ) {
return;
}
var data = [];
$( this ).closest( 'form' ).find( '[data-config-field]' ).each( function() {
data.push( {
'name': $( this ).attr( 'name' ).replace( /^wpcf7-/, '' ).replace( /-/g, '_' ),
'value': $( this ).val()
} );
} );
data.push( { 'name': 'context', 'value': 'dry-run' } );
$.ajax( {
method: 'POST',
url: wpcf7.apiSettings.getRoute( '/contact-forms/' + postId ),
beforeSend: function( xhr ) {
xhr.setRequestHeader( 'X-WP-Nonce', wpcf7.apiSettings.nonce );
},
data: data
} ).done( function( response ) {
wpcf7.configValidator.errors = response.config_errors;
wpcf7.updateConfigErrors();
} );
} );
$( window ).on( 'beforeunload', function( event ) {
var changed = false;
$( '#wpcf7-admin-form-element :input[type!="hidden"]' ).each( function() {
if ( $( this ).is( ':checkbox, :radio' ) ) {
if ( this.defaultChecked != $( this ).is( ':checked' ) ) {
changed = true;
}
} else if ( $( this ).is( 'select' ) ) {
$( this ).find( 'option' ).each( function() {
if ( this.defaultSelected != $( this ).is( ':selected' ) ) {
changed = true;
}
} );
} else {
if ( this.defaultValue != $( this ).val() ) {
changed = true;
}
}
} );
if ( changed ) {
event.returnValue = wpcf7.saveAlert;
return wpcf7.saveAlert;
}
} );
$( '#wpcf7-admin-form-element' ).submit( function() {
if ( 'copy' != this.action.value ) {
$( window ).off( 'beforeunload' );
}
if ( 'save' == this.action.value ) {
$( '#publishing-action .spinner' ).addClass( 'is-active' );
}
} );
$( '#wpcf7-ctct-enable-contact-list, #wpcf7-sendinblue-enable-contact-list, #wpcf7-sendinblue-enable-transactional-email' ).on( 'change', function() {
if ( $( this ).is( ':checked' ) ) {
$( this ).closest( 'tr' ).removeClass( 'inactive' );
} else {
$( this ).closest( 'tr' ).addClass( 'inactive' );
}
} );
} );
wpcf7.toggleMail2 = function( checkbox ) {
var $checkbox = $( checkbox );
var $fieldset = $( 'fieldset',
$checkbox.closest( '.contact-form-editor-box-mail' ) );
if ( $checkbox.is( ':checked' ) ) {
$fieldset.removeClass( 'hidden' );
} else {
$fieldset.addClass( 'hidden' );
}
};
wpcf7.updateConfigErrors = function() {
var errors = wpcf7.configValidator.errors;
var errorCount = { total: 0 };
$( '[data-config-field]' ).each( function() {
$( this ).removeAttr( 'aria-invalid' );
$( this ).next( 'ul.config-error' ).remove();
var section = $( this ).attr( 'data-config-field' );
$( this ).attr( 'aria-describedby', 'wpcf7-config-error-for-' + section );
if ( errors[ section ] ) {
var $list = $( '<ul></ul>' ).attr( {
'id': 'wpcf7-config-error-for-' + section,
'class': 'config-error'
} );
$.each( errors[ section ], function( i, val ) {
var $li = $( '<li></li>' ).append(
wpcf7.iconInCircle( '!' )
).append(
$( '<span class="screen-reader-text"></span>' ).text( wpcf7.configValidator.iconAlt )
).append( ' ' );
if ( val.link ) {
$li.append(
$( '<a></a>' ).attr( 'href', val.link ).text( val.message )
);
} else {
$li.text( val.message );
}
$li.appendTo( $list );
var tab = section
.replace( /^mail_\d+\./, 'mail.' ).replace( /\..*$/, '' );
if ( ! errorCount[ tab ] ) {
errorCount[ tab ] = 0;
}
errorCount[ tab ] += 1;
errorCount.total += 1;
} );
$( this ).after( $list ).attr( { 'aria-invalid': 'true' } );
}
} );
$( '#contact-form-editor-tabs > li' ).each( function() {
var $item = $( this );
$item.find( '.icon-in-circle' ).remove();
var tab = $item.attr( 'id' ).replace( /-panel-tab$/, '' );
$.each( errors, function( key, val ) {
key = key.replace( /^mail_\d+\./, 'mail.' );
if ( key.replace( /\..*$/, '' ) == tab.replace( '-', '_' ) ) {
var $mark = wpcf7.iconInCircle( '!' );
$item.find( 'a.ui-tabs-anchor' ).first().append( $mark );
return false;
}
} );
var $tabPanelError = $( '#' + tab + '-panel > div.config-error:first' );
$tabPanelError.empty();
if ( errorCount[ tab.replace( '-', '_' ) ] ) {
$tabPanelError.append( wpcf7.iconInCircle( '!' ) );
if ( 1 < errorCount[ tab.replace( '-', '_' ) ] ) {
var manyErrorsInTab = wpcf7.configValidator.manyErrorsInTab
.replace( '%d', errorCount[ tab.replace( '-', '_' ) ] );
$tabPanelError.append( manyErrorsInTab );
} else {
$tabPanelError.append( wpcf7.configValidator.oneErrorInTab );
}
}
} );
$( '#misc-publishing-actions .misc-pub-section.config-error' ).remove();
if ( errorCount.total ) {
var $warning = $( '<div></div>' )
.addClass( 'misc-pub-section config-error' )
.append( wpcf7.iconInCircle( '!' ) );
if ( 1 < errorCount.total ) {
$warning.append(
wpcf7.configValidator.manyErrors.replace( '%d', errorCount.total )
);
} else {
$warning.append( wpcf7.configValidator.oneError );
}
$warning.append( '<br />' ).append(
$( '<a></a>' )
.attr( 'href', wpcf7.configValidator.docUrl )
.text( wpcf7.configValidator.howToCorrect )
);
$( '#misc-publishing-actions' ).append( $warning );
}
};
/**
* Copied from wptitlehint() in wp-admin/js/post.js
*/
wpcf7.titleHint = function() {
var $title = $( '#title' );
var $titleprompt = $( '#title-prompt-text' );
if ( '' === $title.val() ) {
$titleprompt.removeClass( 'screen-reader-text' );
}
$titleprompt.click( function() {
$( this ).addClass( 'screen-reader-text' );
$title.focus();
} );
$title.blur( function() {
if ( '' === $(this).val() ) {
$titleprompt.removeClass( 'screen-reader-text' );
}
} ).focus( function() {
$titleprompt.addClass( 'screen-reader-text' );
} ).keydown( function( e ) {
$titleprompt.addClass( 'screen-reader-text' );
$( this ).unbind( e );
} );
};
wpcf7.iconInCircle = function( icon ) {
var $span = $( '<span class="icon-in-circle" aria-hidden="true"></span>' );
return $span.text( icon );
};
wpcf7.apiSettings.getRoute = function( path ) {
var url = wpcf7.apiSettings.root;
url = url.replace(
wpcf7.apiSettings.namespace,
wpcf7.apiSettings.namespace + path );
return url;
};
} )( jQuery );

View File

@@ -0,0 +1,249 @@
( function( $ ) {
'use strict';
if ( typeof wpcf7 === 'undefined' || wpcf7 === null ) {
return;
}
wpcf7.taggen = {};
$( function() {
$( 'form.tag-generator-panel' ).each( function() {
wpcf7.taggen.update( $( this ) );
} );
} );
$( 'form.tag-generator-panel' ).submit( function() {
return false;
} );
$( 'form.tag-generator-panel .control-box :input' ).change( function() {
var $form = $( this ).closest( 'form.tag-generator-panel' );
wpcf7.taggen.normalize( $( this ) );
wpcf7.taggen.update( $form );
} );
$( 'input.insert-tag' ).click( function() {
var $form = $( this ).closest( 'form.tag-generator-panel' );
var tag = $form.find( 'input.tag' ).val();
wpcf7.taggen.insert( tag );
tb_remove(); // close thickbox
return false;
} );
wpcf7.taggen.update = function( $form ) {
var id = $form.attr( 'data-id' );
var name = '';
var name_fields = $form.find( 'input[name="name"]' );
if ( name_fields.length ) {
name = name_fields.val();
if ( '' === name ) {
name = id + '-' + Math.floor( Math.random() * 1000 );
name_fields.val( name );
}
}
if ( $.isFunction( wpcf7.taggen.update[ id ] ) ) {
return wpcf7.taggen.update[ id ].call( this, $form );
}
$form.find( 'input.tag' ).each( function() {
var tag_type = $( this ).attr( 'name' );
if ( $form.find( ':input[name="tagtype"]' ).length ) {
tag_type = $form.find( ':input[name="tagtype"]' ).val();
}
if ( $form.find( ':input[name="required"]' ).is( ':checked' ) ) {
tag_type += '*';
}
var components = wpcf7.taggen.compose( tag_type, $form );
$( this ).val( components );
} );
$form.find( 'span.mail-tag' ).text( '[' + name + ']' );
$form.find( 'input.mail-tag' ).each( function() {
$( this ).val( '[' + name + ']' );
} );
};
wpcf7.taggen.update.captcha = function( $form ) {
var captchac = wpcf7.taggen.compose( 'captchac', $form );
var captchar = wpcf7.taggen.compose( 'captchar', $form );
$form.find( 'input.tag' ).val( captchac + ' ' + captchar );
};
wpcf7.taggen.compose = function( tagType, $form ) {
var name = $form.find( 'input[name="name"]' ).val();
var scope = $form.find( '.scope.' + tagType );
if ( ! scope.length ) {
scope = $form;
}
var options = [];
scope.find( 'input.option' ).not( ':checkbox,:radio' ).each( function( i ) {
var val = $( this ).val();
if ( ! val ) {
return;
}
if ( $( this ).hasClass( 'filetype' ) ) {
val = val.split( /[,|\s]+/ ).join( '|' );
}
if ( $( this ).hasClass( 'color' ) ) {
val = '#' + val;
}
if ( 'class' == $( this ).attr( 'name' ) ) {
$.each( val.split( ' ' ), function( i, n ) {
options.push( 'class:' + n );
} );
} else {
options.push( $( this ).attr( 'name' ) + ':' + val );
}
} );
scope.find( 'input:checkbox.option' ).each( function( i ) {
if ( $( this ).is( ':checked' ) ) {
options.push( $( this ).attr( 'name' ) );
}
} );
scope.find( 'input:radio.option' ).each( function( i ) {
if ( $( this ).is( ':checked' ) && ! $( this ).hasClass( 'default' ) ) {
options.push( $( this ).attr( 'name' ) + ':' + $( this ).val() );
}
} );
if ( 'radio' == tagType ) {
options.push( 'default:1' );
}
options = ( options.length > 0 ) ? options.join( ' ' ) : '';
var value = '';
if ( scope.find( ':input[name="values"]' ).val() ) {
$.each(
scope.find( ':input[name="values"]' ).val().split( "\n" ),
function( i, n ) {
value += ' "' + n.replace( /["]/g, '&quot;' ) + '"';
}
);
}
var components = [];
$.each( [ tagType, name, options, value ], function( i, v ) {
v = $.trim( v );
if ( '' != v ) {
components.push( v );
}
} );
components = $.trim( components.join( ' ' ) );
components = '[' + components + ']';
var content = scope.find( ':input[name="content"]' ).val();
content = $.trim( content );
if ( content ) {
components += ' ' + content + ' [/' + tagType + ']';
}
return components;
};
wpcf7.taggen.normalize = function( $input ) {
var val = $input.val();
if ( $input.is( 'input[name="name"]' ) ) {
val = val.replace( /[^0-9a-zA-Z:._-]/g, '' ).replace( /^[^a-zA-Z]+/, '' );
}
if ( $input.is( '.numeric' ) ) {
val = val.replace( /[^0-9.-]/g, '' );
}
if ( $input.is( '.idvalue' ) ) {
val = val.replace( /[^-0-9a-zA-Z_]/g, '' );
}
if ( $input.is( '.classvalue' ) ) {
val = $.map( val.split( ' ' ), function( n ) {
return n.replace( /[^-0-9a-zA-Z_]/g, '' );
} ).join( ' ' );
val = $.trim( val.replace( /\s+/g, ' ' ) );
}
if ( $input.is( '.color' ) ) {
val = val.replace( /[^0-9a-fA-F]/g, '' );
}
if ( $input.is( '.filesize' ) ) {
val = val.replace( /[^0-9kKmMbB]/g, '' );
}
if ( $input.is( '.filetype' ) ) {
val = val.replace( /[^0-9a-zA-Z.,|\s]/g, '' );
}
if ( $input.is( '.date' ) ) {
// 'yyyy-mm-dd' ISO 8601 format
if ( ! val.match( /^\d{4}-\d{2}-\d{2}$/ ) ) {
val = '';
}
}
if ( $input.is( ':input[name="values"]' ) ) {
val = $.trim( val );
}
$input.val( val );
if ( $input.is( ':checkbox.exclusive' ) ) {
wpcf7.taggen.exclusiveCheckbox( $input );
}
};
wpcf7.taggen.exclusiveCheckbox = function( $cb ) {
if ( $cb.is( ':checked' ) ) {
$cb.siblings( ':checkbox.exclusive' ).prop( 'checked', false );
}
};
wpcf7.taggen.insert = function( content ) {
$( 'textarea#wpcf7-form' ).each( function() {
this.focus();
if ( document.selection ) { // IE
var selection = document.selection.createRange();
selection.text = content;
} else if ( this.selectionEnd || 0 === this.selectionEnd ) {
var val = $( this ).val();
var end = this.selectionEnd;
$( this ).val( val.substring( 0, end ) +
content + val.substring( end, val.length ) );
this.selectionStart = end + content.length;
this.selectionEnd = end + content.length;
} else {
$( this ).val( $( this ).val() + content );
}
this.focus();
} );
};
} )( jQuery );

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,85 @@
<?php
add_action(
'init',
'wpcf7_init_block_editor_assets',
10, 0
);
function wpcf7_init_block_editor_assets() {
$assets = array();
$asset_file = wpcf7_plugin_path(
'includes/block-editor/index.asset.php'
);
if ( file_exists( $asset_file ) ) {
$assets = include( $asset_file );
}
$assets = wp_parse_args( $assets, array(
'dependencies' => array(
'wp-api-fetch',
'wp-block-editor',
'wp-blocks',
'wp-components',
'wp-element',
'wp-i18n',
'wp-url',
),
'version' => WPCF7_VERSION,
) );
wp_register_script(
'contact-form-7-block-editor',
wpcf7_plugin_url( 'includes/block-editor/index.js' ),
$assets['dependencies'],
$assets['version']
);
wp_set_script_translations(
'contact-form-7-block-editor',
'contact-form-7'
);
register_block_type(
wpcf7_plugin_path( 'includes/block-editor' ),
array(
'editor_script' => 'contact-form-7-block-editor',
)
);
}
add_action(
'enqueue_block_editor_assets',
'wpcf7_enqueue_block_editor_assets',
10, 0
);
function wpcf7_enqueue_block_editor_assets() {
$contact_forms = array_map(
static function ( $contact_form ) {
return array(
'id' => $contact_form->id(),
'slug' => $contact_form->name(),
'title' => $contact_form->title(),
'locale' => $contact_form->locale(),
);
},
WPCF7_ContactForm::find( array(
'posts_per_page' => 20,
'orderby' => 'modified',
'order' => 'DESC',
) )
);
wp_add_inline_script(
'contact-form-7-block-editor',
sprintf(
'window.wpcf7 = {contactForms:%s};',
json_encode( $contact_forms )
),
'before'
);
}

View File

@@ -0,0 +1,35 @@
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 2,
"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"
},
"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"
}

View File

@@ -0,0 +1,14 @@
<?php
return array(
'dependencies' => array(
'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,989 @@
<?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.6.1';
const error = 100;
const error_maybe_empty = 101;
const error_invalid_mailbox_syntax = 102;
const error_email_not_in_site_domain = 103;
const error_html_in_message = 104;
const error_multiple_controls_in_label = 105;
const error_file_not_found = 106;
const error_unavailable_names = 107;
const error_invalid_mail_header = 108;
const error_deprecated_settings = 109;
const error_file_not_in_content_dir = 110;
const error_unavailable_html_elements = 111;
const error_attachments_overweight = 112;
const error_dots_in_names = 113;
const error_colons_in_names = 114;
const error_upload_filesize_overlimit = 115;
/**
* Returns a URL linking to the documentation page for the error type.
*/
public static function get_doc_link( $error_code = '' ) {
$url = __( 'https://contactform7.com/configuration-errors/',
'contact-form-7'
);
if ( '' !== $error_code ) {
$error_code = strtr( $error_code, '_', '-' );
$url = sprintf( '%s/%s', untrailingslashit( $url ), $error_code );
}
return esc_url( $url );
}
private $contact_form;
private $errors = array();
public function __construct( WPCF7_ContactForm $contact_form ) {
$this->contact_form = $contact_form;
}
/**
* 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();
}
/**
* Counts detected errors.
*/
public function count_errors( $args = '' ) {
$args = wp_parse_args( $args, 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 ( $args['section']
and $key != $args['section']
and preg_replace( '/\..*$/', '', $key, 1 ) != $args['section'] ) {
continue;
}
foreach ( $errors as $error ) {
if ( empty( $error ) ) {
continue;
}
if ( $args['code'] and $error['code'] != $args['code'] ) {
continue;
}
$count += 1;
}
}
return $count;
}
/**
* Collects messages for detected errors.
*/
public function collect_error_messages() {
$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'] );
}
$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 ) {
switch ( $code ) {
case self::error_maybe_empty:
return __( "There is a possible empty field.", 'contact-form-7' );
case self::error_invalid_mailbox_syntax:
return __( "Invalid mailbox syntax is used.", 'contact-form-7' );
case self::error_email_not_in_site_domain:
return __( "Sender email address does not belong to the site domain.", 'contact-form-7' );
case self::error_html_in_message:
return __( "HTML tags are used in a message.", 'contact-form-7' );
case self::error_multiple_controls_in_label:
return __( "Multiple form controls are in a single label element.", 'contact-form-7' );
case self::error_invalid_mail_header:
return __( "There are invalid mail header fields.", 'contact-form-7' );
case self::error_deprecated_settings:
return __( "Deprecated settings are used.", 'contact-form-7' );
default:
return '';
}
}
/**
* Adds a validation error.
*
* @param string $section The section where the error detected.
* @param int $code The unique code of the error.
* This must be one of the class constants.
* @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(),
) );
if ( ! isset( $this->errors[$section] ) ) {
$this->errors[$section] = array();
}
$this->errors[$section][] = array( 'code' => $code, 'args' => $args );
return true;
}
/**
* Removes an 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->errors = array();
$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_errors' );
if ( $this->errors ) {
update_post_meta(
$this->contact_form->id(), '_config_errors', $this->errors
);
}
}
/**
* Restore errors from the database.
*/
public function restore() {
$config_errors = get_post_meta(
$this->contact_form->id(), '_config_errors', true
);
foreach ( (array) $config_errors as $section => $errors ) {
if ( empty( $errors ) ) {
continue;
}
if ( ! is_array( $errors ) ) { // for back-compat
$code = $errors;
$this->add_error( $section, $code );
} else {
foreach ( (array) $errors as $error ) {
if ( ! empty( $error['code'] ) ) {
$code = $error['code'];
$args = isset( $error['args'] ) ? $error['args'] : '';
$this->add_error( $section, $code, $args );
}
}
}
}
}
/**
* Callback function for WPCF7_MailTaggedText. Replaces mail-tags with
* the most conservative inputs.
*/
public function replace_mail_tags_with_minimum_input( $matches ) {
// allow [[foo]] syntax for escaping a tag
if ( $matches[1] == '[' && $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 = '';
$form_tags = $this->contact_form->scan_form_tags(
array( 'name' => $field_name )
);
if ( $form_tags ) {
$form_tag = new WPCF7_FormTag( $form_tags[0] );
$is_required = ( $form_tag->is_required() || 'radio' == $form_tag->type );
if ( ! $is_required ) {
return $example_blank;
}
if ( wpcf7_form_tag_supports( $form_tag->type, 'selectable-values' ) ) {
if ( $form_tag->pipes instanceof WPCF7_Pipes ) {
if ( $mail_tag->get_option( 'do_not_heat' ) ) {
$before_pipes = $form_tag->pipes->collect_befores();
$last_item = array_pop( $before_pipes );
} else {
$after_pipes = $form_tag->pipes->collect_afters();
$last_item = array_pop( $after_pipes );
}
} else {
$last_item = array_pop( $form_tag->values );
}
if ( $last_item and wpcf7_is_mailbox_list( $last_item ) ) {
return $example_email;
} else {
return $example_text;
}
}
if ( 'email' == $form_tag->basetype ) {
return $example_email;
} else {
return $example_text;
}
} else { // maybe special mail tag
// 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 ( '_user_' == substr( $field_name, 0, 6 ) ) {
return $this->contact_form->is_true( 'subscribers_only' )
? $example_text
: $example_blank;
} elseif ( '_' == substr( $field_name, 0, 1 ) ) {
return '_email' == substr( $field_name, -6 )
? $example_email
: $example_text;
}
}
return $tag;
}
/**
* Runs error detection for the form section.
*/
public function validate_form() {
$section = 'form.body';
$form = $this->contact_form->prop( 'form' );
$this->detect_multiple_controls_in_label( $section, $form );
$this->detect_unavailable_names( $section, $form );
$this->detect_unavailable_html_elements( $section, $form );
$this->detect_dots_in_names( $section, $form );
$this->detect_colons_in_names( $section, $form );
$this->detect_upload_filesize_overlimit( $section, $form );
}
/**
* 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 $this->add_error( $section,
self::error_multiple_controls_in_label, array(
'link' => self::get_doc_link( 'multiple_controls_in_label' ),
)
);
}
}
}
}
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 ) {
$ng_names = array_unique( $ng_names );
return $this->add_error( $section,
self::error_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 ) ),
'link' => self::get_doc_link( 'unavailable_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 $this->add_error( $section,
self::error_unavailable_html_elements,
array(
'message' => __( "Unavailable HTML elements are used in the form template.", 'contact-form-7' ),
'link' => self::get_doc_link( 'unavailable_html_elements' ),
)
);
}
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 ( false !== strpos( $tag->raw_name, '.' ) ) {
return $this->add_error( $section,
self::error_dots_in_names,
array(
'message' => __( "Dots are used in form-tag names.", 'contact-form-7' ),
'link' => self::get_doc_link( 'dots_in_names' ),
)
);
}
}
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 ( false !== strpos( $tag->raw_name, ':' ) ) {
return $this->add_error( $section,
self::error_colons_in_names,
array(
'message' => __( "Colons are used in form-tag names.", 'contact-form-7' ),
'link' => self::get_doc_link( 'colons_in_names' ),
)
);
}
}
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 $this->add_error( $section,
self::error_upload_filesize_overlimit,
array(
'message' => __( "Uploadable file size exceeds PHPs maximum acceptable size.", 'contact-form-7' ),
'link' => self::get_doc_link( 'upload_filesize_overlimit' ),
)
);
}
}
return false;
}
/**
* 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' => '',
) );
$callback = array( $this, 'replace_mail_tags_with_minimum_input' );
$subject = new WPCF7_MailTaggedText(
$components['subject'],
array( 'callback' => $callback )
);
$subject = $subject->replace_tags();
$subject = wpcf7_strip_newline( $subject );
$this->detect_maybe_empty( sprintf( '%s.subject', $template ), $subject );
$sender = new WPCF7_MailTaggedText(
$components['sender'],
array( 'callback' => $callback )
);
$sender = $sender->replace_tags();
$sender = wpcf7_strip_newline( $sender );
$invalid_mailbox = $this->detect_invalid_mailbox_syntax(
sprintf( '%s.sender', $template ),
$sender
);
if ( ! $invalid_mailbox and ! wpcf7_is_email_in_site_domain( $sender ) ) {
$this->add_error( sprintf( '%s.sender', $template ),
self::error_email_not_in_site_domain, array(
'link' => self::get_doc_link( 'email_not_in_site_domain' ),
)
);
}
$recipient = new WPCF7_MailTaggedText(
$components['recipient'],
array( 'callback' => $callback )
);
$recipient = $recipient->replace_tags();
$recipient = wpcf7_strip_newline( $recipient );
$this->detect_invalid_mailbox_syntax(
sprintf( '%s.recipient', $template ),
$recipient
);
$additional_headers = new WPCF7_MailTaggedText(
$components['additional_headers'],
array( 'callback' => $callback )
);
$additional_headers = $additional_headers->replace_tags();
$additional_headers = explode( "\n", $additional_headers );
$mailbox_header_types = array( 'reply-to', 'cc', 'bcc' );
$invalid_mail_header_exists = false;
foreach ( $additional_headers as $header ) {
$header = trim( $header );
if ( '' === $header ) {
continue;
}
if ( ! preg_match( '/^([0-9A-Za-z-]+):(.*)$/', $header, $matches ) ) {
$invalid_mail_header_exists = true;
} else {
$header_name = $matches[1];
$header_value = trim( $matches[2] );
if ( in_array( strtolower( $header_name ), $mailbox_header_types )
and '' !== $header_value ) {
$this->detect_invalid_mailbox_syntax(
sprintf( '%s.additional_headers', $template ),
$header_value,
array(
'message' =>
__( "Invalid mailbox syntax is used in the %name% field.", 'contact-form-7' ),
'params' => array( 'name' => $header_name )
)
);
}
}
}
if ( $invalid_mail_header_exists ) {
$this->add_error( sprintf( '%s.additional_headers', $template ),
self::error_invalid_mail_header, array(
'link' => self::get_doc_link( 'invalid_mail_header' ),
)
);
}
$body = new WPCF7_MailTaggedText(
$components['body'],
array( 'callback' => $callback )
);
$body = $body->replace_tags();
$this->detect_maybe_empty( sprintf( '%s.body', $template ), $body );
if ( '' !== $components['attachments'] ) {
$attachables = array();
$tags = $this->contact_form->scan_form_tags(
array( 'type' => array( 'file', 'file*' ) )
);
foreach ( $tags as $tag ) {
$name = $tag->name;
if ( false === strpos( $components['attachments'], "[{$name}]" ) ) {
continue;
}
$limit = (int) $tag->get_limit_option();
if ( empty( $attachables[$name] )
or $attachables[$name] < $limit ) {
$attachables[$name] = $limit;
}
}
$total_size = array_sum( $attachables );
$has_file_not_found = false;
$has_file_not_in_content_dir = false;
foreach ( explode( "\n", $components['attachments'] ) as $line ) {
$line = trim( $line );
if ( '' === $line or '[' == substr( $line, 0, 1 ) ) {
continue;
}
$has_file_not_found = $this->detect_file_not_found(
sprintf( '%s.attachments', $template ), $line
);
if ( ! $has_file_not_found and ! $has_file_not_in_content_dir ) {
$has_file_not_in_content_dir = $this->detect_file_not_in_content_dir(
sprintf( '%s.attachments', $template ), $line
);
}
if ( ! $has_file_not_found ) {
$path = path_join( WP_CONTENT_DIR, $line );
$total_size += (int) @filesize( $path );
}
}
$max = 25 * MB_IN_BYTES; // 25 MB
if ( $max < $total_size ) {
$this->add_error( sprintf( '%s.attachments', $template ),
self::error_attachments_overweight,
array(
'message' => __( "The total size of attachment files is too large.", 'contact-form-7' ),
'link' => self::get_doc_link( '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, $args = '' ) {
$args = wp_parse_args( $args, array(
'link' => self::get_doc_link( 'invalid_mailbox_syntax' ),
'message' => '',
'params' => array(),
) );
if ( ! wpcf7_is_mailbox_list( $content ) ) {
return $this->add_error( $section,
self::error_invalid_mailbox_syntax, $args
);
}
return false;
}
/**
* Detects errors of empty message fields.
*
* @link https://contactform7.com/configuration-errors/maybe-empty/
*/
public function detect_maybe_empty( $section, $content ) {
if ( '' === $content ) {
return $this->add_error( $section,
self::error_maybe_empty, array(
'link' => self::get_doc_link( 'maybe_empty' ),
)
);
}
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 $this->add_error( $section,
self::error_file_not_found,
array(
'message' =>
__( "Attachment file does not exist at %path%.", 'contact-form-7' ),
'params' => array( 'path' => $content ),
'link' => self::get_doc_link( 'file_not_found' ),
)
);
}
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 $this->add_error( $section,
self::error_file_not_in_content_dir,
array(
'message' =>
__( "It is not allowed to use files outside the wp-content directory.", 'contact-form-7' ),
'link' => self::get_doc_link( 'file_not_in_content_dir' ),
)
);
}
return false;
}
/**
* 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 );
$this->detect_html_in_message( $section, $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 $this->add_error( $section,
self::error_html_in_message,
array(
'link' => self::get_doc_link( 'html_in_message' ),
)
);
}
return false;
}
/**
* Runs error detection for the additional settings section.
*/
public function validate_additional_settings() {
$deprecated_settings_used =
$this->contact_form->additional_setting( 'on_sent_ok' ) ||
$this->contact_form->additional_setting( 'on_submit' );
if ( $deprecated_settings_used ) {
return $this->add_error( 'additional_settings.body',
self::error_deprecated_settings,
array(
'link' => self::get_doc_link( 'deprecated_settings' ),
)
);
}
}
}

View File

@@ -0,0 +1,417 @@
<?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 ) {
global $wpdb;
$q = "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = '_old_cf7_unit_id'"
. $wpdb->prepare( " AND meta_value = %d", $old_id );
if ( $new_id = $wpdb->get_var( $q ) ) {
return wpcf7_contact_form( $new_id );
}
}
/**
* 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( reset( $contact_forms ) );
}
}
/**
* 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 isset( $_POST[$name] ) ? wp_unslash( $_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 );
$default_classes = array_filter( explode( ' ', $default_classes ) );
$classes = array_merge( array( 'wpcf7-form-control' ), $default_classes );
$typebase = rtrim( $type, '*' );
$required = ( '*' == substr( $type, -1 ) );
$classes[] = 'wpcf7-' . $typebase;
if ( $required ) {
$classes[] = 'wpcf7-validates-as-required';
}
$classes = 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' => 0,
'title' => '',
'html_id' => '',
'html_name' => '',
'html_title' => '',
'html_class' => '',
'output' => 'form',
),
$atts, 'wpcf7'
);
$id = (int) $atts['id'];
$title = trim( $atts['title'] );
if ( ! $contact_form = wpcf7_contact_form( $id ) ) {
$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 );
};
return wpcf7_switch_locale(
$contact_form->locale(),
$callback,
$contact_form, $atts
);
}
/**
* Saves the contact form data.
*/
function wpcf7_save_contact_form( $args = '', $context = 'save' ) {
$args = wp_parse_args( $args, array(
'id' => -1,
'title' => null,
'locale' => null,
'form' => null,
'mail' => null,
'mail_2' => null,
'messages' => null,
'additional_settings' => null,
) );
$args = wp_unslash( $args );
$args['id'] = (int) $args['id'];
if ( -1 == $args['id'] ) {
$contact_form = WPCF7_ContactForm::get_template();
} else {
$contact_form = wpcf7_contact_form( $args['id'] );
}
if ( empty( $contact_form ) ) {
return false;
}
if ( null !== $args['title'] ) {
$contact_form->set_title( $args['title'] );
}
if ( null !== $args['locale'] ) {
$contact_form->set_locale( $args['locale'] );
}
$properties = array();
if ( null !== $args['form'] ) {
$properties['form'] = wpcf7_sanitize_form( $args['form'] );
}
if ( null !== $args['mail'] ) {
$properties['mail'] = wpcf7_sanitize_mail( $args['mail'] );
$properties['mail']['active'] = true;
}
if ( null !== $args['mail_2'] ) {
$properties['mail_2'] = wpcf7_sanitize_mail( $args['mail_2'] );
}
if ( null !== $args['messages'] ) {
$properties['messages'] = wpcf7_sanitize_messages( $args['messages'] );
}
if ( null !== $args['additional_settings'] ) {
$properties['additional_settings'] = wpcf7_sanitize_additional_settings(
$args['additional_settings']
);
}
$contact_form->set_properties( $properties );
do_action( 'wpcf7_save_contact_form', $contact_form, $args, $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;
}

View File

@@ -0,0 +1,220 @@
<?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 e-mail was sent from a contact form on %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 e-mail was sent from a contact form on %1$s (%2$s)', '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'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'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,180 @@
<?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 ( isset( $_POST['_wpcf7'] ) ) {
$contact_form = wpcf7_contact_form( (int) $_POST['_wpcf7'] );
if ( $contact_form ) {
$contact_form->submit();
}
}
}
/**
* Registers main scripts and styles.
*/
add_action(
'wp_enqueue_scripts',
static function () {
$assets = array();
$asset_file = wpcf7_plugin_path( 'includes/js/index.asset.php' );
if ( file_exists( $asset_file ) ) {
$assets = include( $asset_file );
}
$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'],
true
);
wp_register_script(
'contact-form-7-html5-fallback',
wpcf7_plugin_url( 'includes/js/html5-fallback.js' ),
array( 'jquery-ui-datepicker' ),
WPCF7_VERSION,
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 = array(
'api' => array(
'root' => sanitize_url( get_rest_url() ),
'namespace' => 'contact-form-7/v1',
),
);
if ( defined( 'WP_CACHE' ) and WP_CACHE ) {
$wpcf7['cached'] = 1;
}
wp_localize_script( 'contact-form-7', 'wpcf7', $wpcf7 );
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,168 @@
.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 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 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,424 @@
<?php
/**
* Validates uploaded files and moves them to the temporary directory.
*
* @param array $file An item of `$_FILES`.
* @param string|array $args Optional. Arguments to control behavior.
* @return array|WP_Error Array of file paths, or WP_Error if validation fails.
*/
function wpcf7_unship_uploaded_file( $file, $args = '' ) {
$args = wp_parse_args( $args, 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( $args['schema'] ) and isset( $args['name'] ) ) {
$result = $args['schema']->validate( array(
'file' => true,
'field' => $args['name'],
) );
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, $args
);
$filename = wp_unique_filename( $uploads_dir, $filename );
$new_file = path_join( $uploads_dir, $filename );
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
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' ) ) ) {
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 ) and is_writable( $dir ) ) {
$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;
}
}
if ( $handle = @fopen( $htaccess_file, 'w' ) ) {
fwrite( $handle, "# Apache 2.4+\n" );
fwrite( $handle, "<IfModule authz_core_module>\n" );
fwrite( $handle, " Require all denied\n" );
fwrite( $handle, "</IfModule>\n" );
fwrite( $handle, "\n" );
fwrite( $handle, "# Apache 2.2\n" );
fwrite( $handle, "<IfModule !authz_core_module>\n" );
fwrite( $handle, " Deny from all\n" );
fwrite( $handle, "</IfModule>\n" );
fclose( $handle );
}
}
}
/**
* 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 {
$rand_max = mt_getrandmax();
$rand = zeroise( mt_rand( 0, $rand_max ), strlen( $rand_max ) );
$dir_new = path_join( $dir, $rand );
} 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() {
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 $dir;
}
}
$dir = path_join( wpcf7_upload_dir( 'dir' ), 'wpcf7_uploads' );
wp_mkdir_p( $dir );
return $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 ) ) {
$message = 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
);
echo sprintf(
'<div class="notice notice-warning"><p>%s</p></div>',
esc_html( $message )
);
}
}

View File

@@ -0,0 +1,565 @@
<?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 ( '*' === substr( $this->type, -1 ) );
}
/**
* 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() {
return $this->get_option( 'id', 'id', true );
}
/**
* 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', 'class' )
);
$options = array_filter( array_unique( $options ) );
if ( empty( $options ) ) {
return false;
}
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 ( (array) $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 ( (array) $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 ( (array) $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 ( (array) $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 ) ? $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 isset( $_GET[$this->name] ) ) {
$vals = (array) $_GET[$this->name];
$vals = array_map( 'wpcf7_sanitize_query_var', $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 isset( $_POST[$this->name] ) ) {
$vals = (array) $_POST[$this->name];
$vals = array_map( 'wpcf7_sanitize_query_var', $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 ( 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,590 @@
<?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 && $this->tag_type_supports( $tag_type, $features )
|| $invert && ! $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() . '/s',
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,
sha1( $tag )
);
list( $placeholder ) =
WPCF7_HTMLFormatter::normalize_start_tag( $placeholder );
$this->placeholders[$placeholder] = $tag;
return $placeholder;
};
return preg_replace_callback(
'/' . $this->tag_regex() . '/s',
$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() . '/s',
array( $this, 'replace_callback' ),
$content
);
return $content;
} else {
preg_replace_callback(
'/' . $this->tag_regex() . '/s',
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 ( '!' === substr( $feature, 0, 1 ) ) { // 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() {
$tagnames = array_keys( $this->tag_types );
$tagregexp = implode( '|', array_map( 'preg_quote', $tagnames ) );
return '(\[?)'
. '\[(' . $tagregexp . ')(?:[\r\n\t ](.*?))?(?:[\r\n\t ](\/))?\]'
. '(?:([^[]*?)\[\/\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() );
$text = preg_replace( "/[\x{00a0}\x{200b}]+/u", " ", $text );
$text = trim( $text );
$pattern = '%^([-+*=0-9a-zA-Z:.!?#$&@_/|\%\r\n\t ]*?)((?:[\r\n\t ]*"[^"]*"|[\r\n\t ]*\'[^\']*\')*)$%';
if ( preg_match( $pattern, $text, $matches ) ) {
if ( ! empty( $matches[1] ) ) {
$atts['options'] = preg_split( '/[\r\n\t ]+/', trim( $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,552 @@
<?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,
sha1( $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,
) );
$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 = trim( $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 ) ) {
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 trim( $text );
}
/**
* Canonicalizes text.
*
* @param string $text Input text.
* @param string|array|object $args Options.
* @return string Canonicalized text.
*/
function wpcf7_canonicalize( $text, $args = '' ) {
// for back-compat
if ( is_string( $args ) and '' !== $args
and false === strpos( $args, '=' ) ) {
$args = array(
'strto' => $args,
);
}
$args = wp_parse_args( $args, 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' )
);
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 ( $args['strip_separators'] ) {
$text = preg_replace( '/[\r\n\t ]+/', '', $text );
} else {
$text = preg_replace( '/[\r\n\t ]+/', ' ', $text );
}
if ( 'lower' == $args['strto'] ) {
if ( function_exists( 'mb_strtolower' ) ) {
$text = mb_strtolower( $text, $charset );
} else {
$text = strtolower( $text );
}
} elseif ( 'upper' == $args['strto'] ) {
if ( function_exists( 'mb_strtoupper' ) ) {
$text = mb_strtoupper( $text, $charset );
} else {
$text = strtoupper( $text );
}
}
$text = trim( $text );
return $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_-]/', '', $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 );
$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 ( (array) $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,
'capture' => true,
'checked' => true,
'disabled' => true,
'list' => true,
'max' => true,
'maxlength' => true,
'min' => true,
'minlength' => true,
'multiple' => true,
'name' => true,
'placeholder' => true,
'readonly' => 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(
'disabled' => true,
'multiple' => true,
'name' => true,
'size' => true,
),
'textarea' => array(
'cols' => true,
'disabled' => true,
'maxlength' => true,
'minlength' => true,
'name' => true,
'placeholder' => true,
'readonly' => true,
'rows' => true,
'spellcheck' => true,
'wrap' => true,
),
);
$additional_tags_for_form = array_map(
static function ( $elm ) {
$global_attributes = array(
'aria-atomic' => true,
'aria-checked' => true,
'aria-describedby' => true,
'aria-details' => true,
'aria-disabled' => 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,
'id' => true,
'inputmode' => true,
'role' => true,
'style' => true,
'tabindex' => true,
'title' => true,
);
return array_merge( $global_attributes, (array) $elm );
},
$additional_tags_for_form
);
$allowed_tags[$context] = array_merge(
$allowed_tags[$context],
$additional_tags_for_form
);
}
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', 'multiple', 'readonly', 'required', 'selected',
);
if ( in_array( $name, $boolean_attributes ) 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 );
}

View File

@@ -0,0 +1,690 @@
<?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 $args Optional. Output options.
* @return string Comma-separated list.
*/
function wpcf7_flat_join( $input, $args = '' ) {
$args = wp_parse_args( $args, array(
'separator' => ', ',
) );
$input = wpcf7_array_flatten( $input );
$output = array();
foreach ( (array) $input as $value ) {
if ( is_scalar( $value ) ) {
$output[] = trim( (string) $value );
}
}
return implode( $args['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 to form content.
*/
function wpcf7_autop_or_not() {
return (bool) apply_filters( 'wpcf7_autop_or_not', WPCF7_AUTOP );
}
/**
* 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 $args Optional. Link options.
* @return string Formatted anchor element.
*/
function wpcf7_link( $url, $anchor_text, $args = '' ) {
$args = wp_parse_args( $args, array(
'id' => null,
'class' => null,
) );
$atts = array_merge( $args, 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() );
}
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 $args Optional. Output options.
* @return string Version string.
*/
function wpcf7_version( $args = '' ) {
$defaults = array(
'limit' => -1,
'only_major' => false,
);
$args = wp_parse_args( $args, $defaults );
if ( $args['only_major'] ) {
$args['limit'] = 2;
}
$args['limit'] = (int) $args['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 < $args['limit'] ) {
$ver = array_slice( $ver, 0, $args['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 ) ) {
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 ) {
if ( is_file( $dir ) ) {
$file = $dir;
if ( @unlink( $file ) ) {
return true;
}
$stat = stat( $file );
if ( @chmod( $file, $stat['mode'] | 0200 ) ) { // add write for owner
if ( @unlink( $file ) ) {
return true;
}
@chmod( $file, $stat['mode'] );
}
return false;
}
if ( ! is_dir( $dir ) ) {
return false;
}
if ( $handle = opendir( $dir ) ) {
while ( false !== ( $file = readdir( $handle ) ) ) {
if ( $file == "."
or $file == ".." ) {
continue;
}
wpcf7_rmdir_p( path_join( $dir, $file ) );
}
closedir( $handle );
}
if ( false !== ( $files = scandir( $dir ) )
and ! array_diff( $files, array( '.', '..' ) ) ) {
return rmdir( $dir );
}
return false;
}
/**
* Builds a URL-encoded query string.
*
* @link https://developer.wordpress.org/reference/functions/_http_build_query/
*
* @param array $args URL query parameters.
* @param string $key Optional. If specified, used to prefix key name.
* @return string Query string.
*/
function wpcf7_build_query( $args, $key = '' ) {
$sep = '&';
$ret = array();
foreach ( (array) $args 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|bool 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;
$text = str_replace( "\r\n", "\n", $text );
$encoding = mb_detect_encoding( $text, mb_detect_order(), true );
if ( $encoding ) {
$text = mb_convert_encoding( $text, 'UTF-16', $encoding );
} else {
$text = mb_convert_encoding( $text, 'UTF-16', 'UTF-8' );
}
$byte_count = mb_strlen( $text, '8bit' );
return floor( $byte_count / 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' ) );
}
/**
* 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 ) {
if ( function_exists( '__' ) ) {
trigger_error(
sprintf(
/* translators: 1: PHP function name, 2: version number, 3: alternative function name */
__( 'Function %1$s is <strong>deprecated</strong> since Contact Form 7 version %2$s! Use %3$s instead.', 'contact-form-7' ),
$function_name, $version, $replacement
),
E_USER_DEPRECATED
);
} else {
trigger_error(
sprintf(
'Function %1$s is <strong>deprecated</strong> since Contact Form 7 version %2$s! Use %3$s instead.',
$function_name, $version, $replacement
),
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 ) {
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 {
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 ) {
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
);
}
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
);
}
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 ) {
$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 ) {
trigger_error( $log );
}
}
/**
* 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 ) );
}

View File

@@ -0,0 +1,678 @@
<?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 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( $args = '' ) {
$this->options = wp_parse_args( $args, array(
'auto_br' => true,
'auto_indent' => true,
) );
}
/**
* 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 ( $chunk['type'] === self::start_tag ) {
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 ( $chunk['type'] === self::text ) {
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 ( $chunk['type'] === self::text ) {
$this->append_text( $chunk['content'] );
}
if ( $chunk['type'] === self::start_tag ) {
$this->start_tag( $chunk['content'] );
}
if ( $chunk['type'] === self::end_tag ) {
$this->end_tag( $chunk['content'] );
}
if ( $chunk['type'] === self::comment ) {
$this->append_comment( $chunk['content'] );
}
}
// Close all remaining tags.
$this->close_all_tags();
return $this->output;
}
/**
* 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->output .= $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 '' !== trim( $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->output .= $paragraph;
}
foreach ( $paragraphs as $paragraph ) {
$this->start_tag( 'p' );
$paragraph = ltrim( $paragraph );
$paragraph = self::normalize_paragraph(
$paragraph,
$this->options['auto_br']
);
$this->output .= $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->output .= $content;
}
} else {
$auto_br = $this->options['auto_br'] &&
$this->has_parent( self::br_parent_elements );
$content = self::normalize_paragraph( $content, $auto_br );
$this->output .= $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 ) ) {
if (
! $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' );
}
} elseif (
'p' === $tag_name or
in_array( $tag_name, self::p_parent_elements ) or
in_array( $tag_name, self::p_nonparent_elements )
) {
// 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 ( ! in_array( $tag_name, self::void_elements ) ) {
array_unshift( $this->stacked_elements, $tag_name );
}
if ( ! in_array( $tag_name, self::p_child_elements ) ) {
if ( '' !== $this->output ) {
$this->output = rtrim( $this->output ) . "\n";
}
if ( $this->options['auto_indent'] ) {
$this->output .= self::indent( count( $this->stacked_elements ) - 1 );
}
}
$this->output .= $tag;
}
/**
* 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 );
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 ) ) {
$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;
}
}
}
/**
* Closes all open tags.
*/
public function close_all_tags() {
while ( $element = array_shift( $this->stacked_elements ) ) {
$this->append_end_tag( $element );
}
}
/**
* 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 ) ) {
// Remove unnecessary <br />.
$this->output = preg_replace( '/\s*<br \/>\s*$/', '', $this->output );
$this->output = rtrim( $this->output ) . "\n";
if ( $this->options['auto_indent'] ) {
$this->output .= self::indent( count( $this->stacked_elements ) );
}
}
$this->output .= sprintf( '</%s>', $tag_name );
// Remove trailing <p></p>.
$this->output = preg_replace( '/<p>\s*<\/p>$/', '', $this->output );
}
/**
* Appends an HTML comment to the output property.
*
* @param string $tag An HTML comment.
*/
public function append_comment( $tag ) {
$this->output .= $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 ) ) {
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 );
}
/**
* 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 ) ) {
// 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;
}
}

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 ) ); ?>
</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 = isset( $_GET['code'] ) ? $_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,6 @@
<?php
return array(
'dependencies' => array(),
'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,661 @@
<?php
/**
* 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 $use_html = false;
private $exclude_blank = false;
/**
* Returns the singleton instance of this class.
*/
public static function get_current() {
return self::$current;
}
/**
* 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;
}
/**
* 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 ) {
$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 );
}
}
}
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 );
$footer = apply_filters( 'wpcf7_mail_html_footer',
'</body>
</html>', $this );
$html = $header . wpcf7_autop( $body ) . $footer;
return $html;
}
/**
* 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 ) ) {
if ( WP_DEBUG ) {
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 ) ) {
if ( WP_DEBUG ) {
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 ) {
if ( WP_DEBUG ) {
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, $args = '' ) {
if ( true === $args ) {
$args = array( 'html' => true );
}
$args = wp_parse_args( $args, array(
'html' => false,
'exclude_blank' => false,
) );
return wpcf7_mail_replace_tags( $content, $args );
}
/**
* 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 $args Optional. Output options.
* @return string Result of replacement.
*/
function wpcf7_mail_replace_tags( $content, $args = '' ) {
$args = wp_parse_args( $args, array(
'html' => false,
'exclude_blank' => false,
) );
if ( is_array( $content ) ) {
foreach ( $content as $key => $value ) {
$content[$key] = wpcf7_mail_replace_tags( $value, $args );
}
return $content;
}
$content = explode( "\n", $content );
foreach ( $content as $num => $line ) {
$line = new WPCF7_MailTaggedText( $line, $args );
$replaced = $line->replace_tags();
if ( $args['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, $args = '' ) {
$args = wp_parse_args( $args, array(
'html' => false,
'callback' => null,
) );
$this->html = (bool) $args['html'];
if ( null !== $args['callback']
and is_callable( $args['callback'] ) ) {
$this->callback = $args['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 = isset( $_POST[$field_name] )
? wp_unslash( $_POST[$field_name] )
: '';
}
$replaced = $submitted;
if ( null !== $replaced ) {
if ( $format = $mail_tag->get_option( 'format' ) ) {
$replaced = $this->format( $replaced, $format );
}
$replaced = wpcf7_flat_join( $replaced, array(
'separator' => wp_get_list_item_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;
}
}
/**
* 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;
}
}

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