| @@ -2,8 +2,10 @@ | ||
| 2 | 2 | |
| 3 | 3 | namespace forge12\contactform7\CF7DoubleOptIn { |
| 4 | 4 | |
| 5 | 5 | use forge12\plugins\ContactForm7; |
| 6 | + use Forge12\Shared\LoggerInterface; | |
| 7 | + use Forge12\DoubleOptIn\EmailTemplates\PlaceholderMapper; | |
| 6 | 8 | |
| 7 | 9 | if ( ! defined( 'ABSPATH' ) ) { |
| 8 | 10 | exit; |
| 9 | 11 | } |
| @@ -12,57 +14,163 @@ | ||
| 12 | 14 | * Class Backend |
| 13 | 15 | * Responsible to handle the admin settings for the double opt-in field |
| 14 | 16 | * |
| 15 | 17 | * @package forge12\contactform7\CF7OptIn |
| 18 | + * | |
| 19 | + * @deprecated 4.0.0 Use \Forge12\DoubleOptIn\Integration\CF7Integration instead. | |
| 20 | + * This class is maintained for backward compatibility only. | |
| 21 | + * @see \Forge12\DoubleOptIn\Integration\CF7Integration | |
| 22 | + * @see \Forge12\DoubleOptIn\Integration\AdminPanelInterface | |
| 16 | 23 | */ |
| 17 | 24 | class CF7Backend { |
| 25 | + private LoggerInterface $logger; | |
| 26 | + | |
| 18 | 27 | /** |
| 19 | 28 | * Admin constructor. |
| 20 | 29 | */ |
| 21 | - public function __construct() { | |
| 22 | - add_action( 'admin_init', array( $this, 'addHooks' ) ); | |
| 23 | - add_action( 'admin_enqueue_scripts', array( $this, 'addStyles' ) ); | |
| 30 | + public function __construct( LoggerInterface $logger ) { | |
| 31 | + $this->logger = $logger; | |
| 32 | + | |
| 33 | + $this->get_logger()->debug( 'Admin constructor called', [ | |
| 34 | + 'plugin' => 'double-opt-in', | |
| 35 | + 'class' => __CLASS__, | |
| 36 | + 'method' => __METHOD__, | |
| 37 | + ] ); | |
| 38 | + | |
| 39 | + add_action( 'admin_init', [ $this, 'addHooks' ] ); | |
| 40 | + $this->get_logger()->debug( 'Hook admin_init registered', [ | |
| 41 | + 'plugin' => 'double-opt-in', | |
| 42 | + ] ); | |
| 43 | + | |
| 44 | + add_action( 'admin_enqueue_scripts', [ $this, 'addStyles' ] ); | |
| 45 | + $this->get_logger()->debug( 'Hook admin_enqueue_scripts registered', [ | |
| 46 | + 'plugin' => 'double-opt-in', | |
| 47 | + ] ); | |
| 24 | 48 | } |
| 25 | 49 | |
| 50 | + | |
| 51 | + public function get_logger() { | |
| 52 | + return $this->logger; | |
| 53 | + } | |
| 54 | + | |
| 26 | 55 | /** |
| 27 | 56 | * Add the styles for the form |
| 28 | 57 | */ |
| 29 | 58 | public function addStyles( $hook ) { |
| 30 | - wp_enqueue_script( 'f12-cf7-doubleoptin-admin', plugins_url( 'assets/f12-cf7-popup.js', __FILE__ ), array( 'jquery' ) ); | |
| 31 | - wp_localize_script( 'f12-cf7-doubleoptin-admin', 'doi', array( | |
| 32 | - 'ajax_url' => admin_url( 'admin-ajax.php' ), | |
| 33 | - 'nonce' => wp_create_nonce( 'f12_doi_details' ) | |
| 34 | - ) ); | |
| 59 | + // Only load the DOI admin scripts — and their privileged | |
| 60 | + // `f12_doi_details` nonce — on the screens that actually use them | |
| 61 | + // (Contact Form 7's admin/editor and the DOI admin), NOT on every | |
| 62 | + // wp-admin page. Broadcasting the nonce everywhere let a | |
| 63 | + // low-privilege user scrape it from e.g. profile.php. | |
| 64 | + $hook = (string) $hook; | |
| 65 | + $onPluginScreen = ( strpos( $hook, 'wpcf7' ) !== false ) | |
| 66 | + || ( strpos( $hook, 'f12-doi' ) !== false ) | |
| 67 | + || ( strpos( $hook, 'f12-cf7-doubleoptin' ) !== false ); | |
| 68 | + if ( ! $onPluginScreen ) { | |
| 69 | + return; | |
| 70 | + } | |
| 35 | 71 | |
| 36 | - wp_enqueue_script( 'f12-cf7-doubleoptin-templateloader', plugins_url( 'assets/f12-cf7-templateloader.js', __FILE__ ), array( 'jquery' ) ); | |
| 37 | - wp_localize_script( 'f12-cf7-doubleoptin-templateloader', 'templateloader', array( | |
| 38 | - 'ajax_url' => admin_url( 'admin-ajax.php' ), | |
| 39 | - 'nonce' => wp_create_nonce( 'f12_doi_templateloader' ), | |
| 40 | - 'label_placeholder' => __( 'Please wait while we load the template...', 'double-opt-in' ) | |
| 41 | - ) ); | |
| 72 | + $this->get_logger()->debug( 'Enqueuing admin styles and scripts', [ | |
| 73 | + 'plugin' => 'double-opt-in', | |
| 74 | + 'class' => __CLASS__, | |
| 75 | + 'method' => __METHOD__, | |
| 76 | + 'hook' => $hook, | |
| 77 | + ] ); | |
| 42 | 78 | |
| 79 | + wp_enqueue_script( | |
| 80 | + 'f12-cf7-doubleoptin-admin', | |
| 81 | + plugins_url( 'assets/f12-cf7-popup.js', __FILE__ ), | |
| 82 | + [ 'jquery' ], | |
| 83 | + defined( 'FORGE12_OPTIN_VERSION' ) ? FORGE12_OPTIN_VERSION : false, | |
| 84 | + true | |
| 85 | + ); | |
| 86 | + $this->get_logger()->debug( 'Admin popup script enqueued', [ | |
| 87 | + 'plugin' => 'double-opt-in', | |
| 88 | + ] ); | |
| 89 | + | |
| 90 | + wp_localize_script( | |
| 91 | + 'f12-cf7-doubleoptin-admin', | |
| 92 | + 'doi', | |
| 93 | + [ | |
| 94 | + 'ajax_url' => admin_url( 'admin-ajax.php' ), | |
| 95 | + 'nonce' => wp_create_nonce( 'f12_doi_details' ), | |
| 96 | + ] | |
| 97 | + ); | |
| 98 | + $this->get_logger()->debug( 'Admin popup script localized', [ | |
| 99 | + 'plugin' => 'double-opt-in', | |
| 100 | + ] ); | |
| 101 | + | |
| 102 | + wp_enqueue_script( | |
| 103 | + 'f12-cf7-doubleoptin-templateloader', | |
| 104 | + plugins_url( 'assets/f12-cf7-templateloader.js', __FILE__ ), | |
| 105 | + [ 'jquery' ], | |
| 106 | + defined( 'FORGE12_OPTIN_VERSION' ) ? FORGE12_OPTIN_VERSION : false, | |
| 107 | + true | |
| 108 | + ); | |
| 109 | + $this->get_logger()->debug( 'Template loader script enqueued', [ | |
| 110 | + 'plugin' => 'double-opt-in', | |
| 111 | + ] ); | |
| 112 | + | |
| 113 | + wp_localize_script( | |
| 114 | + 'f12-cf7-doubleoptin-templateloader', | |
| 115 | + 'templateloader', | |
| 116 | + [ | |
| 117 | + 'ajax_url' => admin_url( 'admin-ajax.php' ), | |
| 118 | + 'nonce' => wp_create_nonce( 'f12_doi_templateloader' ), | |
| 119 | + 'label_placeholder' => __( 'Please wait while we load the template...', 'double-opt-in' ), | |
| 120 | + ] | |
| 121 | + ); | |
| 122 | + $this->get_logger()->debug( 'Template loader script localized', [ | |
| 123 | + 'plugin' => 'double-opt-in', | |
| 124 | + ] ); | |
| 43 | 125 | } |
| 44 | 126 | |
| 127 | + | |
| 45 | 128 | /** |
| 46 | 129 | * Add the hooks responsible to handle wordpress functions |
| 47 | 130 | */ |
| 48 | 131 | public function addHooks() { |
| 49 | - add_filter( 'wpcf7_editor_panels', array( $this, 'addPanel' ), 10, 1 ); | |
| 50 | - add_action( 'wpcf7_save_contact_form', array( $this, 'save' ), 10, 3 ); | |
| 132 | + $this->get_logger()->debug( 'Registering CF7 admin hooks', [ | |
| 133 | + 'plugin' => 'double-opt-in', | |
| 134 | + 'class' => __CLASS__, | |
| 135 | + 'method' => __METHOD__, | |
| 136 | + ] ); | |
| 137 | + | |
| 138 | + add_filter( 'wpcf7_editor_panels', [ $this, 'addPanel' ], 10, 1 ); | |
| 139 | + $this->get_logger()->debug( 'Filter wpcf7_editor_panels registered', [ | |
| 140 | + 'plugin' => 'double-opt-in', | |
| 141 | + ] ); | |
| 142 | + | |
| 143 | + add_action( 'wpcf7_save_contact_form', [ $this, 'save' ], 10, 3 ); | |
| 144 | + $this->get_logger()->debug( 'Action wpcf7_save_contact_form registered', [ | |
| 145 | + 'plugin' => 'double-opt-in', | |
| 146 | + ] ); | |
| 51 | 147 | } |
| 52 | 148 | |
| 149 | + | |
| 53 | 150 | /** |
| 54 | 151 | * Add a custom panel to the contact form 7 options |
| 55 | 152 | */ |
| 56 | 153 | public function addPanel( array $panels ) { |
| 57 | - $panels['optin'] = array( | |
| 154 | + $this->get_logger()->debug( 'Adding CF7 editor panel', [ | |
| 155 | + 'plugin' => 'double-opt-in', | |
| 156 | + 'class' => __CLASS__, | |
| 157 | + 'method' => __METHOD__, | |
| 158 | + ] ); | |
| 159 | + | |
| 160 | + $panels['optin'] = [ | |
| 58 | 161 | 'title' => __( 'Double-Opt-in', 'double-opt-in' ), |
| 59 | - 'callback' => array( $this, 'render' ) | |
| 60 | - ); | |
| 162 | + 'callback' => [ $this, 'render' ], | |
| 163 | + ]; | |
| 61 | 164 | |
| 165 | + $this->get_logger()->debug( 'CF7 editor panel added', [ | |
| 166 | + 'plugin' => 'double-opt-in', | |
| 167 | + ] ); | |
| 168 | + | |
| 62 | 169 | return $panels; |
| 63 | 170 | } |
| 64 | 171 | |
| 172 | + | |
| 65 | 173 | /** |
| 66 | 174 | * On Contact Form save store the information in the database |
| 67 | 175 | * |
| 68 | 176 | * @param \WPCF7_ContactForm $contact_form |
| @@ -71,60 +179,111 @@ | ||
| 71 | 179 | */ |
| 72 | 180 | public function save( $contact_form, $args, $context ) { |
| 73 | 181 | $postID = $contact_form->id(); |
| 74 | 182 | |
| 183 | + $this->get_logger()->debug( 'Saving CF7 Double Opt-In settings', [ | |
| 184 | + 'plugin' => 'double-opt-in', | |
| 185 | + 'class' => __CLASS__, | |
| 186 | + 'method' => __METHOD__, | |
| 187 | + 'post_id' => $postID, | |
| 188 | + ] ); | |
| 189 | + | |
| 75 | 190 | // Validate nonce |
| 76 | - if ( ! isset( $_POST['f12_cf7_doubleoptin_save_form_nonce'] ) || ! wp_verify_nonce( $_POST['f12_cf7_doubleoptin_save_form_nonce'], 'f12_cf7_doubleoptin_save_form_action' ) ) { | |
| 191 | + if ( ! isset( $_POST['f12_cf7_doubleoptin_save_form_nonce'] ) || ! wp_verify_nonce( wp_unslash( $_POST['f12_cf7_doubleoptin_save_form_nonce'] ), 'f12_cf7_doubleoptin_save_form_action' ) ) { | |
| 192 | + $this->get_logger()->warning( 'Nonce validation failed during save', [ | |
| 193 | + 'plugin' => 'double-opt-in', | |
| 194 | + 'post_id' => $postID, | |
| 195 | + ] ); | |
| 77 | 196 | return; |
| 78 | 197 | } |
| 79 | 198 | |
| 80 | - // Check if the double opt in settings is set | |
| 199 | + // Check if the double opt-in settings is set | |
| 81 | 200 | if ( ! $postID || ! isset( $_POST['doubleoptin'] ) ) { |
| 82 | - update_post_meta( $postID, 'f12-cf7-doubleoptin', array() ); | |
| 83 | - | |
| 201 | + update_post_meta( $postID, 'f12-cf7-doubleoptin', [] ); | |
| 202 | + $this->get_logger()->debug( 'No doubleoptin data found, cleared settings', [ | |
| 203 | + 'plugin' => 'double-opt-in', | |
| 204 | + 'post_id' => $postID, | |
| 205 | + ] ); | |
| 84 | 206 | return; |
| 85 | 207 | } |
| 86 | 208 | |
| 87 | 209 | $parameter = SanitizeHelper::sanitize_array( $_POST['doubleoptin'] ); |
| 210 | + $metadata = CF7DoubleOptIn::getInstance()->getParameter( $postID ); | |
| 88 | 211 | |
| 89 | - // load the default parameter | |
| 90 | - $metadata = CF7DoubleOptIn::getInstance()->getParameter( $postID ); | |
| 91 | - | |
| 92 | - // validated all parameter defined in the default parameter options and sanitize them. | |
| 93 | 212 | foreach ( $metadata as $key => $value ) { |
| 94 | 213 | if ( isset( $parameter[ $key ] ) ) { |
| 95 | - if ( $key == 'body' ) { | |
| 214 | + if ( $key === 'body' ) { | |
| 96 | 215 | $metadata[ $key ] = $parameter[ $key ]; |
| 97 | - } else if ( $key == 'enable' ) { | |
| 216 | + } elseif ( $key === 'enable' ) { | |
| 98 | 217 | $metadata[ $key ] = (int) $parameter[ $key ]; |
| 99 | - } else if ( $key == 'sender' ) { | |
| 218 | + } elseif ( $key === 'sender' ) { | |
| 100 | 219 | $metadata[ $key ] = $parameter[ $key ]; |
| 101 | 220 | } else { |
| 102 | 221 | $metadata[ $key ] = $parameter[ $key ]; |
| 103 | 222 | } |
| 104 | - } else if ( $key == 'enable' ) { | |
| 223 | + } elseif ( $key === 'enable' ) { | |
| 105 | 224 | $metadata[ $key ] = 0; |
| 106 | 225 | } |
| 107 | 226 | } |
| 108 | 227 | |
| 109 | - /** | |
| 110 | - * Adjust the Metadata before saving | |
| 111 | - * | |
| 112 | - * @param array $metadata | |
| 113 | - */ | |
| 114 | 228 | $metadata = apply_filters( 'f12_cf7_doubleoptin_metadata_cf7', $metadata ); |
| 115 | - | |
| 116 | - /** | |
| 117 | - * Adjust the Metadata before saving | |
| 118 | - * | |
| 119 | - * @param array $metadata | |
| 120 | - */ | |
| 121 | 229 | $metadata = apply_filters( 'f12_cf7_doubleoptin_save_form', $metadata ); |
| 122 | 230 | |
| 123 | 231 | update_post_meta( $postID, 'f12-cf7-doubleoptin', $metadata ); |
| 232 | + | |
| 233 | + // Save placeholder mapping | |
| 234 | + if ( isset( $_POST['doubleoptin']['placeholder_mapping'] ) && is_array( $_POST['doubleoptin']['placeholder_mapping'] ) ) { | |
| 235 | + $mapping = array_map( 'sanitize_text_field', $_POST['doubleoptin']['placeholder_mapping'] ); | |
| 236 | + PlaceholderMapper::saveCustomMapping( $postID, $mapping, 'cf7' ); | |
| 237 | + | |
| 238 | + $this->get_logger()->debug( 'Placeholder mapping saved', [ | |
| 239 | + 'plugin' => 'double-opt-in', | |
| 240 | + 'post_id' => $postID, | |
| 241 | + 'mapping' => $mapping, | |
| 242 | + ] ); | |
| 243 | + } | |
| 244 | + | |
| 245 | + $this->get_logger()->info( 'Double Opt-In settings saved', [ | |
| 246 | + 'plugin' => 'double-opt-in', | |
| 247 | + 'post_id' => $postID, | |
| 248 | + 'data' => $metadata, | |
| 249 | + ] ); | |
| 124 | 250 | } |
| 125 | 251 | |
| 252 | + | |
| 126 | 253 | /** |
| 254 | + * Get all available templates including custom ones. | |
| 255 | + * | |
| 256 | + * @return array Array of template key => label. | |
| 257 | + */ | |
| 258 | + private function getAvailableTemplates(): array { | |
| 259 | + $templates = [ | |
| 260 | + 'blank' => 'blank', | |
| 261 | + 'newsletter_en' => 'newsletter_en', | |
| 262 | + 'newsletter_en_2' => 'newsletter_en_2', | |
| 263 | + 'newsletter_en_3' => 'newsletter_en_3', | |
| 264 | + ]; | |
| 265 | + | |
| 266 | + // Add custom templates from the Email Template Editor | |
| 267 | + try { | |
| 268 | + $container = \Forge12\DoubleOptIn\Container\Container::getInstance(); | |
| 269 | + $integration = $container->get( \Forge12\DoubleOptIn\EmailTemplates\EmailTemplateIntegration::class ); | |
| 270 | + $customTemplates = $integration->getCustomTemplates(); | |
| 271 | + | |
| 272 | + foreach ( $customTemplates as $template ) { | |
| 273 | + $templates[ 'custom_' . $template['id'] ] = $template['title'] . ' (' . __( 'Custom', 'double-opt-in' ) . ')'; | |
| 274 | + } | |
| 275 | + } catch ( \Exception $e ) { | |
| 276 | + // Silently fail if integration is not available | |
| 277 | + $this->get_logger()->warning( 'Failed to load custom templates: ' . $e->getMessage(), [ | |
| 278 | + 'plugin' => 'double-opt-in', | |
| 279 | + ] ); | |
| 280 | + } | |
| 281 | + | |
| 282 | + return $templates; | |
| 283 | + } | |
| 284 | + | |
| 285 | + /** | |
| 127 | 286 | * Return an option list containing all tags for the condition and a default field to disable the condition. |
| 128 | 287 | * |
| 129 | 288 | * @param \WPCF7_ContactForm $post |
| 130 | 289 | * |
| @@ -130,10 +289,18 @@ | ||
| 130 | 289 | * |
| 131 | 290 | * @return array |
| 132 | 291 | */ |
| 133 | 292 | private function getTags( $post ) { |
| 134 | - $tags = array(); | |
| 293 | + $this->get_logger()->debug( 'Fetching CF7 form tags', [ | |
| 294 | + 'plugin' => 'double-opt-in', | |
| 295 | + 'class' => __CLASS__, | |
| 296 | + 'method' => __METHOD__, | |
| 297 | + 'post_id' => $post->id() ?? null, | |
| 298 | + ] ); | |
| 299 | + | |
| 300 | + $tags = []; | |
| 135 | 301 | $arrayTags = $post->scan_form_tags(); |
| 302 | + | |
| 136 | 303 | foreach ( $arrayTags as $formTag /** @var \WPCF7_FormTag $formTag */ ) { |
| 137 | 304 | if ( ! empty( $formTag->name ) ) { |
| 138 | 305 | $tags[ $formTag->name ] = $formTag->name; |
| 139 | 306 | } |
| @@ -138,14 +305,23 @@ | ||
| 138 | 305 | $tags[ $formTag->name ] = $formTag->name; |
| 139 | 306 | } |
| 140 | 307 | } |
| 141 | 308 | |
| 309 | + $this->get_logger()->debug( 'Form tags fetched', [ | |
| 310 | + 'plugin' => 'double-opt-in', | |
| 311 | + 'count' => count( $tags ), | |
| 312 | + ] ); | |
| 313 | + | |
| 142 | 314 | return $tags; |
| 143 | 315 | } |
| 144 | 316 | |
| 317 | + | |
| 145 | 318 | /** |
| 146 | 319 | * Show the backend double opt in options |
| 147 | 320 | * |
| 321 | + * Displays a notice with link to central form management. | |
| 322 | + * Full settings are now managed centrally in the Forms admin page. | |
| 323 | + * | |
| 148 | 324 | * @param \WPCF7_ContactForm $post |
| 149 | 325 | */ |
| 150 | 326 | public function render( $post ) { |
| 151 | 327 | if ( ! $post ) { |
| @@ -151,333 +327,143 @@ | ||
| 151 | 327 | if ( ! $post ) { |
| 152 | 328 | return; |
| 153 | 329 | } |
| 154 | 330 | |
| 155 | - $metadata = CF7DoubleOptIn::getInstance()->getParameter( $post->id() ); | |
| 156 | - $id = "doubleoptin"; | |
| 331 | + $metadata = CF7DoubleOptIn::getInstance()->getParameter( $post->id() ); | |
| 332 | + $centralUrl = admin_url( 'admin.php?page=f12-doi-admin#/forms' ); | |
| 333 | + $isEnabled = isset( $metadata['enable'] ) && $metadata['enable'] == 1; | |
| 334 | + | |
| 335 | + $this->get_logger()->debug( 'Rendering CF7 panel notice', [ | |
| 336 | + 'plugin' => 'double-opt-in', | |
| 337 | + 'form_id' => $post->id(), | |
| 338 | + 'enabled' => $isEnabled, | |
| 339 | + ] ); | |
| 157 | 340 | ?> |
| 158 | - <div class="forge12-plugin" style="padding-top:0;"> | |
| 159 | - <div class="forge12-plugin-content" style="margin-top:0;"> | |
| 160 | - <div class="forge12-plugin-content-main"> | |
| 161 | - <div class="box" style="width:100%;"> | |
| 162 | - <h2><?php _e( 'Opt-In Formular Settings', 'double-opt-in' ); ?></h2> | |
| 163 | - <div class="option"> | |
| 164 | - <div class="label"> | |
| 165 | - <label for="doubleoptin[enable]"> | |
| 166 | - <?php _e( 'Enable', 'double-opt-in' ); ?> | |
| 167 | - </label> | |
| 168 | - </div> | |
| 169 | - <div class="input"> | |
| 170 | - <input type="checkbox" name="doubleoptin[enable]" id="doubleoptin" | |
| 171 | - value="1" <?php echo isset( $metadata['enable'] ) && $metadata['enable'] == 1 ? 'checked = "checked"' : ''; ?> > | |
| 172 | - <span> | |
| 173 | - <?php _e( 'Yes', 'double-opt-in' ); ?> | |
| 174 | - </span> | |
| 175 | - <p><?php _e( 'Enable this checkox to activate the Double-Opt-In Mail for this formular.', 'double-opt-in' ); ?></p> | |
| 176 | - </div> | |
| 177 | - </div> | |
| 341 | + <div class="doi-cf7-notice" style="padding: 20px;"> | |
| 342 | + <div style="background: #fff; border: 1px solid #c3c4c7; border-radius: 4px; padding: 20px;"> | |
| 343 | + <h2 style="margin-top: 0;"><?php _e( 'Double Opt-In Settings', 'double-opt-in' ); ?></h2> | |
| 178 | 344 | |
| 179 | - <div class="option"> | |
| 180 | - <div class="label"> | |
| 181 | - <label for="doubleoptin[category]"> | |
| 182 | - <?php _e( 'Category', 'double-opt-in' ); ?> | |
| 183 | - </label> | |
| 184 | - </div> | |
| 185 | - <div class="input"> | |
| 186 | - <?php | |
| 187 | - $atts = array( | |
| 188 | - 'perPage' => - 1, | |
| 189 | - 'orderBy' => 'name', | |
| 190 | - 'order' => 'ASC' | |
| 191 | - ); | |
| 345 | + <div style="display: flex; align-items: center; gap: 15px; margin-bottom: 20px;"> | |
| 346 | + <span style="font-weight: 600;"><?php _e( 'Status:', 'double-opt-in' ); ?></span> | |
| 347 | + <?php if ( $isEnabled ) : ?> | |
| 348 | + <span style="display: inline-block; padding: 4px 12px; background: #d4edda; color: #155724; border-radius: 3px; font-weight: 500;"> | |
| 349 | + <?php _e( 'Enabled', 'double-opt-in' ); ?> | |
| 350 | + </span> | |
| 351 | + <?php else : ?> | |
| 352 | + <span style="display: inline-block; padding: 4px 12px; background: #f8d7da; color: #721c24; border-radius: 3px; font-weight: 500;"> | |
| 353 | + <?php _e( 'Disabled', 'double-opt-in' ); ?> | |
| 354 | + </span> | |
| 355 | + <?php endif; ?> | |
| 356 | + </div> | |
| 192 | 357 | |
| 193 | - $list = Category::get_list( $atts, $numberOfPages ); | |
| 358 | + <p style="color: #666; margin-bottom: 20px;"> | |
| 359 | + <?php _e( 'Double Opt-In settings are now managed centrally. Use the button below to configure this form.', 'double-opt-in' ); ?> | |
| 360 | + </p> | |
| 194 | 361 | |
| 195 | - $response = '<option value="0">' . __( 'Please select', 'double-opt-in' ) . '</option>'; | |
| 196 | - foreach ( $list as $Category /** @var Category $Category */ ) { | |
| 197 | - $selected = ""; | |
| 198 | - if ( $Category->get_id() == $metadata['category'] ) { | |
| 199 | - $selected = 'selected="selected"'; | |
| 200 | - } | |
| 201 | - $response .= '<option value="' . esc_attr( $Category->get_id() ) . '" ' . $selected . '>' . esc_attr( $Category->get_name() ) . '</option>'; | |
| 202 | - } | |
| 203 | - ?> | |
| 204 | - <select name="doubleoptin[category]"><?php echo wp_kses( $response, array( | |
| 205 | - 'option' => array( | |
| 206 | - 'value' => array(), | |
| 207 | - 'selected' => array() | |
| 208 | - ) | |
| 209 | - ) ); ?></select> | |
| 210 | - <span> | |
| 211 | - <?php _e( 'Assign the Opt-In to a Category for an easier administration.', 'double-opt-in' ); ?> | |
| 212 | - </span> | |
| 213 | - </div> | |
| 214 | - </div> | |
| 362 | + <a href="<?php echo esc_url( $centralUrl ); ?>" class="button button-primary"> | |
| 363 | + <?php _e( 'Configure Double Opt-In', 'double-opt-in' ); ?> | |
| 364 | + </a> | |
| 365 | + </div> | |
| 366 | + </div> | |
| 367 | + <?php | |
| 368 | + } | |
| 215 | 369 | |
| 216 | - <div class="option"> | |
| 217 | - <div class="label"> | |
| 218 | - <label for="doubleoptin[page]"> | |
| 219 | - <?php _e( 'Dynamic Condition', 'double-opt-in' ); ?> | |
| 220 | - </label> | |
| 221 | - </div> | |
| 222 | - <div class="input"> | |
| 223 | - <span> | |
| 224 | - <?php _e( 'Enable the Opt-In only when the field ', 'double-opt-in' ); ?> | |
| 225 | - </span> | |
| 226 | - <?php | |
| 227 | - $ConditionList = new HTMLSelect( $id . '[conditions]', array_merge( array( 'disable' => __( 'Disabled', 'double-opt-in' ) ), $this->getTags( $post ) ), array( | |
| 228 | - 'id' => array( $id . '-conditions' ), | |
| 229 | - 'class' => array( | |
| 230 | - 'large-text', | |
| 231 | - 'code' | |
| 232 | - ) | |
| 233 | - ) ); | |
| 234 | - $ConditionList->setOptionSelectedByKey( $metadata['conditions'] ); | |
| 235 | - echo wp_kses( $ConditionList->get(), array( | |
| 236 | - 'select' => array( 'name' => array() ), | |
| 237 | - 'option' => array( | |
| 238 | - 'value' => array(), | |
| 239 | - 'selected' => array() | |
| 240 | - ) | |
| 241 | - ) ); | |
| 242 | - ?> | |
| 243 | - <span> | |
| 244 | - <?php _e( 'has been filled/checked by the visitor.', 'double-opt-in' ); ?> | |
| 245 | - </span> | |
| 246 | - </div> | |
| 247 | - </div> | |
| 370 | + /** | |
| 371 | + * Render the placeholder mapping UI. | |
| 372 | + * | |
| 373 | + * @param \WPCF7_ContactForm $post The contact form. | |
| 374 | + * @param array $metadata Form metadata. | |
| 375 | + * @param string $id Form element ID prefix. | |
| 376 | + * @return void | |
| 377 | + */ | |
| 378 | + private function renderPlaceholderMappingUI( $post, array $metadata, string $id ): void { | |
| 379 | + $formFields = array_keys( $this->getTags( $post ) ); | |
| 380 | + $standardPlaceholders = PlaceholderMapper::getStandardPlaceholders(); | |
| 381 | + $autoMapping = PlaceholderMapper::autoDetectMapping( $formFields ); | |
| 382 | + $customMapping = PlaceholderMapper::getCustomMapping( $post->id(), 'cf7' ); | |
| 248 | 383 | |
| 249 | - <div class="option"> | |
| 250 | - <div class="label"> | |
| 251 | - <label for="doubleoptin[page]"> | |
| 252 | - <?php _e( 'Confirmation Page', 'double-opt-in' ); ?> | |
| 253 | - </label> | |
| 254 | - </div> | |
| 255 | - <div class="input"> | |
| 256 | - <?php wp_dropdown_pages( array( | |
| 257 | - 'show_option_none' => __( 'default', 'double-opt-in' ), | |
| 258 | - 'name' => 'doubleoptin[page]', | |
| 259 | - 'selected' => $metadata['page'] | |
| 260 | - ) ); ?> | |
| 261 | - <p> | |
| 262 | - <?php _e( 'Select the page that should be displayed after the user clicks on the confirmation link', 'double-opt-in' ); ?> | |
| 263 | - </p> | |
| 264 | - </div> | |
| 265 | - </div> | |
| 384 | + // Merge for display (custom takes precedence) | |
| 385 | + $effectiveMapping = array_merge( $autoMapping, $customMapping ); | |
| 386 | + ?> | |
| 387 | + <div class="box" style="width:100%;"> | |
| 388 | + <h2><?php _e( 'Standard Placeholders Mapping', 'double-opt-in' ); ?></h2> | |
| 389 | + <p class="description" style="margin-bottom: 15px;"> | |
| 390 | + <?php _e( 'Map your form fields to standard placeholders. This allows you to use the same email template across different forms. Fields are auto-detected based on common naming patterns, but you can override them.', 'double-opt-in' ); ?> | |
| 391 | + </p> | |
| 266 | 392 | |
| 267 | - <?php | |
| 268 | - /** | |
| 269 | - * Used to render settings for CF7 | |
| 270 | - * | |
| 271 | - * @param string $output | |
| 272 | - * @param array $metadata | |
| 273 | - * | |
| 274 | - * @since 3.0.0 | |
| 275 | - */ | |
| 276 | - echo apply_filters( 'f12_cf7_formular_settings_after_cf7', '', $metadata ); | |
| 277 | - | |
| 278 | - /** | |
| 279 | - * Deprecated - Used to add settings for cf7. | |
| 280 | - * | |
| 281 | - * @param string $type | |
| 282 | - * @param array $metadata | |
| 283 | - */ | |
| 284 | - do_action( 'f12_cf7_formular_settings_after', 'cf7', $metadata ); | |
| 393 | + <table class="widefat" style="margin-bottom: 20px;"> | |
| 394 | + <thead> | |
| 395 | + <tr> | |
| 396 | + <th style="width: 200px;"><?php _e( 'Standard Placeholder', 'double-opt-in' ); ?></th> | |
| 397 | + <th style="width: 150px;"><?php _e( 'Auto-Detected', 'double-opt-in' ); ?></th> | |
| 398 | + <th><?php _e( 'Custom Mapping (Override)', 'double-opt-in' ); ?></th> | |
| 399 | + </tr> | |
| 400 | + </thead> | |
| 401 | + <tbody> | |
| 402 | + <?php foreach ( $standardPlaceholders as $placeholder => $config ) : | |
| 403 | + $autoDetected = isset( $autoMapping[ $placeholder ] ) ? $autoMapping[ $placeholder ] : ''; | |
| 404 | + $customValue = isset( $customMapping[ $placeholder ] ) ? $customMapping[ $placeholder ] : ''; | |
| 285 | 405 | ?> |
| 286 | - </div> | |
| 287 | - | |
| 288 | - <div class="box" style="width:100%;"> | |
| 289 | - <h2><?php _e( 'Customize your Opt-In Mail', 'double-opt-in' ); ?></h2> | |
| 290 | - <div class="option"> | |
| 291 | - <div class="label"> | |
| 292 | - <label for="doubleoptin-recipient"> | |
| 293 | - <label for="<?php echo esc_attr( $id ); ?>-recipient"><?php echo __( 'To', 'double-opt-in' ); ?></label> | |
| 294 | - </label> | |
| 295 | - </div> | |
| 296 | - <div class="input"> | |
| 297 | - <input type="text" id="<?php echo esc_attr( $id ); ?>-recipient" | |
| 298 | - name="<?php echo esc_attr( $id ); ?>[recipient]" | |
| 299 | - class="large-text code" size="70" | |
| 300 | - value="<?php echo esc_attr( $metadata['recipient'] ); ?>"/> | |
| 301 | - <p> | |
| 302 | - <?php _e( 'This field defines who will receive the Double-Opt-In mail. Enter one of the following tags that represents the mail for the customer:', 'double-opt-in' ); ?> | |
| 303 | - </p> | |
| 304 | - <p> | |
| 305 | - <code> | |
| 306 | - <?php | |
| 307 | - $arrayTags = $this->getTags( $post ); | |
| 308 | - foreach ( $arrayTags as $key => $value ) { | |
| 309 | - $arrayTags[ $key ] = "[" . esc_html( $value ) . "]"; | |
| 406 | + <tr> | |
| 407 | + <td> | |
| 408 | + <code>[<?php echo esc_html( $placeholder ); ?>]</code> | |
| 409 | + <br> | |
| 410 | + <small style="color: #666;"><?php echo esc_html( $config['label'] ); ?></small> | |
| 411 | + </td> | |
| 412 | + <td> | |
| 413 | + <?php if ( $autoDetected ) : ?> | |
| 414 | + <span style="color: #46b450;"> | |
| 415 | + <code>[<?php echo esc_html( $autoDetected ); ?>]</code> | |
| 416 | + </span> | |
| 417 | + <?php else : ?> | |
| 418 | + <span style="color: #999;"><?php _e( 'Not detected', 'double-opt-in' ); ?></span> | |
| 419 | + <?php endif; ?> | |
| 420 | + </td> | |
| 421 | + <td> | |
| 422 | + <select name="doubleoptin[placeholder_mapping][<?php echo esc_attr( $placeholder ); ?>]" | |
| 423 | + style="width: 100%; max-width: 300px;"> | |
| 424 | + <option value=""><?php | |
| 425 | + if ( $autoDetected ) { | |
| 426 | + printf( __( 'Use auto-detected: [%s]', 'double-opt-in' ), $autoDetected ); | |
| 427 | + } else { | |
| 428 | + _e( '-- Select field --', 'double-opt-in' ); | |
| 310 | 429 | } |
| 311 | - echo esc_html( implode( ",", array_filter( $arrayTags ) ) ); | |
| 312 | - ?> | |
| 313 | - </code> | |
| 314 | - </p> | |
| 315 | - </div> | |
| 316 | - </div> | |
| 430 | + ?></option> | |
| 431 | + <?php foreach ( $formFields as $field ) : ?> | |
| 432 | + <option value="<?php echo esc_attr( $field ); ?>" | |
| 433 | + <?php selected( $customValue, $field ); ?>> | |
| 434 | + [<?php echo esc_html( $field ); ?>] | |
| 435 | + </option> | |
| 436 | + <?php endforeach; ?> | |
| 437 | + </select> | |
| 438 | + </td> | |
| 439 | + </tr> | |
| 440 | + <?php endforeach; ?> | |
| 441 | + </tbody> | |
| 442 | + </table> | |
| 317 | 443 | |
| 318 | - <div class="option"> | |
| 319 | - <div class="label"> | |
| 320 | - <label for="<?php echo esc_attr( $id ); ?>-sender"> | |
| 321 | - <?php echo esc_html( __( 'From', 'double-opt-in' ) ); ?> | |
| 322 | - </label> | |
| 323 | - </div> | |
| 324 | - <div class="input"> | |
| 325 | - <input type="text" id="<?php echo esc_attr( $id ); ?>-sender" | |
| 326 | - name="<?php echo esc_attr( $id ); ?>[sender]" | |
| 327 | - class="large-text code" size="70" | |
| 328 | - value="<?php echo esc_attr( $metadata['sender'] ); ?>"/> | |
| 329 | - <p> | |
| 330 | - <?php _e( 'This field defines who will sent the mail. You can either enter the e-Mail (e.g.: [email protected]) or use a placeholder (e.g.: [_site_admin_email]).', 'double-opt-in' ); ?> | |
| 331 | - </p> | |
| 332 | - </div> | |
| 333 | - </div> | |
| 334 | - | |
| 335 | - <div class="option"> | |
| 336 | - <div class="label"> | |
| 337 | - <label for="<?php echo esc_attr( $id ); ?>-sender"> | |
| 338 | - <?php echo esc_html( __( 'From Name', 'double-opt-in' ) ); ?> | |
| 339 | - </label> | |
| 340 | - </div> | |
| 341 | - <div class="input"> | |
| 342 | - <input type="text" id="<?php echo esc_attr( $id ); ?>-sender_name" | |
| 343 | - name="<?php echo esc_attr( $id ); ?>[sender_name]" | |
| 344 | - class="large-text code" size="70" | |
| 345 | - value="<?php echo esc_attr( $metadata['sender_name'] ); ?>"/> | |
| 346 | - <p> | |
| 347 | - <?php _e( 'This field defines the name of the sender (e.g. Max Mustermann).', 'double-opt-in' ); ?> | |
| 348 | - </p> | |
| 349 | - </div> | |
| 350 | - </div> | |
| 351 | - | |
| 352 | - <div class="option"> | |
| 353 | - <div class="label"> | |
| 354 | - <label for="<?php echo esc_attr( $id ); ?>-subject"> | |
| 355 | - <?php echo esc_html( __( 'Subject', 'double-opt-in' ) ); ?> | |
| 356 | - </label> | |
| 357 | - </div> | |
| 358 | - <div class="input"> | |
| 359 | - <input type="text" id="<?php echo esc_attr( $id ); ?>-subject" | |
| 360 | - name="<?php echo esc_attr( $id ); ?>[subject]" | |
| 361 | - class="large-text code" size="70" | |
| 362 | - value="<?php echo esc_attr( $metadata['subject'] ); ?>"/> | |
| 363 | - <p> | |
| 364 | - <?php _e( 'Enter a custom subject for the Double-Opt-In mail (e.g.: Please confirm your registration).', 'double-opt-in' ); ?> | |
| 365 | - </p> | |
| 366 | - </div> | |
| 367 | - </div> | |
| 368 | - | |
| 369 | - <div class="option"> | |
| 370 | - <div class="label"> | |
| 371 | - <label for="<?php echo esc_attr( $id ); ?>-body"> | |
| 372 | - <?php echo esc_html( __( 'Template', 'double-opt-in' ) ); ?> | |
| 373 | - </label> | |
| 374 | - </div> | |
| 375 | - <div class="input"> | |
| 376 | - <div class="preview"> | |
| 377 | - <div class="preview-item"> | |
| 378 | - <div class="preview-item-inner <?php if ( $metadata['template'] == 'blank' ) { | |
| 379 | - echo 'active'; | |
| 380 | - }; ?>"> | |
| 381 | - <img src="<?php echo esc_url( plugin_dir_url( dirname( dirname( __FILE__ ) ) ) . 'mails/blank.png' ); ?>" | |
| 382 | - class="f12-cf7-templateloader-preview" data-template="blank" | |
| 383 | - title="Blank"/> | |
| 384 | - </div> | |
| 385 | - </div> | |
| 386 | - <div class="preview-item"> | |
| 387 | - <div class="preview-item-inner <?php if ( $metadata['template'] == 'newsletter_en' ) { | |
| 388 | - echo 'active'; | |
| 389 | - }; ?>"> | |
| 390 | - <img src="<?php echo esc_url( plugin_dir_url( dirname( dirname( __FILE__ ) ) ) . 'mails/newsletter_en.png' ); ?>" | |
| 391 | - class="f12-cf7-templateloader-preview" title="Newsletter EN" | |
| 392 | - data-template="newsletter_en" alt=""/> | |
| 393 | - </div> | |
| 394 | - </div> | |
| 395 | - <div class="preview-item"> | |
| 396 | - <div class="preview-item-inner <?php if ( $metadata['template'] == 'newsletter_en_2' ) { | |
| 397 | - echo 'active'; | |
| 398 | - }; ?>"> | |
| 399 | - <img src="<?php echo esc_url( plugin_dir_url( dirname( dirname( __FILE__ ) ) ) . 'mails/newsletter_en_2.png' ); ?>" | |
| 400 | - class="f12-cf7-templateloader-preview" title="Newsletter EN 2" | |
| 401 | - data-template="newsletter_en_2"/> | |
| 402 | - </div> | |
| 403 | - </div> | |
| 404 | - <div class="preview-item"> | |
| 405 | - <div class="preview-item-inner <?php if ( $metadata['template'] == 'newsletter_en_3' ) { | |
| 406 | - echo 'active'; | |
| 407 | - }; ?>"> | |
| 408 | - <img src="<?php echo esc_url( plugin_dir_url( dirname( dirname( __FILE__ ) ) ) . 'mails/newsletter_en_3.png' ); ?>" | |
| 409 | - class="f12-cf7-templateloader-preview" title="Newsletter EN 3" | |
| 410 | - data-template="newsletter_en_3"/> | |
| 411 | - </div> | |
| 412 | - </div> | |
| 413 | - </div> | |
| 414 | - <?php | |
| 415 | - $TemplateList = new HTMLSelect( $id . '[template]', array( | |
| 416 | - 'blank' => 'blank', | |
| 417 | - 'newsletter_en' => 'newsletter_en', | |
| 418 | - 'newsletter_en_2' => 'newsletter_en_2', | |
| 419 | - 'newsletter_en_3' => 'newsletter_en_3' | |
| 420 | - ), array( | |
| 421 | - 'class' => array( 'f12-cf7-templateloader' ), | |
| 422 | - 'style' => array( 'display:none;' ) | |
| 423 | - ) ); | |
| 424 | - $TemplateList->setOptionSelectedByKey( $metadata['template'] ); | |
| 425 | - echo wp_kses( $TemplateList->get(), array( | |
| 426 | - 'select' => array( | |
| 427 | - 'style' => array(), | |
| 428 | - 'class' => array(), | |
| 429 | - 'name' => array() | |
| 430 | - ), | |
| 431 | - 'option' => array( | |
| 432 | - 'value' => array(), | |
| 433 | - 'selected' => array() | |
| 434 | - ) | |
| 435 | - ) ); | |
| 436 | - ?> | |
| 437 | - </div> | |
| 438 | - </div> | |
| 439 | - | |
| 440 | - <div class="option"> | |
| 441 | - <div class="label"> | |
| 442 | - <label for="<?php echo esc_attr( $id ); ?>-body"> | |
| 443 | - <?php echo esc_html( __( 'Message body', 'double-opt-in' ) ); ?> | |
| 444 | - </label> | |
| 445 | - </div> | |
| 446 | - <div class="input"> | |
| 447 | - <textarea id="<?php echo esc_attr( $id ); ?>-body" | |
| 448 | - name="<?php echo esc_attr( $id ); ?>[body]" | |
| 449 | - cols="100" rows="18" | |
| 450 | - class="large-text code"><?php echo esc_textarea( $metadata['body'] ); ?></textarea> | |
| 451 | - <p> | |
| 452 | - <?php _e( 'Enter the Message you want to sent to your customer. Do not forget to add the Double-Opt-In tag ([doubleoptinlink]) e.g.:', 'double-opt-in' ); ?> | |
| 453 | - <code> | |
| 454 | - <a href="[doubleoptinlink]">Confirm the registration</a> | |
| 455 | - </code> | |
| 456 | - </p> | |
| 457 | - <p> | |
| 458 | - <?php _e( 'These placeholders are available for the opt-in Message body: ', 'double-opt-in' ); ?> | |
| 459 | - </p> | |
| 460 | - <p> | |
| 461 | - <code>[doubleoptinlink],[doubleoptin_form_url],[doubleoptin_form_subject],[doubleoptin_form_date],[doubleoptin_form_time],[_site_admin_email],<?php | |
| 462 | - $arrayTags = $this->getTags( $post ); | |
| 463 | - foreach ( $arrayTags as $key => $value ) { | |
| 464 | - $arrayTags[ $key ] = "[" . esc_html( $value ) . "]"; | |
| 465 | - } | |
| 466 | - echo implode( ",", array_filter( $arrayTags ) ); | |
| 467 | - ?> | |
| 468 | - </code> | |
| 469 | - </p> | |
| 470 | - </div> | |
| 471 | - </div> | |
| 472 | - </div> | |
| 473 | - | |
| 474 | - | |
| 475 | - <?php do_action( 'f12_cf7_doubleoptin_admin_panel', $post, $metadata, $id ); ?> | |
| 476 | - <?php wp_nonce_field( 'f12_cf7_doubleoptin_save_form_action', 'f12_cf7_doubleoptin_save_form_nonce' ); ?> | |
| 477 | - </div> | |
| 478 | - </div> | |
| 479 | - </div> | |
| 444 | + <div style="background: #f9f9f9; padding: 15px; border-radius: 4px; border: 1px solid #ddd;"> | |
| 445 | + <h4 style="margin-top: 0;"><?php _e( 'How to use', 'double-opt-in' ); ?></h4> | |
| 446 | + <p style="margin-bottom: 10px;"> | |
| 447 | + <?php _e( 'In your email template, use these standard placeholders instead of form-specific ones:', 'double-opt-in' ); ?> | |
| 448 | + </p> | |
| 449 | + <div style="display: flex; flex-wrap: wrap; gap: 10px;"> | |
| 450 | + <?php foreach ( $standardPlaceholders as $placeholder => $config ) : ?> | |
| 451 | + <code style="background: #fff; padding: 3px 8px; border: 1px solid #ddd; border-radius: 3px;"> | |
| 452 | + [<?php echo esc_html( $placeholder ); ?>] | |
| 453 | + </code> | |
| 454 | + <?php endforeach; ?> | |
| 455 | + </div> | |
| 456 | + <p style="margin-top: 15px; margin-bottom: 0;"> | |
| 457 | + <strong><?php _e( 'System Placeholders (always available):', 'double-opt-in' ); ?></strong><br> | |
| 458 | + <code>[doubleoptinlink]</code>, | |
| 459 | + <code>[doubleoptoutlink]</code>, | |
| 460 | + <code>[doubleoptin_form_date]</code>, | |
| 461 | + <code>[doubleoptin_form_time]</code>, | |
| 462 | + <code>[doubleoptin_form_url]</code> | |
| 463 | + </p> | |
| 464 | + </div> | |
| 465 | + </div> | |
| 480 | 466 | <?php |
| 481 | 467 | } |
| 482 | 468 | } |
| 483 | 469 | } |