Theme My Login - Version 7.1

Version Description

  • Implement AJAX support
  • Introduce new Dashboard action
  • Improve performance by reducing queries
  • Require WordPress 5.4
  • Remove angle brackets from password reset link in notification
  • Add sensitive page meta tags to TML actions
  • Add missing lost_password action hook
  • Fix lostpassword link being rewritten on wp-login.php
Download this release

Release Info

Developer jfarthing84
Plugin Icon 128x128 Theme My Login
Version 7.1
Comparing to
See all releases

Code changes from version 7.0.15 to 7.1

admin/assets/scripts/theme-my-login-admin.js CHANGED
@@ -11,6 +11,78 @@
11
  }
12
  } )( jQuery );
13
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  ( function( $ ) {
15
 
16
  $( initMetaBoxes );
11
  }
12
  } )( jQuery );
13
 
14
+ ( function( $ ) {
15
+ $( function() {
16
+ $( '.tml-license-field' ).on( 'input', function() {
17
+ var input = $( this ),
18
+ activate = input.siblings( '.tml-license-button' ).filter( '[data-action="activate"]' ),
19
+ status = input.siblings( '.tml-license-status' );
20
+
21
+ if ( this.value.length == 32 ) {
22
+ activate.show();
23
+ } else {
24
+ activate.hide();
25
+ status
26
+ .html( '' )
27
+ .add( input )
28
+ .addClass( 'tml-license-inactive' )
29
+ .removeClass( 'tml-license-valid tml-license-invalid' );
30
+ }
31
+ } );
32
+
33
+ $( '.tml-license-button' ).on( 'click', function( e ) {
34
+ var button = $( this ),
35
+ action = button.data( 'action' ),
36
+ otherButton = button.siblings( '.tml-license-button' ),
37
+ input = button.siblings( '.tml-license-field' ),
38
+ spinner = button.siblings( '.spinner' ),
39
+ status = button.siblings( '.tml-license-status' );
40
+
41
+ e.preventDefault();
42
+
43
+ button.hide();
44
+ spinner.addClass( 'is-active' );
45
+
46
+ $.post( tmlAdmin.ajaxUrl, {
47
+ action: 'tml-' + action + '-extension-license',
48
+ extension: button.data( 'extension' ),
49
+ key: input.val()
50
+ } ).done( function( response ) {
51
+ if ( response.success ) {
52
+ otherButton.show();
53
+ status
54
+ .show()
55
+ .html( response.data )
56
+ .add( input )
57
+ .addClass(
58
+ action == 'activate'
59
+ ? 'tml-license-valid'
60
+ : 'tml-license-inactive'
61
+ )
62
+ .removeClass(
63
+ action == 'activate'
64
+ ? 'tml-license-invalid'
65
+ : 'tml-license-valid tml-license-invalid'
66
+ );
67
+ } else {
68
+ button.show();
69
+ status
70
+ .show()
71
+ .html( response.data )
72
+ .add( input )
73
+ .addClass( 'tml-license-invalid' )
74
+ .removeClass( 'tml-license-valid' );
75
+ }
76
+ } ).fail( function ( jqXHR, textStatus, errorThrown ) {
77
+ alert( errorThrown );
78
+ button.show();
79
+ } ).always( function() {
80
+ spinner.removeClass( 'is-active' );
81
+ } );
82
+ } );
83
+ } );
84
+ } )( jQuery );
85
+
86
  ( function( $ ) {
87
 
88
  $( initMetaBoxes );
admin/assets/scripts/theme-my-login-admin.min.js CHANGED
@@ -1 +1 @@
1
- !function(o){o(function(){var t=o("#wp-auth-check-form");t.length&&t.attr("data-src",tmlAdmin.interimLoginUrl)})}(jQuery),function(o){o(function(){o("#tml-settings .postbox").length&&(postboxes.add_postbox_toggles(pagenow),o(".postbox").addClass("closed"),o(".metabox-holder").each(function(){var t=o(this);"off"==t.data("sortable")&&(t.find(".meta-box-sortables").sortable("destroy"),t.find(".postbox .hndle").css("cursor","default"))}))})}(jQuery),function(n){n(function(){n(".tml-notice").on("click",".notice-dismiss",function(t){var o=n(t.delegateTarget);n.post(ajaxurl,{action:"tml-dismiss-notice",notice:o.data("notice")})})})}(jQuery);
1
+ !function(i){i(function(){var t=i("#wp-auth-check-form");t.length&&t.attr("data-src",tmlAdmin.interimLoginUrl)})}(jQuery),function(o){o(function(){o(".tml-license-field").on("input",function(){var t=o(this),i=t.siblings(".tml-license-button").filter('[data-action="activate"]'),e=t.siblings(".tml-license-status");32==this.value.length?i.show():(i.hide(),e.html("").add(t).addClass("tml-license-inactive").removeClass("tml-license-valid tml-license-invalid"))}),o(".tml-license-button").on("click",function(t){var s=o(this),i=s.data("action"),e=s.siblings(".tml-license-button"),n=s.siblings(".tml-license-field"),l=s.siblings(".spinner"),a=s.siblings(".tml-license-status");t.preventDefault(),s.hide(),l.addClass("is-active"),o.post(tmlAdmin.ajaxUrl,{action:"tml-"+i+"-extension-license",extension:s.data("extension"),key:n.val()}).done(function(t){t.success?(e.show(),a.show().html(t.data).add(n).addClass("activate"==i?"tml-license-valid":"tml-license-inactive").removeClass("activate"==i?"tml-license-invalid":"tml-license-valid tml-license-invalid")):(s.show(),a.show().html(t.data).add(n).addClass("tml-license-invalid").removeClass("tml-license-valid"))}).fail(function(t,i,e){alert(e),s.show()}).always(function(){l.removeClass("is-active")})})})}(jQuery),function(i){i(function(){i("#tml-settings .postbox").length&&(postboxes.add_postbox_toggles(pagenow),i(".postbox").addClass("closed"),i(".metabox-holder").each(function(){var t=i(this);"off"==t.data("sortable")&&(t.find(".meta-box-sortables").sortable("destroy"),t.find(".postbox .hndle").css("cursor","default"))}))})}(jQuery),function(e){e(function(){e(".tml-notice").on("click",".notice-dismiss",function(t){var i=e(t.delegateTarget);e.post(ajaxurl,{action:"tml-dismiss-notice",notice:i.data("notice")})})})}(jQuery);
admin/assets/styles/theme-my-login-admin.css CHANGED
@@ -9,15 +9,13 @@
9
  }
10
 
11
  .tml-extensions-wrap * {
12
- -webkit-box-sizing: border-box;
13
- box-sizing: border-box;
14
  }
15
 
16
  .tml-extension {
17
  background-color: #fff;
18
  border: 1px solid #ccc;
19
- -webkit-box-shadow: 0 0 5px rgba(0, 0, 0, 0.15);
20
- box-shadow: 0 0 5px rgba(0, 0, 0, 0.15);
21
  float: left;
22
  margin: 15px;
23
  max-width: 350px;
@@ -70,8 +68,7 @@
70
 
71
  .tml-extension-button:active,
72
  .tml-extension-button:focus {
73
- -webkit-box-shadow: 0 0 0 0.2em rgba(141, 80, 195, 0.5);
74
- box-shadow: 0 0 0 0.2em rgba(141, 80, 195, 0.5);
75
  color: #fff;
76
  }
77
 
@@ -85,3 +82,26 @@
85
  font-size: 1.5em;
86
  text-decoration: none;
87
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  }
10
 
11
  .tml-extensions-wrap * {
12
+ box-sizing: border-box;
 
13
  }
14
 
15
  .tml-extension {
16
  background-color: #fff;
17
  border: 1px solid #ccc;
18
+ box-shadow: 0 0 5px rgba(0, 0, 0, 0.15);
 
19
  float: left;
20
  margin: 15px;
21
  max-width: 350px;
68
 
69
  .tml-extension-button:active,
70
  .tml-extension-button:focus {
71
+ box-shadow: 0 0 0 0.2em rgba(141, 80, 195, 0.5);
 
72
  color: #fff;
73
  }
74
 
82
  font-size: 1.5em;
83
  text-decoration: none;
84
  }
85
+
86
+ #tml-settings input[type="text"].tml-license-valid {
87
+ background-color: #b5e1b9;
88
+ border-color: #46b450;
89
+ }
90
+
91
+ #tml-settings input[type="text"].tml-license-invalid {
92
+ background-color: #f1adad;
93
+ border-color: #dc3232;
94
+ }
95
+
96
+ #tml-settings p.tml-license-valid {
97
+ color: #46b450;
98
+ }
99
+
100
+ #tml-settings p.tml-license-invalid {
101
+ color: #dc3232;
102
+ }
103
+
104
+ #tml-settings .spinner {
105
+ float: none;
106
+ margin-top: 0;
107
+ }
admin/assets/styles/theme-my-login-admin.min.css CHANGED
@@ -1 +1 @@
1
- .tml-extensions-wrap{margin:0 -15px}.tml-extensions-wrap:after{content:"";clear:both;display:table}.tml-extensions-wrap *{-webkit-box-sizing:border-box;box-sizing:border-box}.tml-extension{background-color:#fff;border:1px solid #ccc;-webkit-box-shadow:0 0 5px rgba(0,0,0,.15);box-shadow:0 0 5px rgba(0,0,0,.15);float:left;margin:15px;max-width:350px}@media (min-width:576px){.tml-extension{width:40%}}@media (min-width:783px){.tml-extension{width:30%}}.tml-extension-image{height:auto;max-width:100%}.tml-extension-body{padding:15px}.tml-extension-body p{min-height:5em}.tml-extension-title{margin:0 0 15px;padding:0}.tml-extension-button{background-color:#8d50c3;color:#fff;display:block;font-size:1.1em;padding:10px;text-align:center;text-decoration:none}.tml-extension-button:hover{color:#fff;background-color:#7a3cb0}.tml-extension-button:active,.tml-extension-button:focus{-webkit-box-shadow:0 0 0 .2em rgba(141,80,195,.5);box-shadow:0 0 0 .2em rgba(141,80,195,.5);color:#fff}.tml-view-all-extensions-wrap{padding:15px 0;text-align:center}.tml-view-all-extensions-link{display:inline-block;font-size:1.5em;text-decoration:none}
1
+ .tml-extensions-wrap{margin:0 -15px}.tml-extensions-wrap:after{content:"";clear:both;display:table}.tml-extensions-wrap *{box-sizing:border-box}.tml-extension{background-color:#fff;border:1px solid #ccc;box-shadow:0 0 5px rgba(0,0,0,.15);float:left;margin:15px;max-width:350px}@media (min-width:576px){.tml-extension{width:40%}}@media (min-width:783px){.tml-extension{width:30%}}.tml-extension-image{height:auto;max-width:100%}.tml-extension-body{padding:15px}.tml-extension-body p{min-height:5em}.tml-extension-title{margin:0 0 15px;padding:0}.tml-extension-button{background-color:#8d50c3;color:#fff;display:block;font-size:1.1em;padding:10px;text-align:center;text-decoration:none}.tml-extension-button:hover{color:#fff;background-color:#7a3cb0}.tml-extension-button:active,.tml-extension-button:focus{box-shadow:0 0 0 .2em rgba(141,80,195,.5);color:#fff}.tml-view-all-extensions-wrap{padding:15px 0;text-align:center}.tml-view-all-extensions-link{display:inline-block;font-size:1.5em;text-decoration:none}#tml-settings input[type=text].tml-license-valid{background-color:#b5e1b9;border-color:#46b450}#tml-settings input[type=text].tml-license-invalid{background-color:#f1adad;border-color:#dc3232}#tml-settings p.tml-license-valid{color:#46b450}#tml-settings p.tml-license-invalid{color:#dc3232}#tml-settings .spinner{float:none;margin-top:0}
admin/extensions.php CHANGED
@@ -153,6 +153,53 @@ function tml_admin_handle_extension_licenses() {
153
  }
154
  }
155
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
156
  /**
157
  * Check that all of the licenses are valid.
158
  *
153
  }
154
  }
155
 
156
+ /**
157
+ * Handle AJAX activation of extension licenses.
158
+ *
159
+ * @since 7.1
160
+ */
161
+ function tml_admin_ajax_activate_extension_license() {
162
+ if ( ! $extension = tml_get_extension( tml_get_request_value( 'extension', 'post' ) ) ) {
163
+ tml_send_ajax_error( __( 'Invalid extension.', 'theme-my-login' ) );
164
+ }
165
+
166
+ $extension->set_license_key( tml_get_request_value( 'key', 'post' ) );
167
+
168
+ $response = tml_activate_extension_license( $extension );
169
+
170
+ if ( is_wp_error( $response ) ) {
171
+ $extension->set_license_key();
172
+ $extension->set_license_status();
173
+
174
+ tml_send_ajax_error( $response->get_error_message() );
175
+ }
176
+
177
+ $extension->set_license_status( $response );
178
+
179
+ tml_send_ajax_success( __( 'Active', 'theme-my-login' ) );
180
+ }
181
+
182
+ /**
183
+ * Handle AJAX deactivation of extension licenses.
184
+ *
185
+ * @since 7.1
186
+ */
187
+ function tml_admin_ajax_deactivate_extension_license() {
188
+ if ( ! $extension = tml_get_extension( tml_get_request_value( 'extension', 'post' ) ) ) {
189
+ tml_send_ajax_error( __( 'Invalid extension.', 'theme-my-login' ) );
190
+ }
191
+
192
+ $response = tml_deactivate_extension_license( $extension );
193
+
194
+ if ( is_wp_error( $response ) ) {
195
+ tml_send_ajax_error( $response->get_error_message() );
196
+ }
197
+
198
+ $extension->set_license_status();
199
+
200
+ tml_send_ajax_success( __( 'Inactive', 'theme-my-login' ) );
201
+ }
202
+
203
  /**
204
  * Check that all of the licenses are valid.
205
  *
admin/functions.php CHANGED
@@ -126,6 +126,7 @@ function tml_admin_enqueue_style_and_scripts() {
126
 
127
  wp_enqueue_script( 'theme-my-login-admin', THEME_MY_LOGIN_URL . "admin/assets/scripts/theme-my-login-admin$suffix.js", array( 'jquery', 'postbox' ), THEME_MY_LOGIN_VERSION );
128
  wp_localize_script( 'theme-my-login-admin', 'tmlAdmin', array(
 
129
  'interimLoginUrl' => site_url( add_query_arg( array(
130
  'interim-login' => 1,
131
  'wp_lang' => get_user_locale(),
126
 
127
  wp_enqueue_script( 'theme-my-login-admin', THEME_MY_LOGIN_URL . "admin/assets/scripts/theme-my-login-admin$suffix.js", array( 'jquery', 'postbox' ), THEME_MY_LOGIN_VERSION );
128
  wp_localize_script( 'theme-my-login-admin', 'tmlAdmin', array(
129
+ 'ajaxUrl' => admin_url( 'admin-ajax.php' ),
130
  'interimLoginUrl' => site_url( add_query_arg( array(
131
  'interim-login' => 1,
132
  'wp_lang' => get_user_locale(),
admin/hooks.php CHANGED
@@ -40,12 +40,13 @@ add_action( 'admin_init', 'tml_admin_update' );
40
  // Nav menus
41
  add_action( 'admin_head-nav-menus.php', 'tml_admin_add_nav_menu_meta_box', 10 );
42
 
 
 
 
 
43
  /**
44
  * Add filters
45
  */
46
 
47
  // General
48
  add_filter( 'plugin_action_links', 'tml_admin_filter_plugin_action_links', 10, 4 );
49
-
50
- // Nav menus
51
- add_filter( 'wp_edit_nav_menu_walker', 'tml_admin_filter_edit_nav_menu_walker', 99 );
40
  // Nav menus
41
  add_action( 'admin_head-nav-menus.php', 'tml_admin_add_nav_menu_meta_box', 10 );
42
 
43
+ // AJAX
44
+ add_action( 'wp_ajax_tml-activate-extension-license', 'tml_admin_ajax_activate_extension_license' );
45
+ add_action( 'wp_ajax_tml-deactivate-extension-license', 'tml_admin_ajax_deactivate_extension_license' );
46
+
47
  /**
48
  * Add filters
49
  */
50
 
51
  // General
52
  add_filter( 'plugin_action_links', 'tml_admin_filter_plugin_action_links', 10, 4 );
 
 
 
admin/settings.php CHANGED
@@ -460,39 +460,56 @@ function tml_admin_setting_callback_license_key_field( $args ) {
460
  $status = $extension->get_license_status();
461
 
462
  if ( 'valid' == $status ) {
463
- $input_style = sprintf( 'background-color: %s; border-color: %s;', '#b5e1b9', '#46b450' );
464
- $text_style = 'color: #46b450;';
465
- $text = __( 'Active', 'theme-my-login' );
466
  } elseif ( 'invalid' == $status ) {
467
- $input_style = sprintf( 'background-color: %s; border-color: %s;', '#f1adad', '#dc3232' );
468
- $text_style = 'color: #dc3232;';
469
- $text = __( 'Invalid', 'theme-my-login' );
470
  } else {
471
- $input_style = $text_style = '';
472
- $text = __( 'Inactive', 'theme-my-login' );
473
  }
474
 
475
- echo sprintf( '<input style="%1$s" type="text" name="%2$s" id="%2$s" value="%3$s" class="regular-text code" %4$s />',
476
- esc_attr( $input_style ),
477
  esc_attr( $args['label_for'] ),
478
  esc_attr( $license ),
 
479
  'valid' == $status ? 'readonly="readonly"' : ''
480
  ) . "\n";
481
 
482
- if ( empty( $license ) ) {
483
- return;
484
- }
 
 
 
 
 
 
 
 
485
 
486
- if ( 'valid' == $status ) {
487
- submit_button( __( 'Deactivate', 'theme-my-login' ), 'secondary large', 'tml_deactivate_license[' . $extension->get_name() . ']', false );
488
- } else {
489
- submit_button( __( 'Activate', 'theme-my-login' ), 'secondary large', 'tml_activate_license[' . $extension->get_name() . ']', false );
490
- }
491
- ?>
 
 
 
 
 
492
 
493
- <p style="<?php echo esc_attr( $text_style ); ?>"><?php echo esc_html( $text ); ?></p>
494
 
495
- <?php
 
 
 
 
 
496
  }
497
 
498
  /**
@@ -549,7 +566,7 @@ function tml_admin_save_ms_settings() {
549
  $whitelist_options = apply_filters( 'whitelist_options', array() );
550
 
551
  if ( ! isset( $whitelist_options[ $option_page ] ) ) {
552
- wp_die( __( '<strong>ERROR</strong>: options page not found.' ) );
553
  }
554
 
555
  foreach ( $whitelist_options[ $option_page ] as $option ) {
460
  $status = $extension->get_license_status();
461
 
462
  if ( 'valid' == $status ) {
463
+ $class = 'tml-license-valid';
464
+ $text = __( 'Active', 'theme-my-login' );
 
465
  } elseif ( 'invalid' == $status ) {
466
+ $class = 'tml-license-invalid';
467
+ $text = __( 'Invalid', 'theme-my-login' );
 
468
  } else {
469
+ $class = 'tml-license-inactive';
470
+ $text = __( 'Inactive', 'theme-my-login' );
471
  }
472
 
473
+ echo sprintf(
474
+ '<input type="text" name="%1$s" id="%1$s" value="%2$s" class="regular-text code tml-license-field %3$s" maxlength="32" %4$s />',
475
  esc_attr( $args['label_for'] ),
476
  esc_attr( $license ),
477
+ esc_attr( $class ),
478
  'valid' == $status ? 'readonly="readonly"' : ''
479
  ) . "\n";
480
 
481
+ submit_button(
482
+ __( 'Deactivate', 'theme-my-login' ),
483
+ 'secondary tml-license-button',
484
+ 'tml_deactivate_license[' . $extension->get_name() . ']',
485
+ false,
486
+ array(
487
+ 'data-action' => 'deactivate',
488
+ 'data-extension' => $extension->get_name(),
489
+ 'style' => ( empty( $license ) || 'valid' != $status ) ? 'display: none;' : '',
490
+ )
491
+ );
492
 
493
+ submit_button(
494
+ __( 'Activate', 'theme-my-login' ),
495
+ 'secondary tml-license-button',
496
+ 'tml_activate_license[' . $extension->get_name() . ']',
497
+ false,
498
+ array(
499
+ 'data-action' => 'activate',
500
+ 'data-extension' => $extension->get_name(),
501
+ 'style' => ( empty( $license ) || 'valid' == $status ) ? 'display: none;' : '',
502
+ )
503
+ );
504
 
505
+ echo '<div class="spinner"></div>';
506
 
507
+ printf(
508
+ '<p class="tml-license-status %1$s" style="%3$s">%2$s</p>',
509
+ esc_attr( $class ),
510
+ esc_html( $text ),
511
+ empty( $license ) ? 'display: none;' : ''
512
+ );
513
  }
514
 
515
  /**
566
  $whitelist_options = apply_filters( 'whitelist_options', array() );
567
 
568
  if ( ! isset( $whitelist_options[ $option_page ] ) ) {
569
+ wp_die( __( '<strong>Error</strong>: Options page not found.' ) );
570
  }
571
 
572
  foreach ( $whitelist_options[ $option_page ] as $option ) {
assets/scripts/theme-my-login.js CHANGED
@@ -1,3 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ( function ( $ ) {
2
 
3
  $( initFocus );
1
+ ( function ( $ ) {
2
+
3
+ $( '.tml' ).on( 'submit', 'form[data-ajax="1"]', function( e ) {
4
+ var form = $( this ),
5
+ input = form.find( ':input' ),
6
+ submit = form.find( ':submit' ),
7
+ container = $( e.delegateTarget ),
8
+ notices = container.find( '.tml-alerts' );
9
+
10
+ e.preventDefault();
11
+
12
+ notices.empty();
13
+
14
+ input.prop( 'readonly', true );
15
+ submit.prop( 'disabled', true );
16
+
17
+ $.ajax( {
18
+ data: form.serialize(),
19
+ method: form.attr( 'method' ) || 'get',
20
+ url: form.attr( 'action' )
21
+ } )
22
+ .always( function() {
23
+ input.prop( 'readonly', false );
24
+ submit.prop( 'disabled', false );
25
+ } )
26
+ .done( function( response ) {
27
+ if ( response.success ) {
28
+ if ( response.data.refresh ) {
29
+ location.reload( true );
30
+ } else if ( response.data.redirect ) {
31
+ location.href = response.data.redirect;
32
+ } else if ( response.data.notice ) {
33
+ notices.hide().html( response.data.notice ).fadeIn();
34
+ }
35
+ } else {
36
+ notices.hide().html( response.data.errors ).fadeIn();
37
+ }
38
+ } );
39
+ } );
40
+ } )( jQuery );
41
+
42
  ( function ( $ ) {
43
 
44
  $( initFocus );
assets/scripts/theme-my-login.min.js CHANGED
@@ -1 +1 @@
1
- !function(e){e(function(){var s,a;if(!themeMyLogin.action)return;switch(s=e("#user_login"),themeMyLogin.action){case"activate":(a=e("#key")).length&&a.focus();break;case"lostpassword":case"retrievepassword":case"register":s.focus();break;case"resetpass":case"rp":e("#pass1").focus();break;case"login":-1!=themeMyLogin.errors.indexOf("invalid_username")&&s.val(""),s.val()?e("#user_pass").focus():s.focus()}})}(jQuery),function(e){function s(){var s=e("#pass1").val(),a=e("#pass-strength-result");if(a.removeClass("short bad good strong"),s)switch(wp.passwordStrength.meter(s,wp.passwordStrength.userInputBlacklist(),s)){case-1:a.addClass("bad").html(pwsL10n.unknown);break;case 2:a.addClass("bad").html(pwsL10n.bad);break;case 3:a.addClass("good").html(pwsL10n.good);break;case 4:a.addClass("strong").html(pwsL10n.strong);break;case 5:a.addClass("short").html(pwsL10n.mismatch);break;default:a.addClass("short").html(pwsL10n.short)}else a.html("&nbsp;")}e(document).ready(function(){e("#pass1").val("").on("keyup paste",s)})}(jQuery);
1
+ !function(n){n(".tml").on("submit",'form[data-ajax="1"]',function(a){var e=n(this),s=e.find(":input"),t=e.find(":submit"),r=n(a.delegateTarget).find(".tml-alerts");a.preventDefault(),r.empty(),s.prop("readonly",!0),t.prop("disabled",!0),n.ajax({data:e.serialize(),method:e.attr("method")||"get",url:e.attr("action")}).always(function(){s.prop("readonly",!1),t.prop("disabled",!1)}).done(function(a){a.success?a.data.refresh?location.reload(!0):a.data.redirect?location.href=a.data.redirect:a.data.notice&&r.hide().html(a.data.notice).fadeIn():r.hide().html(a.data.errors).fadeIn()})})}(jQuery),function(s){s(function(){var a,e;if(!themeMyLogin.action)return;switch(a=s("#user_login"),themeMyLogin.action){case"activate":(e=s("#key")).length&&e.focus();break;case"lostpassword":case"retrievepassword":case"register":a.focus();break;case"resetpass":case"rp":s("#pass1").focus();break;case"login":-1!=themeMyLogin.errors.indexOf("invalid_username")&&a.val(""),a.val()?s("#user_pass").focus():a.focus()}})}(jQuery),function(s){function a(){var a=s("#pass1").val(),e=s("#pass-strength-result");if(e.removeClass("short bad good strong"),a)switch(wp.passwordStrength.meter(a,wp.passwordStrength.userInputBlacklist(),a)){case-1:e.addClass("bad").html(pwsL10n.unknown);break;case 2:e.addClass("bad").html(pwsL10n.bad);break;case 3:e.addClass("good").html(pwsL10n.good);break;case 4:e.addClass("strong").html(pwsL10n.strong);break;case 5:e.addClass("short").html(pwsL10n.mismatch);break;default:e.addClass("short").html(pwsL10n.short)}else e.html("&nbsp;")}s(document).ready(function(){s("#pass1").val("").on("keyup paste",a)})}(jQuery);
assets/styles/theme-my-login.css CHANGED
@@ -3,8 +3,7 @@
3
  }
4
 
5
  .tml * {
6
- -webkit-box-sizing: border-box;
7
- box-sizing: border-box;
8
  }
9
 
10
  .tml .tml-field-wrap {
@@ -43,8 +42,7 @@
43
  .tml .tml-success,
44
  .tml .tml-action-confirmaction .success {
45
  border-left: 4px solid #00a0d2;
46
- -webkit-box-shadow: 1px 1px 2px 1px rgba(0, 0, 0, 0.1);
47
- box-shadow: 1px 1px 2px 1px rgba(0, 0, 0, 0.1);
48
  display: block;
49
  margin: 0 0 1em;
50
  padding: 0.75em;
3
  }
4
 
5
  .tml * {
6
+ box-sizing: border-box;
 
7
  }
8
 
9
  .tml .tml-field-wrap {
42
  .tml .tml-success,
43
  .tml .tml-action-confirmaction .success {
44
  border-left: 4px solid #00a0d2;
45
+ box-shadow: 1px 1px 2px 1px rgba(0, 0, 0, 0.1);
 
46
  display: block;
47
  margin: 0 0 1em;
48
  padding: 0.75em;
assets/styles/theme-my-login.min.css CHANGED
@@ -1 +1 @@
1
- .tml{font-size:1em}.tml *{-webkit-box-sizing:border-box;box-sizing:border-box}.tml .tml-field-wrap{margin-bottom:1em}.tml .tml-label{display:block;margin:.5em 0}.tml .tml-checkbox+.tml-label{display:inline}.tml .tml-field{width:100%}.tml .tml-description{display:block;font-size:.85em;font-style:italic;margin:.5em 0}.tml .tml-errors,.tml .tml-messages{list-style:none;margin:0;padding:0}.tml .tml-action-confirmaction .success,.tml .tml-error,.tml .tml-message,.tml .tml-success{border-left:4px solid #00a0d2;-webkit-box-shadow:1px 1px 2px 1px rgba(0,0,0,.1);box-shadow:1px 1px 2px 1px rgba(0,0,0,.1);display:block;margin:0 0 1em;padding:.75em}.tml .tml-error{border-left-color:#dc3232}.tml .tml-action-confirmaction .success,.tml .tml-success{border-left-color:#46b450}#pass-strength-result{background-color:#eee;border:1px solid #ddd;color:#23282d;font-weight:700;opacity:0;margin-bottom:1em;padding:.5em}#pass-strength-result.strong{background-color:#c1e1b9;border-color:#83c373;opacity:1}#pass-strength-result.good{background-color:#ffe399;border-color:#ffc733;opacity:1}#pass-strength-result.bad{background-color:#fbc5a9;border-color:#f78b53;opacity:1}#pass-strength-result.short{background-color:#f1adad;border-color:#e35b5b;opacity:1}
1
+ .tml{font-size:1em}.tml *{box-sizing:border-box}.tml .tml-field-wrap{margin-bottom:1em}.tml .tml-label{display:block;margin:.5em 0}.tml .tml-checkbox+.tml-label{display:inline}.tml .tml-field{width:100%}.tml .tml-description{display:block;font-size:.85em;font-style:italic;margin:.5em 0}.tml .tml-errors,.tml .tml-messages{list-style:none;margin:0;padding:0}.tml .tml-action-confirmaction .success,.tml .tml-error,.tml .tml-message,.tml .tml-success{border-left:4px solid #00a0d2;box-shadow:1px 1px 2px 1px rgba(0,0,0,.1);display:block;margin:0 0 1em;padding:.75em}.tml .tml-error{border-left-color:#dc3232}.tml .tml-action-confirmaction .success,.tml .tml-success{border-left-color:#46b450}#pass-strength-result{background-color:#eee;border:1px solid #ddd;color:#23282d;font-weight:700;opacity:0;margin-bottom:1em;padding:.5em}#pass-strength-result.strong{background-color:#c1e1b9;border-color:#83c373;opacity:1}#pass-strength-result.good{background-color:#ffe399;border-color:#ffc733;opacity:1}#pass-strength-result.bad{background-color:#fbc5a9;border-color:#f78b53;opacity:1}#pass-strength-result.short{background-color:#f1adad;border-color:#e35b5b;opacity:1}
includes/actions.php CHANGED
@@ -14,11 +14,21 @@
14
  */
15
  function tml_register_default_actions() {
16
 
 
 
 
 
 
 
 
 
 
17
  // Login
18
  tml_register_action( 'login', array(
19
  'title' => __( 'Log In' ),
20
  'slug' => 'login',
21
  'callback' => 'tml_login_handler',
 
22
  'show_on_forms' => __( 'Log in' ),
23
  'show_nav_menu_item' => ! is_user_logged_in(),
24
  ) );
@@ -38,6 +48,7 @@ function tml_register_default_actions() {
38
  'title' => __( 'Register' ),
39
  'slug' => 'register',
40
  'callback' => 'tml_registration_handler',
 
41
  'show_on_forms' => (bool) get_option( 'users_can_register' ),
42
  'show_nav_menu_item' => ! is_user_logged_in(),
43
  ) );
@@ -47,6 +58,7 @@ function tml_register_default_actions() {
47
  'title' => __( 'Lost Password' ),
48
  'slug' => 'lostpassword',
49
  'callback' => 'tml_lost_password_handler',
 
50
  'network' => true,
51
  'show_on_forms' => __( 'Lost your password?' ),
52
  'show_in_nav_menus' => false,
@@ -259,11 +271,26 @@ function tml_action_has_page( $action = '' ) {
259
  return false;
260
  }
261
 
262
- if ( ! $page = get_page_by_path( tml_get_action_slug( $action ) ) ) {
263
- return false;
 
 
 
 
 
 
 
 
 
 
 
264
  }
265
 
266
- return $page;
 
 
 
 
267
  }
268
 
269
  /**
@@ -333,12 +360,33 @@ function tml_action_handler() {
333
  /** This action is documented in wp-login.php */
334
  do_action( 'login_form_' . tml_get_request_value( 'action' ) );
335
 
336
- /**
337
- * Fires when a TML action is being requested.
338
- *
339
- * @since 7.0.3
340
- */
341
- do_action( 'tml_action_' . tml_get_action()->get_name() );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
342
  }
343
 
344
  /**
@@ -348,13 +396,18 @@ function tml_action_handler() {
348
  */
349
  function tml_login_handler() {
350
 
 
 
 
 
 
351
  $errors = new WP_Error;
352
 
353
  $secure_cookie = '';
354
 
355
  // If the user wants ssl but the session is not ssl, force a secure cookie.
356
  if ( ! empty( $_POST['log'] ) && ! force_ssl_admin() ) {
357
- $user_name = sanitize_user( $_POST['log'] );
358
  $user = get_user_by( 'login', $user_name );
359
 
360
  if ( ! $user && strpos( $user_name, '@' ) ) {
@@ -386,15 +439,15 @@ function tml_login_handler() {
386
  if ( empty( $_COOKIE[ LOGGED_IN_COOKIE ] ) ) {
387
  if ( headers_sent() ) {
388
  $user = new WP_Error( 'test_cookie', sprintf(
389
- __( '<strong>ERROR</strong>: Cookies are blocked due to unexpected output. For help, please see <a href="%1$s">this documentation</a> or try the <a href="%2$s">support forums</a>.' ),
390
- __( 'https://wordpress.org/support/article/cookies' ),
391
- __( 'https://wordpress.org/support/' )
392
  )
393
  );
394
  } elseif ( isset( $_POST['testcookie'] ) && empty( $_COOKIE[ TEST_COOKIE ] ) ) {
395
  // If cookies are disabled we can't log in even with a valid user+pass
396
  $user = new WP_Error( 'test_cookie', sprintf(
397
- __( '<strong>ERROR</strong>: Cookies are blocked or not supported by your browser. You must <a href="%s">enable cookies</a> to use WordPress.' ),
398
  __( 'https://wordpress.org/support/article/cookies#enable-cookies-your-browser' )
399
  )
400
  );
@@ -405,7 +458,7 @@ function tml_login_handler() {
405
 
406
  if ( ! is_wp_error( $user ) && ! $reauth ) {
407
 
408
- if ( ( empty( $redirect_to ) || $redirect_to == 'wp-admin/' || $redirect_to == admin_url() ) ) {
409
 
410
  // If the user doesn't belong to a blog, send them to user admin. If the user can't edit posts, send them to their profile.
411
  if ( is_multisite() && ! get_active_blog_for_user( $user->ID ) && ! is_super_admin( $user->ID ) ) {
@@ -415,15 +468,27 @@ function tml_login_handler() {
415
  $redirect_to = get_dashboard_url( $user->ID );
416
 
417
  } elseif ( ! $user->has_cap( 'edit_posts' ) ) {
418
- $redirect_to = $user->has_cap( 'read' ) ? admin_url( 'profile.php' ) : home_url();
419
  }
420
 
421
- wp_redirect( $redirect_to );
422
- exit;
 
 
 
 
 
 
423
  }
424
 
425
- wp_safe_redirect( $redirect_to );
426
- exit;
 
 
 
 
 
 
427
  } else {
428
  $errors = $user;
429
  }
@@ -473,6 +538,12 @@ function tml_login_handler() {
473
  if ( $reauth ) {
474
  wp_clear_auth_cookie();
475
  }
 
 
 
 
 
 
476
  }
477
 
478
  /**
@@ -489,9 +560,16 @@ function tml_logout_handler() {
489
  wp_logout();
490
 
491
  if ( ! empty( $_REQUEST['redirect_to'] ) ) {
492
- $redirect_to = $requested_redirect_to = $_REQUEST['redirect_to'];
 
493
  } else {
494
- $redirect_to = site_url( 'wp-login.php?loggedout=true' );
 
 
 
 
 
 
495
  $requested_redirect_to = '';
496
  }
497
 
@@ -509,7 +587,10 @@ function tml_logout_handler() {
509
  */
510
  function tml_registration_handler() {
511
 
512
- if ( is_multisite() ) {
 
 
 
513
  /** This filter is documented in wp-login.php */
514
  $signup_location = apply_filters( 'wp_signup_location', network_site_url( 'wp-signup.php' ) );
515
 
@@ -518,13 +599,20 @@ function tml_registration_handler() {
518
  }
519
 
520
  if ( ! get_option( 'users_can_register' ) ) {
521
- wp_redirect( site_url( 'wp-login.php?registration=disabled' ) );
522
- exit;
 
 
 
 
 
 
 
523
  }
524
 
525
  if ( tml_is_post_request() ) {
526
- $user_login = isset( $_POST['user_login'] ) ? $_POST['user_login'] : '';
527
- $user_email = isset( $_POST['user_email'] ) ? $_POST['user_email'] : '';
528
  $user_id = register_new_user( $user_login, $user_email );
529
  if ( ! is_wp_error( $user_id ) ) {
530
  $redirect_to = ! empty( $_POST['redirect_to'] ) ? $_POST['redirect_to'] : site_url( 'wp-login.php?checkemail=registered' );
@@ -539,10 +627,21 @@ function tml_registration_handler() {
539
  */
540
  $redirect_to = apply_filters( 'tml_registration_redirect', $redirect_to, get_userdata( $user_id ) );
541
 
542
- wp_safe_redirect( $redirect_to );
543
- exit;
 
 
 
 
 
 
544
  } else {
545
  tml_set_errors( $user_id );
 
 
 
 
 
546
  }
547
  }
548
  }
@@ -557,11 +656,23 @@ function tml_lost_password_handler() {
557
  if ( tml_is_post_request() ) {
558
  $errors = tml_retrieve_password();
559
  if ( ! is_wp_error( $errors ) ) {
560
- $redirect_to = ! empty( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : site_url( 'wp-login.php?checkemail=confirm' );
561
- wp_safe_redirect( $redirect_to );
562
- exit;
 
 
 
 
 
 
 
563
  } else {
564
  tml_set_errors( $errors );
 
 
 
 
 
565
  }
566
  }
567
 
@@ -572,6 +683,9 @@ function tml_lost_password_handler() {
572
  tml_add_error( 'expiredkey', __( 'Your password reset link has expired. Please request a new link below.' ) );
573
  }
574
  }
 
 
 
575
  }
576
 
577
  /**
14
  */
15
  function tml_register_default_actions() {
16
 
17
+ // Dashboard
18
+ tml_register_action( 'dashboard', array(
19
+ 'title' => __( 'Dashboard' ),
20
+ 'slug' => 'dashboard',
21
+ 'callback' => 'tml_dashboard_handler',
22
+ 'show_on_forms' => false,
23
+ 'show_nav_menu_item' => is_user_logged_in(),
24
+ ) );
25
+
26
  // Login
27
  tml_register_action( 'login', array(
28
  'title' => __( 'Log In' ),
29
  'slug' => 'login',
30
  'callback' => 'tml_login_handler',
31
+ 'ajax_callback' => 'tml_login_handler',
32
  'show_on_forms' => __( 'Log in' ),
33
  'show_nav_menu_item' => ! is_user_logged_in(),
34
  ) );
48
  'title' => __( 'Register' ),
49
  'slug' => 'register',
50
  'callback' => 'tml_registration_handler',
51
+ 'ajax_callback' => 'tml_registration_handler',
52
  'show_on_forms' => (bool) get_option( 'users_can_register' ),
53
  'show_nav_menu_item' => ! is_user_logged_in(),
54
  ) );
58
  'title' => __( 'Lost Password' ),
59
  'slug' => 'lostpassword',
60
  'callback' => 'tml_lost_password_handler',
61
+ 'ajax_callback' => 'tml_lost_password_handler',
62
  'network' => true,
63
  'show_on_forms' => __( 'Lost your password?' ),
64
  'show_in_nav_menus' => false,
271
  return false;
272
  }
273
 
274
+ $pages = wp_cache_get( 'tml_pages' );
275
+ if ( false === $pages ) {
276
+ $pages = get_posts( [
277
+ 'post_name__in' => array_map( 'tml_get_action_slug', tml_get_actions() ),
278
+ 'post_type' => 'page',
279
+ 'nopaging' => true,
280
+ 'update_post_meta_cache' => false,
281
+ 'update_post_term_cache' => false,
282
+ ] );
283
+
284
+ if ( ! empty( $pages ) ) {
285
+ wp_cache_set( 'tml_pages', $pages );
286
+ }
287
  }
288
 
289
+ if ( $pages = wp_list_filter( $pages, [ 'post_name' => $action->get_slug() ] ) ) {
290
+ return reset( $pages );
291
+ }
292
+
293
+ return false;
294
  }
295
 
296
  /**
360
  /** This action is documented in wp-login.php */
361
  do_action( 'login_form_' . tml_get_request_value( 'action' ) );
362
 
363
+ if ( tml_is_ajax_request() ) {
364
+ /**
365
+ * Fires when a TML action is being requested.
366
+ *
367
+ * @since 7.1
368
+ */
369
+ do_action( 'tml_action_ajax_' . tml_get_action()->get_name() );
370
+ } else {
371
+ /**
372
+ * Fires when a TML action is being requested.
373
+ *
374
+ * @since 7.0.3
375
+ */
376
+ do_action( 'tml_action_' . tml_get_action()->get_name() );
377
+ }
378
+ }
379
+
380
+ /**
381
+ * Handle the 'dashboard' action.
382
+ *
383
+ * @since 7.1
384
+ */
385
+ function tml_dashboard_handler() {
386
+ if ( ! is_user_logged_in() ) {
387
+ wp_redirect( wp_login_url( $_SERVER['REQUEST_URI'] ) );
388
+ exit;
389
+ }
390
  }
391
 
392
  /**
396
  */
397
  function tml_login_handler() {
398
 
399
+ if ( is_user_logged_in() ) {
400
+ wp_redirect( tml_get_action_url( 'dashboard' ) );
401
+ exit;
402
+ }
403
+
404
  $errors = new WP_Error;
405
 
406
  $secure_cookie = '';
407
 
408
  // If the user wants ssl but the session is not ssl, force a secure cookie.
409
  if ( ! empty( $_POST['log'] ) && ! force_ssl_admin() ) {
410
+ $user_name = sanitize_user( wp_unslash( $_POST['log'] ) );
411
  $user = get_user_by( 'login', $user_name );
412
 
413
  if ( ! $user && strpos( $user_name, '@' ) ) {
439
  if ( empty( $_COOKIE[ LOGGED_IN_COOKIE ] ) ) {
440
  if ( headers_sent() ) {
441
  $user = new WP_Error( 'test_cookie', sprintf(
442
+ __( '<strong>Error</strong>: Cookies are blocked due to unexpected output. For help, please see <a href="%1$s">this documentation</a> or try the <a href="%2$s">support forums</a>.' ),
443
+ __( 'https://wordpress.org/support/article/cookies/' ),
444
+ __( 'https://wordpress.org/support/forums/' )
445
  )
446
  );
447
  } elseif ( isset( $_POST['testcookie'] ) && empty( $_COOKIE[ TEST_COOKIE ] ) ) {
448
  // If cookies are disabled we can't log in even with a valid user+pass
449
  $user = new WP_Error( 'test_cookie', sprintf(
450
+ __( '<strong>Error</strong>: Cookies are blocked or not supported by your browser. You must <a href="%s">enable cookies</a> to use WordPress.' ),
451
  __( 'https://wordpress.org/support/article/cookies#enable-cookies-your-browser' )
452
  )
453
  );
458
 
459
  if ( ! is_wp_error( $user ) && ! $reauth ) {
460
 
461
+ if ( ( empty( $redirect_to ) || 'wp-admin/' == $redirect_to || admin_url() == $redirect_to ) ) {
462
 
463
  // If the user doesn't belong to a blog, send them to user admin. If the user can't edit posts, send them to their profile.
464
  if ( is_multisite() && ! get_active_blog_for_user( $user->ID ) && ! is_super_admin( $user->ID ) ) {
468
  $redirect_to = get_dashboard_url( $user->ID );
469
 
470
  } elseif ( ! $user->has_cap( 'edit_posts' ) ) {
471
+ $redirect_to = tml_get_action_url( 'dashboard' );
472
  }
473
 
474
+ if ( tml_is_ajax_request() ) {
475
+ tml_send_ajax_success( array(
476
+ 'redirect' => $redirect_to,
477
+ ) );
478
+ } else {
479
+ wp_redirect( $redirect_to );
480
+ exit;
481
+ }
482
  }
483
 
484
+ if ( tml_is_ajax_request() ) {
485
+ tml_send_ajax_success( array(
486
+ 'redirect' => tml_validate_redirect( $redirect_to ),
487
+ ) );
488
+ } else {
489
+ wp_safe_redirect( $redirect_to );
490
+ exit;
491
+ }
492
  } else {
493
  $errors = $user;
494
  }
538
  if ( $reauth ) {
539
  wp_clear_auth_cookie();
540
  }
541
+
542
+ if ( tml_is_ajax_request() ) {
543
+ tml_send_ajax_error( array(
544
+ 'errors' => tml_get_form()->render_errors(),
545
+ ) );
546
+ }
547
  }
548
 
549
  /**
560
  wp_logout();
561
 
562
  if ( ! empty( $_REQUEST['redirect_to'] ) ) {
563
+ $redirect_to = $_REQUEST['redirect_to'];
564
+ $requested_redirect_to = $redirect_to;
565
  } else {
566
+ $redirect_to = add_query_arg(
567
+ array(
568
+ 'loggedout' => 'true',
569
+ 'wp_lang' => get_user_locale( $user ),
570
+ ),
571
+ wp_login_url()
572
+ );
573
  $requested_redirect_to = '';
574
  }
575
 
587
  */
588
  function tml_registration_handler() {
589
 
590
+ if ( is_user_logged_in() ) {
591
+ wp_redirect( tml_get_action_url( 'dashboard' ) );
592
+ exit;
593
+ } elseif ( is_multisite() ) {
594
  /** This filter is documented in wp-login.php */
595
  $signup_location = apply_filters( 'wp_signup_location', network_site_url( 'wp-signup.php' ) );
596
 
599
  }
600
 
601
  if ( ! get_option( 'users_can_register' ) ) {
602
+ if ( tml_is_ajax_request() ) {
603
+ tml_add_error( 'registerdisabled', __( 'User registration is currently not allowed.' ) );
604
+ tml_send_ajax_error( array(
605
+ 'errors' => tml_get_form()->render_errors(),
606
+ ) );
607
+ } else {
608
+ wp_redirect( site_url( 'wp-login.php?registration=disabled' ) );
609
+ exit;
610
+ }
611
  }
612
 
613
  if ( tml_is_post_request() ) {
614
+ $user_login = tml_get_request_value( 'user_login', 'post' );
615
+ $user_email = tml_get_request_value( 'user_email', 'post' );
616
  $user_id = register_new_user( $user_login, $user_email );
617
  if ( ! is_wp_error( $user_id ) ) {
618
  $redirect_to = ! empty( $_POST['redirect_to'] ) ? $_POST['redirect_to'] : site_url( 'wp-login.php?checkemail=registered' );
627
  */
628
  $redirect_to = apply_filters( 'tml_registration_redirect', $redirect_to, get_userdata( $user_id ) );
629
 
630
+ if ( tml_is_ajax_request() ) {
631
+ wp_send_json_success( array(
632
+ 'redirect' => tml_validate_redirect( $redirect_to ),
633
+ ) );
634
+ } else {
635
+ wp_safe_redirect( $redirect_to );
636
+ exit;
637
+ }
638
  } else {
639
  tml_set_errors( $user_id );
640
+ if ( tml_is_ajax_request() ) {
641
+ tml_send_ajax_error( array(
642
+ 'errors' => tml_get_form()->render_errors(),
643
+ ) );
644
+ }
645
  }
646
  }
647
  }
656
  if ( tml_is_post_request() ) {
657
  $errors = tml_retrieve_password();
658
  if ( ! is_wp_error( $errors ) ) {
659
+ if ( tml_is_ajax_request() ) {
660
+ tml_add_error( 'confirm', __( 'Check your email for the confirmation link.' ), 'message' );
661
+ tml_send_ajax_success( array(
662
+ 'notice' => tml_get_form()->render_errors(),
663
+ ) );
664
+ } else {
665
+ $redirect_to = ! empty( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : site_url( 'wp-login.php?checkemail=confirm' );
666
+ wp_safe_redirect( $redirect_to );
667
+ exit;
668
+ }
669
  } else {
670
  tml_set_errors( $errors );
671
+ if ( tml_is_ajax_request() ) {
672
+ tml_send_ajax_error( array(
673
+ 'errors' => tml_get_form()->render_errors(),
674
+ ) );
675
+ }
676
  }
677
  }
678
 
683
  tml_add_error( 'expiredkey', __( 'Your password reset link has expired. Please request a new link below.' ) );
684
  }
685
  }
686
+
687
+ /** This filter is documented in wp-login.php */
688
+ do_action( 'lost_password', tml_get_errors() );
689
  }
690
 
691
  /**
includes/class-theme-my-login-action.php CHANGED
@@ -42,6 +42,13 @@ class Theme_My_Login_Action {
42
  */
43
  protected $callback;
44
 
 
 
 
 
 
 
 
45
  /**
46
  * Whether this action is a network action or not.
47
  *
@@ -96,6 +103,7 @@ class Theme_My_Login_Action {
96
  * @type string $title The action title.
97
  * @type string $slug The action slug.
98
  * @type callable $callback The action callback to fire when accessed.
 
99
  * @type bool|string $show_on_forms Whether a link to the action should be shown on forms or not.
100
  * @type bool $show_in_widget Whether this action should be selectable in the widget or not.
101
  * @type bool $show_in_nav_menus Whether this action should be available for use in nav menus or not.
@@ -111,6 +119,7 @@ class Theme_My_Login_Action {
111
  'title' => '',
112
  'slug' => '',
113
  'callback' => '',
 
114
  'network' => false,
115
  'show_on_forms' => true,
116
  'show_in_widget' => true,
@@ -125,6 +134,7 @@ class Theme_My_Login_Action {
125
  $this->set_title( $args['title'] );
126
  $this->set_slug( $args['slug'] );
127
  $this->set_callback( $args['callback'] );
 
128
 
129
  $this->network = (bool) $args['network'];
130
  $this->show_on_forms = $args['show_on_forms'];
@@ -230,6 +240,50 @@ class Theme_My_Login_Action {
230
  }
231
  }
232
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
233
  /**
234
  * Get the action slug.
235
  *
42
  */
43
  protected $callback;
44
 
45
+ /**
46
+ * The AJAX action handler.
47
+ *
48
+ * @var callable
49
+ */
50
+ protected $ajax_callback;
51
+
52
  /**
53
  * Whether this action is a network action or not.
54
  *
103
  * @type string $title The action title.
104
  * @type string $slug The action slug.
105
  * @type callable $callback The action callback to fire when accessed.
106
+ * @type callable $ajax_callback The action callback to fire when accessed via AJAX.
107
  * @type bool|string $show_on_forms Whether a link to the action should be shown on forms or not.
108
  * @type bool $show_in_widget Whether this action should be selectable in the widget or not.
109
  * @type bool $show_in_nav_menus Whether this action should be available for use in nav menus or not.
119
  'title' => '',
120
  'slug' => '',
121
  'callback' => '',
122
+ 'ajax_callback' => '',
123
  'network' => false,
124
  'show_on_forms' => true,
125
  'show_in_widget' => true,
134
  $this->set_title( $args['title'] );
135
  $this->set_slug( $args['slug'] );
136
  $this->set_callback( $args['callback'] );
137
+ $this->set_ajax_callback( $args['ajax_callback'] );
138
 
139
  $this->network = (bool) $args['network'];
140
  $this->show_on_forms = $args['show_on_forms'];
240
  }
241
  }
242
 
243
+ /**
244
+ * Get the action AJAX callback.
245
+ *
246
+ * @since 7.1
247
+ *
248
+ * @return callable The action AJAX callback.
249
+ */
250
+ public function get_ajax_callback() {
251
+ return $this->ajax_callback;
252
+ }
253
+
254
+ /**
255
+ * Set the action AJAX callback.
256
+ *
257
+ * @since 7.1
258
+ *
259
+ * @param callable $ajax_callback The action callback.
260
+ */
261
+ public function set_ajax_callback( $ajax_callback ) {
262
+ $this->ajax_callback = $ajax_callback;
263
+ }
264
+
265
+ /**
266
+ * Adds the AJAX callback to the proper hook.
267
+ *
268
+ * @since 7.1
269
+ */
270
+ public function add_ajax_callback_hook() {
271
+ if ( $ajax_callback = $this->get_ajax_callback() ) {
272
+ add_action( 'tml_action_ajax_' . $this->get_name(), $ajax_callback, 15 );
273
+ }
274
+ }
275
+
276
+ /**
277
+ * Removes the AJAX callback from the proper hook.
278
+ *
279
+ * @since 7.1
280
+ */
281
+ public function remove_ajax_callback_hook() {
282
+ if ( $ajax_callback = $this->get_ajax_callback() ) {
283
+ remove_action( 'tml_action_ajax_' . $this->get_name(), $ajax_callback, 15 );
284
+ }
285
+ }
286
+
287
  /**
288
  * Get the action slug.
289
  *
includes/class-theme-my-login-extension.php CHANGED
@@ -326,6 +326,17 @@ abstract class Theme_My_Login_Extension {
326
  return get_site_option( $this->license_key_option );
327
  }
328
 
 
 
 
 
 
 
 
 
 
 
 
329
  /**
330
  * Get the name of the license status option for the extension.
331
  *
326
  return get_site_option( $this->license_key_option );
327
  }
328
 
329
+ /**
330
+ * Set the license key for the extension.
331
+ *
332
+ * @since 7.1
333
+ *
334
+ * @param string $key The license key.
335
+ */
336
+ public function set_license_key( $key = '' ) {
337
+ update_site_option( $this->license_key_option, $key );
338
+ }
339
+
340
  /**
341
  * Get the name of the license status option for the extension.
342
  *
includes/class-theme-my-login-form-field.php CHANGED
@@ -657,7 +657,7 @@ class Theme_My_Login_Form_Field {
657
  $option .= ' checked="checked"';
658
  }
659
  $option .= '>' . "\n";
660
- $option .= '<label class="tml-label" for="' . $id . '">' . esc_html( $label ) . "</label>\n";
661
 
662
  $options[] = $option;
663
  }
@@ -689,6 +689,13 @@ class Theme_My_Login_Form_Field {
689
  $output .= $args['control_after'];
690
  break;
691
 
 
 
 
 
 
 
 
692
  default :
693
  $output .= $label;
694
  $output .= $error;
657
  $option .= ' checked="checked"';
658
  }
659
  $option .= '>' . "\n";
660
+ $option .= '<label class="tml-label" for="' . $id . '">' . $label . "</label>\n";
661
 
662
  $options[] = $option;
663
  }
689
  $output .= $args['control_after'];
690
  break;
691
 
692
+ case 'button' :
693
+ case 'submit' :
694
+ $output .= $args['control_before'];
695
+ $output .= '<button name="' . $this->get_name() . '" type="' . $this->get_type() . '"' . $attributes . '>' . $this->get_value() . "</button>\n";
696
+ $output .= $args['control_after'];
697
+ break;
698
+
699
  default :
700
  $output .= $label;
701
  $output .= $error;
includes/class-theme-my-login-form.php CHANGED
@@ -586,7 +586,7 @@ class Theme_My_Login_Form {
586
  */
587
  $output = apply_filters( 'tml_before_form', $output, $this->name, $this );
588
 
589
- $output .= $this->render_errors();
590
 
591
  $output .= '<form name="' . esc_attr( $this->get_name() ) . '" action="' . esc_url( $this->get_action() ) . '" method="' . esc_attr( $this->get_method() ) . '"';
592
  foreach ( $this->get_attributes() as $key => $value ) {
586
  */
587
  $output = apply_filters( 'tml_before_form', $output, $this->name, $this );
588
 
589
+ $output .= '<div class="tml-alerts">' . $this->render_errors() . '</div>';
590
 
591
  $output .= '<form name="' . esc_attr( $this->get_name() ) . '" action="' . esc_url( $this->get_action() ) . '" method="' . esc_attr( $this->get_method() ) . '"';
592
  foreach ( $this->get_attributes() as $key => $value ) {
includes/class-theme-my-login-widget.php CHANGED
@@ -83,20 +83,24 @@ class Theme_My_Login_Widget extends WP_Widget {
83
  *
84
  * @param array $user_links The links shown in the widget when logged in.
85
  */
86
- $user_links = apply_filters( 'tml_widget_user_links', array(
87
- 'dashboard' => array(
88
- 'title' => __( 'Dashboard' ),
89
- 'url' => admin_url(),
 
 
 
 
90
  ),
91
- 'profile' => array(
92
- 'title' => __( 'Profile', 'theme-my-login' ),
93
- 'url' => admin_url( 'profile.php' ),
94
  ),
95
- 'logout' => array(
96
- 'title' => __( 'Log Out' ),
97
- 'url' => wp_logout_url(),
98
  ),
99
- ) );
100
  ?>
101
 
102
  <div class="tml tml-user-panel">
83
  *
84
  * @param array $user_links The links shown in the widget when logged in.
85
  */
86
+ $user_links = apply_filters( 'tml_widget_user_links', array_filter( array(
87
+ 'site_admin' => current_user_can( 'edit_posts' ) ? array(
88
+ 'title' => __( 'Site Admin' ),
89
+ 'url' => admin_url(),
90
+ ) : false,
91
+ 'dashboard' => array(
92
+ 'title' => __( 'Dashboard' ),
93
+ 'url' => tml_get_action_url( 'dashboard' ),
94
  ),
95
+ 'profile' => array(
96
+ 'title' => __( 'Edit My Profile' ),
97
+ 'url' => admin_url( 'profile.php' ),
98
  ),
99
+ 'logout' => array(
100
+ 'title' => __( 'Log Out' ),
101
+ 'url' => wp_logout_url(),
102
  ),
103
+ ) ) );
104
  ?>
105
 
106
  <div class="tml tml-user-panel">
includes/class-theme-my-login.php CHANGED
@@ -76,6 +76,7 @@ final class Theme_My_Login {
76
  $this->actions[ $action->get_name() ] = $action;
77
 
78
  $action->add_callback_hook();
 
79
 
80
  /**
81
  * Fires after registering an action.
76
  $this->actions[ $action->get_name() ] = $action;
77
 
78
  $action->add_callback_hook();
79
+ $action->add_ajax_callback_hook();
80
 
81
  /**
82
  * Fires after registering an action.
includes/compat.php CHANGED
@@ -18,29 +18,30 @@
18
  * @return True on success, WP_Error on error.
19
  */
20
  function tml_retrieve_password() {
21
- $errors = new WP_Error();
 
22
 
23
  if ( empty( $_POST['user_login'] ) || ! is_string( $_POST['user_login'] ) ) {
24
- $errors->add( 'empty_username', __( '<strong>ERROR</strong>: Enter a username or email address.' ) );
25
  } elseif ( strpos( $_POST['user_login'], '@' ) ) {
26
  $user_data = get_user_by( 'email', trim( wp_unslash( $_POST['user_login'] ) ) );
27
  if ( empty( $user_data ) ) {
28
- $errors->add( 'invalid_email', __( '<strong>ERROR</strong>: There is no account with that username or email address.' ) );
29
  }
30
  } else {
31
- $login = trim( $_POST['user_login'] );
32
  $user_data = get_user_by( 'login', $login );
33
  }
34
 
35
  /** This action is documented in wp-login.php */
36
- do_action( 'lostpassword_post', $errors );
37
 
38
  if ( $errors->get_error_code() ) {
39
  return $errors;
40
  }
41
 
42
  if ( ! $user_data ) {
43
- $errors->add( 'invalidcombo', __( '<strong>ERROR</strong>: There is no account with that username or email address.' ) );
44
  return $errors;
45
  }
46
 
@@ -88,7 +89,7 @@ function tml_retrieve_password_notification( $user, $key ) {
88
  $message .= sprintf( __( 'Username: %s' ), $user->user_login ) . "\r\n\r\n";
89
  $message .= __( 'If this was a mistake, just ignore this email and nothing will happen.' ) . "\r\n\r\n";
90
  $message .= __( 'To reset your password, visit the following address:' ) . "\r\n\r\n";
91
- $message .= '<' . network_site_url( "wp-login.php?action=rp&key=$key&login=" . rawurlencode( $user->user_login ), 'login' ) . ">\r\n";
92
 
93
  /* translators: Password reset email subject. %s: Site name */
94
  $title = sprintf( __( '[%s] Password Reset' ), $site_name );
@@ -151,6 +152,9 @@ function tml_retrieve_password_notification( $user, $key ) {
151
  $retrieve_password_email['message'],
152
  $retrieve_password_email['headers']
153
  ) ) {
154
- wp_die( __( 'The email could not be sent.' ) . "<br />\n" . __( 'Possible reason: your host may have disabled the mail() function.' ) );
 
 
 
155
  }
156
  }
18
  * @return True on success, WP_Error on error.
19
  */
20
  function tml_retrieve_password() {
21
+ $errors = new WP_Error();
22
+ $user_data = false;
23
 
24
  if ( empty( $_POST['user_login'] ) || ! is_string( $_POST['user_login'] ) ) {
25
+ $errors->add( 'empty_username', __( '<strong>Error</strong>: Enter a username or email address.' ) );
26
  } elseif ( strpos( $_POST['user_login'], '@' ) ) {
27
  $user_data = get_user_by( 'email', trim( wp_unslash( $_POST['user_login'] ) ) );
28
  if ( empty( $user_data ) ) {
29
+ $errors->add( 'invalid_email', __( '<strong>Error</strong>: There is no account with that username or email address.' ) );
30
  }
31
  } else {
32
+ $login = trim( wp_unslash( $_POST['user_login'] ) );
33
  $user_data = get_user_by( 'login', $login );
34
  }
35
 
36
  /** This action is documented in wp-login.php */
37
+ do_action( 'lostpassword_post', $errors, $user_data );
38
 
39
  if ( $errors->get_error_code() ) {
40
  return $errors;
41
  }
42
 
43
  if ( ! $user_data ) {
44
+ $errors->add( 'invalidcombo', __( '<strong>Error</strong>: There is no account with that username or email address.' ) );
45
  return $errors;
46
  }
47
 
89
  $message .= sprintf( __( 'Username: %s' ), $user->user_login ) . "\r\n\r\n";
90
  $message .= __( 'If this was a mistake, just ignore this email and nothing will happen.' ) . "\r\n\r\n";
91
  $message .= __( 'To reset your password, visit the following address:' ) . "\r\n\r\n";
92
+ $message .= network_site_url( "wp-login.php?action=rp&key=$key&login=" . rawurlencode( $user->user_login ), 'login' ) . "\r\n";
93
 
94
  /* translators: Password reset email subject. %s: Site name */
95
  $title = sprintf( __( '[%s] Password Reset' ), $site_name );
152
  $retrieve_password_email['message'],
153
  $retrieve_password_email['headers']
154
  ) ) {
155
+ wp_die( sprintf(
156
+ __( '<strong>Error</strong>: The email could not be sent. Your site may not be correctly configured to send emails. <a href="%s">Get support for resetting your password</a>.' ),
157
+ esc_url( __( 'https://wordpress.org/support/article/resetting-your-password/' ) )
158
+ ) );
159
  }
160
  }
includes/extensions.php CHANGED
@@ -193,27 +193,29 @@ function tml_activate_extension_license( $extension ) {
193
  switch ( $response->error ) {
194
  case 'expired' :
195
  $message = sprintf(
196
- __( 'Your license key expired on %s.', 'theme_my_login' ),
197
  date_i18n( get_option( 'date_format' ), strtotime( $license_data->expires, current_time( 'timestamp' ) ) )
198
  );
199
  break;
200
 
201
- case 'revoked' :
202
  $message = __( 'Your license key has been disabled.', 'theme-my-login' );
203
  break;
204
 
205
  case 'missing' :
 
 
 
206
  case 'item_name_mismatch' :
207
  $message = __( 'Invalid license.', 'theme-my-login' );
208
  break;
209
 
210
- case 'invalid' :
211
- case 'site_inactive' :
212
- $message = __( 'Your license is not active for this URL.', 'theme-my-login' );
213
  break;
214
 
215
- case 'no_activations_left':
216
- $message = __( 'Your license key has reached its activation limit.', 'theme-my-login' );
217
  break;
218
 
219
  default :
@@ -250,6 +252,13 @@ function tml_deactivate_extension_license( $extension ) {
250
  return new WP_Error( 'http_error', __( 'An error occurred, please try again.', 'theme-my-login' ) );
251
  }
252
 
 
 
 
 
 
 
 
253
  return $response->license;
254
  }
255
 
193
  switch ( $response->error ) {
194
  case 'expired' :
195
  $message = sprintf(
196
+ __( 'Your license key expired on %s.', 'theme-my-login' ),
197
  date_i18n( get_option( 'date_format' ), strtotime( $license_data->expires, current_time( 'timestamp' ) ) )
198
  );
199
  break;
200
 
201
+ case 'disabled' :
202
  $message = __( 'Your license key has been disabled.', 'theme-my-login' );
203
  break;
204
 
205
  case 'missing' :
206
+ case 'missing_url' :
207
+ case 'key_mismatch' :
208
+ case 'invalid_item_id' :
209
  case 'item_name_mismatch' :
210
  $message = __( 'Invalid license.', 'theme-my-login' );
211
  break;
212
 
213
+ case 'no_activations_left' :
214
+ $message = __( 'Your license key has reached its activation limit.', 'theme-my-login' );
 
215
  break;
216
 
217
+ case 'license_not_activable' :
218
+ $message = __( 'You are attempting to activate a bundle license. Please use the license that corresponds to the individual extension you are attemtping to activate.', 'theme-my-login' );
219
  break;
220
 
221
  default :
252
  return new WP_Error( 'http_error', __( 'An error occurred, please try again.', 'theme-my-login' ) );
253
  }
254
 
255
+ if ( false === $response->success ) {
256
+ return new WP_Error( 'deactivation_failed', sprintf(
257
+ __( 'Unable to deactivate license. Please deactivate it on <a href="%1$s" target="_blank">our site</a>.', 'theme-my-login' ),
258
+ 'https://thememylogin.com/your-account/?action=license-keys'
259
+ ) );
260
+ }
261
+
262
  return $response->license;
263
  }
264
 
includes/forms.php CHANGED
@@ -31,15 +31,21 @@ function tml_register_default_forms() {
31
  function tml_register_login_form() {
32
 
33
  tml_register_form( 'login', array(
34
- 'action' => tml_get_action_url( 'login' ),
 
 
 
35
  ) );
36
 
37
  tml_add_form_field( 'login', 'log', array(
38
- 'type' => 'text',
39
- 'label' => tml_get_username_label( 'login' ),
40
- 'value' => tml_get_request_value( 'log', 'post' ),
41
- 'id' => 'user_login',
42
- 'priority' => 10,
 
 
 
43
  ) );
44
 
45
  tml_add_form_field( 'login', 'pwd', array(
@@ -88,16 +94,23 @@ function tml_register_login_form() {
88
  function tml_register_registration_form() {
89
 
90
  tml_register_form( 'register', array(
91
- 'action' => tml_get_action_url( 'register' ),
 
 
 
 
92
  ) );
93
 
94
  if ( tml_is_default_registration_type() ) {
95
  tml_add_form_field( 'register', 'user_login', array(
96
- 'type' => 'text',
97
- 'label' => __( 'Username' ),
98
- 'value' => tml_get_request_value( 'user_login', 'post' ),
99
- 'id' => 'user_login',
100
- 'priority' => 10,
 
 
 
101
  ) );
102
  } else {
103
  tml_add_form_field( 'register', 'user_login', array(
@@ -185,15 +198,21 @@ function tml_register_registration_form() {
185
  function tml_register_lost_password_form() {
186
 
187
  tml_register_form( 'lostpassword', array(
188
- 'action' => tml_get_action_url( 'lostpassword' ),
 
 
 
189
  ) );
190
 
191
  tml_add_form_field( 'lostpassword', 'user_login', array(
192
- 'type' => 'text',
193
- 'label' => tml_get_username_label( 'lostpassword' ),
194
- 'value' => '',
195
- 'id' => 'user_login',
196
- 'priority' => 10,
 
 
 
197
  ) );
198
 
199
  tml_add_form_field( 'lostpassword', 'lostpassword_form', array(
@@ -223,23 +242,34 @@ function tml_register_password_reset_form() {
223
 
224
  tml_register_form( 'resetpass', array(
225
  'action' => tml_get_action_url( 'resetpass' ),
 
 
 
226
  'render_args' => array(
227
  'show_links' => false,
228
  ),
229
  ) );
230
 
231
  tml_add_form_field( 'resetpass', 'pass1', array(
232
- 'type' => 'password',
233
- 'label' => __( 'New password' ),
234
- 'id' => 'pass1',
235
- 'priority' => 10,
 
 
 
 
236
  ) );
237
 
238
  tml_add_form_field( 'resetpass', 'pass2', array(
239
- 'type' => 'password',
240
- 'label' => __( 'Confirm new password' ),
241
- 'id' => 'pass2',
242
- 'priority' => 10,
 
 
 
 
243
  ) );
244
 
245
  tml_add_form_field( 'resetpass', 'indicator', array(
31
  function tml_register_login_form() {
32
 
33
  tml_register_form( 'login', array(
34
+ 'action' => tml_get_action_url( 'login' ),
35
+ 'attributes' => array(
36
+ 'data-ajax' => 1,
37
+ ),
38
  ) );
39
 
40
  tml_add_form_field( 'login', 'log', array(
41
+ 'type' => 'text',
42
+ 'label' => tml_get_username_label( 'login' ),
43
+ 'value' => tml_get_request_value( 'log', 'post' ),
44
+ 'id' => 'user_login',
45
+ 'attributes' => array(
46
+ 'autocapitalize' => 'off',
47
+ ),
48
+ 'priority' => 10,
49
  ) );
50
 
51
  tml_add_form_field( 'login', 'pwd', array(
94
  function tml_register_registration_form() {
95
 
96
  tml_register_form( 'register', array(
97
+ 'action' => tml_get_action_url( 'register' ),
98
+ 'attributes' => array(
99
+ 'novalidate' => 'novalidate',
100
+ 'data-ajax' => 1,
101
+ ),
102
  ) );
103
 
104
  if ( tml_is_default_registration_type() ) {
105
  tml_add_form_field( 'register', 'user_login', array(
106
+ 'type' => 'text',
107
+ 'label' => __( 'Username' ),
108
+ 'value' => tml_get_request_value( 'user_login', 'post' ),
109
+ 'id' => 'user_login',
110
+ 'attributes' => array(
111
+ 'autocapitalize' => 'off',
112
+ ),
113
+ 'priority' => 10,
114
  ) );
115
  } else {
116
  tml_add_form_field( 'register', 'user_login', array(
198
  function tml_register_lost_password_form() {
199
 
200
  tml_register_form( 'lostpassword', array(
201
+ 'action' => tml_get_action_url( 'lostpassword' ),
202
+ 'attributes' => array(
203
+ 'data-ajax' => 1,
204
+ ),
205
  ) );
206
 
207
  tml_add_form_field( 'lostpassword', 'user_login', array(
208
+ 'type' => 'text',
209
+ 'label' => tml_get_username_label( 'lostpassword' ),
210
+ 'value' => tml_get_request_value( 'user_login', 'post' ),
211
+ 'id' => 'user_login',
212
+ 'attributes' => array(
213
+ 'autocapitalize' => 'off',
214
+ ),
215
+ 'priority' => 10,
216
  ) );
217
 
218
  tml_add_form_field( 'lostpassword', 'lostpassword_form', array(
242
 
243
  tml_register_form( 'resetpass', array(
244
  'action' => tml_get_action_url( 'resetpass' ),
245
+ 'attributes' => array(
246
+ 'autocomplete' => 'off',
247
+ ),
248
  'render_args' => array(
249
  'show_links' => false,
250
  ),
251
  ) );
252
 
253
  tml_add_form_field( 'resetpass', 'pass1', array(
254
+ 'type' => 'password',
255
+ 'label' => __( 'New password' ),
256
+ 'id' => 'pass1',
257
+ 'attributes' => array(
258
+ 'autocomplete' => 'off',
259
+ 'aria-describedby' => 'pass-strength-result',
260
+ ),
261
+ 'priority' => 10,
262
  ) );
263
 
264
  tml_add_form_field( 'resetpass', 'pass2', array(
265
+ 'type' => 'password',
266
+ 'label' => __( 'Confirm new password' ),
267
+ 'id' => 'pass2',
268
+ 'attributes' => array(
269
+ 'autocomplete' => 'off',
270
+ 'aria-describedby' => 'pass-strength-result',
271
+ ),
272
+ 'priority' => 10,
273
  ) );
274
 
275
  tml_add_form_field( 'resetpass', 'indicator', array(
includes/functions.php CHANGED
@@ -296,6 +296,9 @@ function tml_do_login_head() {
296
  // This is already attached to "wp_head"
297
  remove_action( 'login_head', 'wp_print_head_scripts', 9 );
298
 
 
 
 
299
  /** This action is documented in wp-login.php */
300
  do_action( 'login_head' );
301
  }
@@ -377,7 +380,7 @@ function tml_filter_site_url( $url, $path, $scheme ) {
377
  parse_str( $parsed_url['query'], $query );
378
 
379
  // Encode the query args
380
- $query = array_map( 'rawurlencode', $query );
381
  }
382
 
383
  /**
@@ -476,6 +479,12 @@ function tml_filter_logout_url( $url, $redirect ) {
476
  * @return string The lostpassword URL.
477
  */
478
  function tml_filter_lostpassword_url( $url, $redirect ) {
 
 
 
 
 
 
479
 
480
  // Bail if logout action doesn't exist for some reason
481
  if ( ! tml_action_exists( 'lostpassword' ) ) {
@@ -671,13 +680,13 @@ function tml_validate_new_user_password( $errors = null ) {
671
 
672
  if ( tml_allow_user_passwords() ) {
673
  if ( empty( $_POST['user_pass1'] ) || empty( $_POST['user_pass2'] ) ) {
674
- $errors->add( 'empty_password', __( '<strong>ERROR</strong>: Please enter a password.', 'theme-my-login' ) );
675
 
676
  } elseif ( false !== strpos( stripslashes( $_POST['user_pass1'] ), "\\" ) ) {
677
- $errors->add( 'password_backslash', __( '<strong>ERROR</strong>: Passwords may not contain the character "\\".', 'theme-my-login' ) );
678
 
679
  } elseif ( $_POST['user_pass1'] !== $_POST['user_pass2'] ) {
680
- $errors->add( 'password_mismatch', __( '<strong>ERROR</strong>: Please enter the same password in both password fields.', 'theme-my-login' ) );
681
  }
682
  }
683
 
@@ -795,7 +804,7 @@ function tml_get_username_label( $action = '' ) {
795
  */
796
  function tml_enforce_login_type( $user, $username, $password ) {
797
  if ( tml_is_email_login_type() && null == $user ) {
798
- return new WP_Error( 'invalid_email', __( '<strong>ERROR</strong>: Invalid email address.' ) );
799
  }
800
  return $user;
801
  }
@@ -1040,3 +1049,95 @@ function tml_is_get_request() {
1040
  function tml_is_post_request() {
1041
  return 'POST' === strtoupper( $_SERVER['REQUEST_METHOD'] );
1042
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
296
  // This is already attached to "wp_head"
297
  remove_action( 'login_head', 'wp_print_head_scripts', 9 );
298
 
299
+ // Don't index TML actions
300
+ add_action( 'login_head', 'wp_sensitive_page_meta' );
301
+
302
  /** This action is documented in wp-login.php */
303
  do_action( 'login_head' );
304
  }
380
  parse_str( $parsed_url['query'], $query );
381
 
382
  // Encode the query args
383
+ $query = tml_array_map_recursive( 'rawurlencode', $query );
384
  }
385
 
386
  /**
479
  * @return string The lostpassword URL.
480
  */
481
  function tml_filter_lostpassword_url( $url, $redirect ) {
482
+ global $pagenow;
483
+
484
+ // Bail if currently visiting wp-login.php
485
+ if ( 'wp-login.php' == $pagenow ) {
486
+ return $url;
487
+ }
488
 
489
  // Bail if logout action doesn't exist for some reason
490
  if ( ! tml_action_exists( 'lostpassword' ) ) {
680
 
681
  if ( tml_allow_user_passwords() ) {
682
  if ( empty( $_POST['user_pass1'] ) || empty( $_POST['user_pass2'] ) ) {
683
+ $errors->add( 'empty_password', __( '<strong>Error</strong>: Please enter a password.', 'theme-my-login' ) );
684
 
685
  } elseif ( false !== strpos( stripslashes( $_POST['user_pass1'] ), "\\" ) ) {
686
+ $errors->add( 'password_backslash', __( '<strong>Error</strong>: Passwords may not contain the character "\\".', 'theme-my-login' ) );
687
 
688
  } elseif ( $_POST['user_pass1'] !== $_POST['user_pass2'] ) {
689
+ $errors->add( 'password_mismatch', __( '<strong>Error</strong>: Please enter the same password in both password fields.', 'theme-my-login' ) );
690
  }
691
  }
692
 
804
  */
805
  function tml_enforce_login_type( $user, $username, $password ) {
806
  if ( tml_is_email_login_type() && null == $user ) {
807
+ return new WP_Error( 'invalid_email', __( '<strong>Error</strong>: Invalid email address.' ) );
808
  }
809
  return $user;
810
  }
1049
  function tml_is_post_request() {
1050
  return 'POST' === strtoupper( $_SERVER['REQUEST_METHOD'] );
1051
  }
1052
+
1053
+ /**
1054
+ * Determine if the current request is an AJAX request.
1055
+ *
1056
+ * @since 7.1
1057
+ *
1058
+ * @return bool
1059
+ */
1060
+ function tml_is_ajax_request() {
1061
+ if ( ! isset( $_SERVER['HTTP_X_REQUESTED_WITH'] ) ) {
1062
+ return false;
1063
+ } elseif ( 'xmlhttprequest' != strtolower( $_SERVER['HTTP_X_REQUESTED_WITH'] ) ) {
1064
+ return false;
1065
+ } else {
1066
+ return true;
1067
+ }
1068
+ }
1069
+
1070
+ /**
1071
+ * Send an AJAX success response.
1072
+ *
1073
+ * @since 7.1
1074
+ *
1075
+ * @param mixed $data Data to send with the response.
1076
+ */
1077
+ function tml_send_ajax_success( $data = null ) {
1078
+ /**
1079
+ * Filters the AJAX success data.
1080
+ *
1081
+ * @since 7.1
1082
+ *
1083
+ * @param mixed $data The AJAX success data.
1084
+ */
1085
+ $data = apply_filters( 'tml_ajax_success_data', $data );
1086
+
1087
+ wp_send_json_success( $data );
1088
+ }
1089
+
1090
+ /**
1091
+ * Send an AJAX error response.
1092
+ *
1093
+ * @since 7.1
1094
+ *
1095
+ * @param mixed $data Data to send with the response.
1096
+ */
1097
+ function tml_send_ajax_error( $data = null ) {
1098
+ /**
1099
+ * Filters the AJAX error data.
1100
+ *
1101
+ * @since 7.1
1102
+ *
1103
+ * @param mixed $data The AJAX error data.
1104
+ */
1105
+ $data = apply_filters( 'tml_ajax_error_data', $data );
1106
+
1107
+ wp_send_json_error( $data );
1108
+ }
1109
+
1110
+ /**
1111
+ * Validate a URL for redirection.
1112
+ *
1113
+ * @since 7.1
1114
+ *
1115
+ * @param string $url The URL to validate.
1116
+ * @return string The validated URL.
1117
+ */
1118
+ function tml_validate_redirect( $url ) {
1119
+ return wp_validate_redirect( wp_sanitize_redirect( $url ),
1120
+ /** This filter is documented in wp-includes/pluggable.php */
1121
+ apply_filters( 'wp_safe_redirect_fallback', admin_url(), 302 )
1122
+ );
1123
+ }
1124
+
1125
+ /**
1126
+ * Map a user defined callback to an array recursively.
1127
+ *
1128
+ * @since 7.0.16
1129
+ *
1130
+ * @param string $callback The name of the callback.
1131
+ * @param array $array The array to be mapped.
1132
+ * @return array The resulting array.
1133
+ */
1134
+ function tml_array_map_recursive( $callback, $array ) {
1135
+ foreach ( $array as $key => $value ) {
1136
+ if ( is_array( $value ) ) {
1137
+ $array[ $key ] = tml_array_map_recursive( $callback, $value );
1138
+ } else {
1139
+ $array[ $key ] = call_user_func( $callback, $value );
1140
+ }
1141
+ }
1142
+ return $array;
1143
+ }
includes/shortcodes.php CHANGED
@@ -61,6 +61,45 @@ function tml_shortcode( $atts = array() ) {
61
 
62
  } elseif ( 'confirmaction' == $action->get_name() && isset( $_GET['request_id'] ) ) {
63
  $content = _wp_privacy_account_request_confirmed_message( $_GET['request_id'] );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
  }
65
 
66
  /**
61
 
62
  } elseif ( 'confirmaction' == $action->get_name() && isset( $_GET['request_id'] ) ) {
63
  $content = _wp_privacy_account_request_confirmed_message( $_GET['request_id'] );
64
+
65
+ } elseif ( 'dashboard' == $action->get_name() ) {
66
+ $content = '<div class="tml-dashboard">';
67
+
68
+ $content .= '<div class="tml-dashboard-avatar">' . get_avatar( get_current_user_id() ) . '</div>';
69
+
70
+ $content .= '<p class="tml-dashboard-greeting">' . sprintf( __( 'Howdy, %s' ), wp_get_current_user()->display_name ) . '</p>';
71
+
72
+ /**
73
+ * Filter the dashboard links.
74
+ *
75
+ * @since 7.1
76
+ *
77
+ * @param array $links The dashboard links.
78
+ */
79
+ $links = apply_filters( 'tml_dashboard_links', array_filter( array(
80
+ 'site_admin' => current_user_can( 'edit_posts' ) ? array(
81
+ 'title' => __( 'Site Admin' ),
82
+ 'url' => admin_url(),
83
+ ) : false,
84
+ 'profile' => array(
85
+ 'title' => __( 'Edit My Profile' ),
86
+ 'url' => admin_url( 'profile.php' ),
87
+ ),
88
+ 'logout' => array(
89
+ 'title' => __( 'Log Out' ),
90
+ 'url' => wp_logout_url(),
91
+ ),
92
+ ) ) );
93
+
94
+ if ( ! empty( $links ) ) {
95
+ $content .= '<ul class="tml-dashboard-links">';
96
+ foreach ( $links as $link ) {
97
+ $content .= '<li><a href="' . esc_url( $link['url'] ) . '">' . esc_html( $link['title'] ) . '</a></li>';
98
+ }
99
+ $content .= '</ul>';
100
+ }
101
+
102
+ $content .= '</div>';
103
  }
104
 
105
  /**
languages/theme-my-login.pot CHANGED
@@ -1,15 +1,15 @@
1
- # Copyright (C) 2019 Theme My Login
2
  # This file is distributed under the same license as the Theme My Login plugin.
3
  msgid ""
4
  msgstr ""
5
- "Project-Id-Version: Theme My Login 7.0.15\n"
6
- "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/theme-my-login\n"
7
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
8
  "Language-Team: LANGUAGE <LL@li.org>\n"
9
  "MIME-Version: 1.0\n"
10
  "Content-Type: text/plain; charset=UTF-8\n"
11
  "Content-Transfer-Encoding: 8bit\n"
12
- "POT-Creation-Date: 2019-09-06T17:31:13-04:00\n"
13
  "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
14
  "X-Generator: WP-CLI 2.2.0\n"
15
  "X-Domain: theme-my-login\n"
@@ -30,42 +30,42 @@ msgstr ""
30
  msgid "Creates an alternate login, registration and password recovery experience within your theme."
31
  msgstr ""
32
 
33
- #: includes/functions.php:539
34
- #: admin/functions.php:277
35
  msgid "Theme My Login Actions"
36
  msgstr ""
37
 
38
- #: includes/functions.php:540
39
  msgid "Theme My Login Action"
40
  msgstr ""
41
 
42
- #: includes/functions.php:568
43
- #: includes/functions.php:595
44
- #: includes/functions.php:610
45
  msgid "TML Action"
46
  msgstr ""
47
 
48
- #: includes/functions.php:674
49
- msgid "<strong>ERROR</strong>: Please enter a password."
50
  msgstr ""
51
 
52
- #: includes/functions.php:677
53
- msgid "<strong>ERROR</strong>: Passwords may not contain the character \"\\\"."
54
  msgstr ""
55
 
56
- #: includes/functions.php:680
57
- msgid "<strong>ERROR</strong>: Please enter the same password in both password fields."
58
  msgstr ""
59
 
60
- #: includes/functions.php:697
61
  msgid "If you have already set your own password, you may disregard this email and use the password you have already set."
62
  msgstr ""
63
 
64
- #: includes/actions.php:68
65
  msgid "Your Data Request"
66
  msgstr ""
67
 
68
- #: includes/actions.php:455
69
  msgid "Registration complete. You may now log in."
70
  msgstr ""
71
 
@@ -78,39 +78,43 @@ msgctxt "Howdy"
78
  msgid "Welcome"
79
  msgstr ""
80
 
81
- #: includes/class-theme-my-login-widget.php:92
82
- msgid "Profile"
83
- msgstr ""
84
-
85
- #: includes/class-theme-my-login-widget.php:173
86
  msgid "Show action links?"
87
  msgstr ""
88
 
89
- #: includes/forms.php:133
90
  msgid "Confirm Password"
91
  msgstr ""
92
 
93
  #: includes/extensions.php:189
94
- #: includes/extensions.php:220
95
- #: includes/extensions.php:250
96
- #: includes/extensions.php:278
97
  msgid "An error occurred, please try again."
98
  msgstr ""
99
 
 
 
 
 
100
  #: includes/extensions.php:202
101
  msgid "Your license key has been disabled."
102
  msgstr ""
103
 
104
- #: includes/extensions.php:207
105
  msgid "Invalid license."
106
  msgstr ""
107
 
108
- #: includes/extensions.php:212
109
- msgid "Your license is not active for this URL."
110
  msgstr ""
111
 
112
- #: includes/extensions.php:216
113
- msgid "Your license key has reached its activation limit."
 
 
 
 
114
  msgstr ""
115
 
116
  #: admin/functions.php:66
@@ -135,19 +139,19 @@ msgid "Theme My Login Extensions"
135
  msgstr ""
136
 
137
  #: admin/functions.php:110
138
- #: admin/functions.php:354
139
  msgid "Extensions"
140
  msgstr ""
141
 
142
- #: admin/functions.php:162
143
  msgid "As a token of our gratitude, we would like to offer your an incentive for upgrading Theme My Login to version 7.0. For a limited time, we are offering a <strong>20% discount</strong> when you use the code <strong>SAVINGFACE</strong> at checkout. Act now - this offer won't last!"
144
  msgstr ""
145
 
146
- #: admin/functions.php:178
147
  msgid "A new <strong>Theme My Login</strong> extension is available!"
148
  msgstr ""
149
 
150
- #: admin/functions.php:185
151
  #: admin/extensions.php:94
152
  msgid "Get This Extension"
153
  msgstr ""
@@ -204,84 +208,86 @@ msgstr ""
204
  msgid "The slugs defined here will be used to generate the URL to the corresponding action. You can see this URL below the slug field. If you would like to use pages for these actions, simply make sure the slug for the action below matches the slug of the page you would like to use for that action."
205
  msgstr ""
206
 
207
- #: admin/settings.php:465
 
208
  msgid "Active"
209
  msgstr ""
210
 
211
- #: admin/settings.php:469
212
  msgid "Invalid"
213
  msgstr ""
214
 
215
- #: admin/settings.php:472
 
216
  msgid "Inactive"
217
  msgstr ""
218
 
219
- #: admin/settings.php:487
220
  msgid "Deactivate"
221
  msgstr ""
222
 
223
- #: admin/settings.php:489
224
  msgid "Activate"
225
  msgstr ""
226
 
227
- #: admin/settings.php:602
228
  msgid "Welcome to Theme My Login!"
229
  msgstr ""
230
 
231
- #: admin/settings.php:603
232
  msgid "Below, you can configure how you would like users to register and log in to your site."
233
  msgstr ""
234
 
235
- #: admin/settings.php:604
236
  msgid "Additionally, you can change the slugs that are used to generate the URLs that represent specific actions."
237
  msgstr ""
238
 
239
- #: admin/settings.php:610
240
- #: admin/settings.php:633
241
- #: admin/settings.php:653
242
- #: admin/settings.php:681
243
  msgid "View Documentation"
244
  msgstr ""
245
 
246
- #: admin/settings.php:615
247
- #: admin/settings.php:637
248
- #: admin/settings.php:688
249
  msgid "Get Support"
250
  msgstr ""
251
 
252
- #: admin/settings.php:625
253
  msgid "When you purchase extensions for Theme My Login, you will enter your license keys on this page."
254
  msgstr ""
255
 
256
- #: admin/settings.php:626
257
  msgid "After you enter your license keys and click the Save Changes button at the bottom of the screen, you will see a new button next to each field with a license in it."
258
  msgstr ""
259
 
260
- #: admin/settings.php:627
261
  msgid "If you have not yet activated your license, this button will say \"Activate\". Click this button to activate your license."
262
  msgstr ""
263
 
264
- #: admin/settings.php:628
265
  msgid "If you have already activated your license, this button will say \"Deactivate\". Click this button to deactivate your license."
266
  msgstr ""
267
 
268
- #: admin/settings.php:647
269
  msgid "This page shows you all of the extensions available to purchase for Theme My Login."
270
  msgstr ""
271
 
272
- #: admin/settings.php:648
273
  msgid "Once you purchase an extension, you download it from your email receipt or your account page on our website. Then, you install it just like a normal WordPress plugin."
274
  msgstr ""
275
 
276
- #: admin/settings.php:657
277
  msgid "Go to the Extensions Store"
278
  msgstr ""
279
 
280
- #: admin/settings.php:661
281
  msgid "View your Theme My Login account"
282
  msgstr ""
283
 
284
- #: admin/settings.php:672
285
  msgid "On this page, you can configure the settings for the Theme My Login %s extension."
286
  msgstr ""
287
 
@@ -296,3 +302,8 @@ msgstr ""
296
  #: admin/extensions.php:104
297
  msgid "View All Extensions"
298
  msgstr ""
 
 
 
 
 
1
+ # Copyright (C) 2020 Theme My Login
2
  # This file is distributed under the same license as the Theme My Login plugin.
3
  msgid ""
4
  msgstr ""
5
+ "Project-Id-Version: Theme My Login 7.1\n"
6
+ "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/build\n"
7
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
8
  "Language-Team: LANGUAGE <LL@li.org>\n"
9
  "MIME-Version: 1.0\n"
10
  "Content-Type: text/plain; charset=UTF-8\n"
11
  "Content-Transfer-Encoding: 8bit\n"
12
+ "POT-Creation-Date: 2020-05-25T11:56:24-04:00\n"
13
  "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
14
  "X-Generator: WP-CLI 2.2.0\n"
15
  "X-Domain: theme-my-login\n"
30
  msgid "Creates an alternate login, registration and password recovery experience within your theme."
31
  msgstr ""
32
 
33
+ #: includes/functions.php:548
34
+ #: admin/functions.php:278
35
  msgid "Theme My Login Actions"
36
  msgstr ""
37
 
38
+ #: includes/functions.php:549
39
  msgid "Theme My Login Action"
40
  msgstr ""
41
 
42
+ #: includes/functions.php:577
43
+ #: includes/functions.php:604
44
+ #: includes/functions.php:619
45
  msgid "TML Action"
46
  msgstr ""
47
 
48
+ #: includes/functions.php:683
49
+ msgid "<strong>Error</strong>: Please enter a password."
50
  msgstr ""
51
 
52
+ #: includes/functions.php:686
53
+ msgid "<strong>Error</strong>: Passwords may not contain the character \"\\\"."
54
  msgstr ""
55
 
56
+ #: includes/functions.php:689
57
+ msgid "<strong>Error</strong>: Please enter the same password in both password fields."
58
  msgstr ""
59
 
60
+ #: includes/functions.php:706
61
  msgid "If you have already set your own password, you may disregard this email and use the password you have already set."
62
  msgstr ""
63
 
64
+ #: includes/actions.php:80
65
  msgid "Your Data Request"
66
  msgstr ""
67
 
68
+ #: includes/actions.php:520
69
  msgid "Registration complete. You may now log in."
70
  msgstr ""
71
 
78
  msgid "Welcome"
79
  msgstr ""
80
 
81
+ #: includes/class-theme-my-login-widget.php:177
 
 
 
 
82
  msgid "Show action links?"
83
  msgstr ""
84
 
85
+ #: includes/forms.php:146
86
  msgid "Confirm Password"
87
  msgstr ""
88
 
89
  #: includes/extensions.php:189
90
+ #: includes/extensions.php:222
91
+ #: includes/extensions.php:252
92
+ #: includes/extensions.php:287
93
  msgid "An error occurred, please try again."
94
  msgstr ""
95
 
96
+ #: includes/extensions.php:196
97
+ msgid "Your license key expired on %s."
98
+ msgstr ""
99
+
100
  #: includes/extensions.php:202
101
  msgid "Your license key has been disabled."
102
  msgstr ""
103
 
104
+ #: includes/extensions.php:210
105
  msgid "Invalid license."
106
  msgstr ""
107
 
108
+ #: includes/extensions.php:214
109
+ msgid "Your license key has reached its activation limit."
110
  msgstr ""
111
 
112
+ #: includes/extensions.php:218
113
+ msgid "You are attempting to activate a bundle license. Please use the license that corresponds to the individual extension you are attemtping to activate."
114
+ msgstr ""
115
+
116
+ #: includes/extensions.php:257
117
+ msgid "Unable to deactivate license. Please deactivate it on <a href=\"%1$s\" target=\"_blank\">our site</a>."
118
  msgstr ""
119
 
120
  #: admin/functions.php:66
139
  msgstr ""
140
 
141
  #: admin/functions.php:110
142
+ #: admin/functions.php:355
143
  msgid "Extensions"
144
  msgstr ""
145
 
146
+ #: admin/functions.php:163
147
  msgid "As a token of our gratitude, we would like to offer your an incentive for upgrading Theme My Login to version 7.0. For a limited time, we are offering a <strong>20% discount</strong> when you use the code <strong>SAVINGFACE</strong> at checkout. Act now - this offer won't last!"
148
  msgstr ""
149
 
150
+ #: admin/functions.php:179
151
  msgid "A new <strong>Theme My Login</strong> extension is available!"
152
  msgstr ""
153
 
154
+ #: admin/functions.php:186
155
  #: admin/extensions.php:94
156
  msgid "Get This Extension"
157
  msgstr ""
208
  msgid "The slugs defined here will be used to generate the URL to the corresponding action. You can see this URL below the slug field. If you would like to use pages for these actions, simply make sure the slug for the action below matches the slug of the page you would like to use for that action."
209
  msgstr ""
210
 
211
+ #: admin/settings.php:464
212
+ #: admin/extensions.php:179
213
  msgid "Active"
214
  msgstr ""
215
 
216
+ #: admin/settings.php:467
217
  msgid "Invalid"
218
  msgstr ""
219
 
220
+ #: admin/settings.php:470
221
+ #: admin/extensions.php:200
222
  msgid "Inactive"
223
  msgstr ""
224
 
225
+ #: admin/settings.php:482
226
  msgid "Deactivate"
227
  msgstr ""
228
 
229
+ #: admin/settings.php:494
230
  msgid "Activate"
231
  msgstr ""
232
 
233
+ #: admin/settings.php:619
234
  msgid "Welcome to Theme My Login!"
235
  msgstr ""
236
 
237
+ #: admin/settings.php:620
238
  msgid "Below, you can configure how you would like users to register and log in to your site."
239
  msgstr ""
240
 
241
+ #: admin/settings.php:621
242
  msgid "Additionally, you can change the slugs that are used to generate the URLs that represent specific actions."
243
  msgstr ""
244
 
245
+ #: admin/settings.php:627
246
+ #: admin/settings.php:650
247
+ #: admin/settings.php:670
248
+ #: admin/settings.php:698
249
  msgid "View Documentation"
250
  msgstr ""
251
 
252
+ #: admin/settings.php:632
253
+ #: admin/settings.php:654
254
+ #: admin/settings.php:705
255
  msgid "Get Support"
256
  msgstr ""
257
 
258
+ #: admin/settings.php:642
259
  msgid "When you purchase extensions for Theme My Login, you will enter your license keys on this page."
260
  msgstr ""
261
 
262
+ #: admin/settings.php:643
263
  msgid "After you enter your license keys and click the Save Changes button at the bottom of the screen, you will see a new button next to each field with a license in it."
264
  msgstr ""
265
 
266
+ #: admin/settings.php:644
267
  msgid "If you have not yet activated your license, this button will say \"Activate\". Click this button to activate your license."
268
  msgstr ""
269
 
270
+ #: admin/settings.php:645
271
  msgid "If you have already activated your license, this button will say \"Deactivate\". Click this button to deactivate your license."
272
  msgstr ""
273
 
274
+ #: admin/settings.php:664
275
  msgid "This page shows you all of the extensions available to purchase for Theme My Login."
276
  msgstr ""
277
 
278
+ #: admin/settings.php:665
279
  msgid "Once you purchase an extension, you download it from your email receipt or your account page on our website. Then, you install it just like a normal WordPress plugin."
280
  msgstr ""
281
 
282
+ #: admin/settings.php:674
283
  msgid "Go to the Extensions Store"
284
  msgstr ""
285
 
286
+ #: admin/settings.php:678
287
  msgid "View your Theme My Login account"
288
  msgstr ""
289
 
290
+ #: admin/settings.php:689
291
  msgid "On this page, you can configure the settings for the Theme My Login %s extension."
292
  msgstr ""
293
 
302
  #: admin/extensions.php:104
303
  msgid "View All Extensions"
304
  msgstr ""
305
+
306
+ #: admin/extensions.php:163
307
+ #: admin/extensions.php:189
308
+ msgid "Invalid extension."
309
+ msgstr ""
readme.txt CHANGED
@@ -1,9 +1,9 @@
1
  === Theme My Login ===
2
  Contributors: thememylogin, jfarthing84
3
  Tags: login, register, password, branding, customize, widget, wp-login, wp-login.php
4
- Requires at least: 4.6
5
- Tested up to: 5.2.4
6
- Stable tag: 7.0.15
7
 
8
  The ultimate login branding solution! Theme My Login offers matchless customization of your WordPress user experience!
9
 
@@ -59,6 +59,16 @@ Report bugs, suggest ideas and participate in development at [GitHub](https://gi
59
 
60
  == Changelog ==
61
 
 
 
 
 
 
 
 
 
 
 
62
  = 7.0.15 =
63
  * Fix extension update issues caused by caching
64
  * Add `tml_script_dependencies` filter
1
  === Theme My Login ===
2
  Contributors: thememylogin, jfarthing84
3
  Tags: login, register, password, branding, customize, widget, wp-login, wp-login.php
4
+ Requires at least: 5.4
5
+ Tested up to: 5.4.2
6
+ Stable tag: trunk
7
 
8
  The ultimate login branding solution! Theme My Login offers matchless customization of your WordPress user experience!
9
 
59
 
60
  == Changelog ==
61
 
62
+ = 7.1 =
63
+ * Implement AJAX support
64
+ * Introduce new Dashboard action
65
+ * Improve performance by reducing queries
66
+ * Require WordPress 5.4
67
+ * Remove angle brackets from password reset link in notification
68
+ * Add sensitive page meta tags to TML actions
69
+ * Add missing `lost_password` action hook
70
+ * Fix lostpassword link being rewritten on wp-login.php
71
+
72
  = 7.0.15 =
73
  * Fix extension update issues caused by caching
74
  * Add `tml_script_dependencies` filter
theme-my-login.php CHANGED
@@ -10,7 +10,7 @@
10
  Plugin Name: Theme My Login
11
  Plugin URI: https://thememylogin.com
12
  Description: Creates an alternate login, registration and password recovery experience within your theme.
13
- Version: 7.0.15
14
  Author: Theme My Login
15
  Author URI: https://thememylogin.com
16
  License: GPLv2
@@ -24,7 +24,7 @@ Network: true
24
  *
25
  * @since 7.0
26
  */
27
- define( 'THEME_MY_LOGIN_VERSION', '7.0.15' );
28
 
29
  /**
30
  * Stores the path to TML.
10
  Plugin Name: Theme My Login
11
  Plugin URI: https://thememylogin.com
12
  Description: Creates an alternate login, registration and password recovery experience within your theme.
13
+ Version: 7.1
14
  Author: Theme My Login
15
  Author URI: https://thememylogin.com
16
  License: GPLv2
24
  *
25
  * @since 7.0
26
  */
27
+ define( 'THEME_MY_LOGIN_VERSION', '7.1' );
28
 
29
  /**
30
  * Stores the path to TML.