/wp-content/plugins/theme-my-login/includes/class-theme-my-login.php

https://bitbucket.org/JacobTyler/fame4good-wp · PHP · 1139 lines · 607 code · 147 blank · 385 comment · 167 complexity · e347e1293d6c405c6e50fffec7637582 MD5 · raw file

  1. <?php
  2. /**
  3. * Holds the Theme My Login class
  4. *
  5. * @package Theme My Login
  6. */
  7. if ( !class_exists( 'Theme_My_Login' ) ) :
  8. /*
  9. * Theme My Login class
  10. *
  11. * This class contains properties and methods common to the front-end.
  12. *
  13. * @since 6.0
  14. */
  15. class Theme_My_Login {
  16. /**
  17. * Holds options object
  18. *
  19. * @since 6.1
  20. * @access public
  21. * @var object
  22. */
  23. var $options;
  24. /**
  25. * Holds errors object
  26. *
  27. * @since 6.0
  28. * @access public
  29. * @var object
  30. */
  31. var $errors;
  32. /**
  33. * Holds total instances of TML
  34. *
  35. * @since 6.0
  36. * @access public
  37. * @var int
  38. */
  39. var $count = 0;
  40. /**
  41. * Holds current instance being requested
  42. *
  43. * @since 6.0
  44. * @access public
  45. * @var int
  46. */
  47. var $request_instance;
  48. /**
  49. * Holds current action being requested
  50. *
  51. * @since 6.0
  52. * @access public
  53. * @var string
  54. */
  55. var $request_action;
  56. /**
  57. * PHP4 style constructor
  58. *
  59. * @since 6.0
  60. * @access public
  61. */
  62. function Theme_My_Login() {
  63. $this->__construct();
  64. }
  65. /**
  66. * PHP5 constructor
  67. *
  68. * @since 6.0
  69. * @access public
  70. */
  71. function __construct() {
  72. $this->request_action = isset( $_REQUEST['action'] ) ? sanitize_user( $_REQUEST['action'], true ) : '';
  73. $this->request_instance = isset( $_REQUEST['instance'] ) ? sanitize_user( $_REQUEST['instance'], true ) : '';
  74. $this->init_options();
  75. // Load options again to allow modules to tap in
  76. add_action( 'tml_modules_loaded', array( &$this, 'init_options' ), 0 );
  77. add_filter( 'rewrite_rules_array', array( &$this, 'rewrite_rules_array' ) );
  78. add_action( 'init', array( &$this, 'init' ) );
  79. add_action( 'widgets_init', array( &$this, 'widgets_init' ) );
  80. add_action( 'parse_request', array( &$this, 'parse_request' ) );
  81. add_action( 'wp', array( &$this, 'wp' ) );
  82. add_action( 'wp_head', array( &$this, 'login_head' ) );
  83. add_action( 'wp_print_footer_scripts', array( &$this, 'print_footer_scripts' ) );
  84. add_filter( 'the_title', array( &$this, 'the_title' ), 10, 2 );
  85. add_filter( 'single_post_title', array( &$this, 'single_post_title' ) );
  86. add_filter( 'wp_setup_nav_menu_item', array( &$this, 'wp_setup_nav_menu_item' ) );
  87. add_filter( 'site_url', array( &$this, 'site_url' ), 10, 3 );
  88. add_filter( 'page_link', array( &$this, 'page_link' ), 10, 2 );
  89. add_filter( 'tml_redirect_url', array( &$this, 'tml_redirect_url' ), 10, 2 );
  90. add_filter( 'wp_list_pages_excludes', array( &$this, 'wp_list_pages_excludes' ) );
  91. add_filter( 'wp_list_pages', array( &$this, 'wp_list_pages' ) );
  92. add_action( 'wp_authenticate', array( &$this, 'wp_authenticate' ) );
  93. add_action( 'tml_new_user_registered', 'wp_new_user_notification', 10, 2 );
  94. add_action( 'tml_user_password_changed', 'wp_password_change_notification' );
  95. add_shortcode( 'theme-my-login', array( &$this, 'shortcode' ) );
  96. }
  97. /**
  98. * Initializes plugin options object
  99. *
  100. * @since 6.1
  101. * @access public
  102. */
  103. function init_options() {
  104. $this->options = new WDBJ_Plugin_Options( 'theme_my_login', apply_filters( 'tml_init_options', array(
  105. 'page_id' => 0,
  106. 'show_page' => 1,
  107. 'enable_css' => 1,
  108. 'email_login' => 1,
  109. 'active_modules' => array(),
  110. 'permalinks' => array(),
  111. 'initial_nag' => 1
  112. ) ) );
  113. }
  114. /**
  115. * Handles permalink rewrite rules
  116. *
  117. * @since 6.2.2
  118. * @access public
  119. *
  120. * @param array $rules Rewrite rules
  121. * @return array Rewrite rules
  122. */
  123. function rewrite_rules_array( $rules ) {
  124. if ( defined( 'WP_INSTALLING' ) )
  125. return $rules;
  126. $page =& get_page( $this->options->get_option( 'page_id' ) );
  127. $page_uri = get_page_uri( $page->ID );
  128. $tml_rules = array();
  129. foreach ( $this->options->get_option( 'permalinks', array() ) as $action => $slug ) {
  130. if ( !empty( $slug ) ) {
  131. $slug = str_replace( $page->post_name, $slug, $page_uri );
  132. $tml_rules["{$slug}/?$"] = "index.php?page_id={$page->ID}&action={$action}";
  133. }
  134. }
  135. return array_merge( $tml_rules, $rules );
  136. }
  137. /**
  138. * Initializes the plugin
  139. *
  140. * @since 6.0
  141. * @access public
  142. */
  143. function init() {
  144. global $wp;
  145. load_plugin_textdomain( 'theme-my-login', '', TML_DIRNAME . '/language' );
  146. $this->errors = new WP_Error();
  147. if ( $this->options->get_option( 'enable_css' ) )
  148. wp_enqueue_style( 'theme-my-login', Theme_My_Login::get_stylesheet(), false, $this->options->get_option( 'version' ) );
  149. $wp->add_query_var( 'action' );
  150. }
  151. /**
  152. * Registers the widget
  153. *
  154. * @since 6.0
  155. * @access public
  156. */
  157. function widgets_init() {
  158. if ( class_exists( 'Theme_My_Login_Widget' ) )
  159. register_widget( 'Theme_My_Login_Widget' );
  160. }
  161. /**
  162. * Determine if specified page is the login page
  163. *
  164. * @since 6.0
  165. * @access public
  166. *
  167. * @param int $page_id Optional. The page ID (Defaults to current page)
  168. */
  169. function is_login_page( $page_id = '' ) {
  170. if ( empty( $page_id ) ) {
  171. global $wp_query;
  172. if ( $wp_query->is_page )
  173. $page_id = $wp_query->get_queried_object_id();
  174. }
  175. $is_login_page = ( $page_id == $this->options->get_option( 'page_id' ) );
  176. return apply_filters( 'tml_is_login_page', $is_login_page, $page_id );
  177. }
  178. /**
  179. * Proccesses the request
  180. *
  181. * Callback for "parse_request" hook in WP::parse_request()
  182. *
  183. * @see WP::parse_request()
  184. * @since 6.0
  185. * @access public
  186. */
  187. function parse_request( &$wp ) {
  188. $errors =& $this->errors;
  189. $action =& $this->request_action;
  190. if ( isset( $wp->query_vars['action'] ) ) {
  191. $action = $wp->query_vars['action'];
  192. unset( $wp->query_vars['action'] );
  193. }
  194. $instance =& $this->request_instance;
  195. if ( is_admin() )
  196. return;
  197. do_action_ref_array( 'tml_request', array( &$this ) );
  198. // allow plugins to override the default actions, and to add extra actions if they want
  199. do_action( 'login_form_' . $action );
  200. if ( has_action( 'tml_request_' . $action ) ) {
  201. do_action_ref_array( 'tml_request_' . $action, array( &$this ) );
  202. } else {
  203. $http_post = ( 'POST' == $_SERVER['REQUEST_METHOD'] );
  204. switch ( $action ) {
  205. case 'postpass' :
  206. global $wp_hasher;
  207. if ( empty( $wp_hasher ) ) {
  208. require_once( ABSPATH . 'wp-includes/class-phpass.php' );
  209. // By default, use the portable hash from phpass
  210. $wp_hasher = new PasswordHash( 8, true );
  211. }
  212. // 10 days
  213. setcookie( 'wp-postpass_' . COOKIEHASH, $wp_hasher->HashPassword( stripslashes( $_POST['post_password'] ) ), time() + 864000, COOKIEPATH );
  214. wp_safe_redirect( wp_get_referer() );
  215. exit;
  216. break;
  217. case 'logout' :
  218. check_admin_referer( 'log-out' );
  219. $user = wp_get_current_user();
  220. wp_logout();
  221. $redirect_to = apply_filters( 'logout_redirect', site_url( 'wp-login.php?loggedout=true' ), isset( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : '', $user );
  222. wp_safe_redirect( $redirect_to );
  223. exit();
  224. break;
  225. case 'lostpassword' :
  226. case 'retrievepassword' :
  227. if ( $http_post ) {
  228. $errors = $this->retrieve_password();
  229. if ( !is_wp_error( $errors ) ) {
  230. $redirect_to = !empty( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : Theme_My_Login::get_current_url( 'checkemail=confirm' );
  231. if ( !empty( $instance ) )
  232. $redirect_to = add_query_arg( 'instance', $instance, $redirect_to );
  233. wp_safe_redirect( $redirect_to );
  234. exit();
  235. }
  236. }
  237. if ( isset( $_REQUEST['error'] ) && 'invalidkey' == $_REQUEST['error'] )
  238. $errors->add( 'invalidkey', __( 'Sorry, that key does not appear to be valid.', 'theme-my-login' ) );
  239. do_action( 'lost_password' );
  240. break;
  241. case 'resetpass' :
  242. case 'rp' :
  243. $user = $this->check_password_reset_key( $_REQUEST['key'], $_REQUEST['login'] );
  244. if ( is_wp_error( $user ) ) {
  245. wp_redirect( Theme_My_Login::get_current_url( 'action=lostpassword&error=invalidkey' ) );
  246. exit;
  247. }
  248. $errors = '';
  249. if ( isset( $_POST['pass1'] ) && $_POST['pass1'] != $_POST['pass2'] ) {
  250. $errors = new WP_Error( 'password_reset_mismatch', __( 'The passwords do not match.', 'theme-my-login' ) );
  251. } elseif ( isset( $_POST['pass1'] ) && !empty( $_POST['pass1'] ) ) {
  252. $this->reset_password( $user, $_POST['pass1'] );
  253. $redirect_to = Theme_My_Login::get_current_url( 'resetpass=complete' );
  254. if ( isset( $_REQUEST['instance'] ) & !empty( $_REQUEST['instance'] ) )
  255. $redirect_to = add_query_arg( 'instance', $_REQUEST['instance'], $redirect_to );
  256. wp_safe_redirect( $redirect_to );
  257. exit();
  258. }
  259. wp_enqueue_script( 'utils' );
  260. wp_enqueue_script( 'user-profile' );
  261. break;
  262. case 'register' :
  263. if ( !get_option( 'users_can_register' ) ) {
  264. wp_redirect( Theme_My_Login::get_current_url( 'registration=disabled' ) );
  265. exit();
  266. }
  267. $user_login = '';
  268. $user_email = '';
  269. if ( $http_post ) {
  270. $user_login = $_POST['user_login'];
  271. $user_email = $_POST['user_email'];
  272. $errors = Theme_My_Login::register_new_user( $user_login, $user_email );
  273. if ( !is_wp_error( $errors ) ) {
  274. $redirect_to = !empty( $_POST['redirect_to'] ) ? $_POST['redirect_to'] : Theme_My_Login::get_current_url( 'checkemail=registered' );
  275. if ( !empty( $instance ) )
  276. $redirect_to = add_query_arg( 'instance', $instance, $redirect_to );
  277. $redirect_to = apply_filters( 'register_redirect', $redirect_to );
  278. wp_safe_redirect( $redirect_to );
  279. exit();
  280. }
  281. }
  282. break;
  283. case 'login' :
  284. default:
  285. $secure_cookie = '';
  286. $interim_login = isset( $_REQUEST['interim-login'] );
  287. // If the user wants ssl but the session is not ssl, force a secure cookie.
  288. if ( !empty( $_POST['log'] ) && !force_ssl_admin() ) {
  289. $user_name = sanitize_user( $_POST['log'] );
  290. if ( $user = get_user_by( 'login', $user_name ) ) {
  291. if ( get_user_option( 'use_ssl', $user->ID ) ) {
  292. $secure_cookie = true;
  293. force_ssl_admin( true );
  294. }
  295. }
  296. }
  297. if ( !empty( $_REQUEST['redirect_to'] ) ) {
  298. $redirect_to = $_REQUEST['redirect_to'];
  299. // Redirect to https if user wants ssl
  300. if ( $secure_cookie && false !== strpos( $redirect_to, 'wp-admin' ) )
  301. $redirect_to = preg_replace( '|^http://|', 'https://', $redirect_to );
  302. } else {
  303. $redirect_to = admin_url();
  304. }
  305. $reauth = empty( $_REQUEST['reauth'] ) ? false : true;
  306. // If the user was redirected to a secure login form from a non-secure admin page, and secure login is required but secure admin is not, then don't use a secure
  307. // cookie and redirect back to the referring non-secure admin page. This allows logins to always be POSTed over SSL while allowing the user to choose visiting
  308. // the admin via http or https.
  309. if ( !$secure_cookie && is_ssl() && force_ssl_login() && !force_ssl_admin() && ( 0 !== strpos( $redirect_to, 'https' ) ) && ( 0 === strpos( $redirect_to, 'http' ) ) )
  310. $secure_cookie = false;
  311. if ( $http_post && isset( $_POST['log'] ) ) {
  312. // Set a cookie now to see if they are supported by the browser.
  313. setcookie( TEST_COOKIE, 'WP Cookie check', 0, COOKIEPATH, COOKIE_DOMAIN );
  314. if ( SITECOOKIEPATH != COOKIEPATH )
  315. setcookie( TEST_COOKIE, 'WP Cookie check', 0, SITECOOKIEPATH, COOKIE_DOMAIN );
  316. $user = wp_signon( '', $secure_cookie );
  317. $redirect_to = apply_filters( 'login_redirect', $redirect_to, isset( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : '', $user );
  318. if ( !is_wp_error( $user ) && !$reauth ) {
  319. if ( ( empty( $redirect_to ) || $redirect_to == 'wp-admin/' || $redirect_to == admin_url() ) ) {
  320. // 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.
  321. if ( is_multisite() && !get_active_blog_for_user( $user->ID ) && !is_super_admin( $user->ID ) )
  322. $redirect_to = user_admin_url();
  323. elseif ( is_multisite() && !$user->has_cap( 'read' ) )
  324. $redirect_to = get_dashboard_url( $user->ID );
  325. elseif ( !$user->has_cap( 'edit_posts' ) )
  326. $redirect_to = admin_url( 'profile.php' );
  327. }
  328. wp_safe_redirect( $redirect_to );
  329. exit();
  330. }
  331. $errors = $user;
  332. }
  333. $this->redirect_to = $redirect_to;
  334. // Clear errors if loggedout is set.
  335. if ( !empty( $_GET['loggedout'] ) || $reauth )
  336. $errors = new WP_Error();
  337. // If cookies are disabled we can't log in even with a valid user+pass
  338. if ( isset( $_POST['testcookie'] ) && empty( $_COOKIE[TEST_COOKIE] ) )
  339. $errors->add( 'test_cookie', __( '<strong>ERROR</strong>: Cookies are blocked or not supported by your browser. You must <a href="http://www.google.com/cookies.html">enable cookies</a> to use WordPress.', 'theme-my-login' ) );
  340. // Some parts of this script use the main login form to display a message
  341. if ( isset( $_GET['loggedout'] ) && true == $_GET['loggedout'] )
  342. $errors->add( 'loggedout', __( 'You are now logged out.', 'theme-my-login' ), 'message' );
  343. elseif ( isset( $_GET['registration'] ) && 'disabled' == $_GET['registration'] )
  344. $errors->add( 'registerdisabled', __( 'User registration is currently not allowed.', 'theme-my-login' ) );
  345. elseif ( isset( $_GET['checkemail'] ) && 'confirm' == $_GET['checkemail'] )
  346. $errors->add( 'confirm', __( 'Check your e-mail for the confirmation link.', 'theme-my-login' ), 'message' );
  347. elseif ( isset( $_GET['resetpass'] ) && 'complete' == $_GET['resetpass'] )
  348. $errors->add( 'password_reset', __( 'Your password has been reset.', 'theme-my-login' ), 'message' );
  349. elseif ( isset( $_GET['checkemail'] ) && 'registered' == $_GET['checkemail'] )
  350. $errors->add( 'registered', __( 'Registration complete. Please check your e-mail.', 'theme-my-login' ), 'message' );
  351. elseif ( $interim_login )
  352. $errors->add( 'expired', __( 'Your session has expired. Please log-in again.', 'theme-my-login' ), 'message' );
  353. elseif ( strpos( $redirect_to, 'about.php?updated' ) )
  354. $errors->add('updated', __( '<strong>You have successfully updated WordPress!</strong> Please log back in to experience the awesomeness.' ), 'message' );
  355. elseif ( $reauth )
  356. $errors->add( 'reauth', __( 'Please log in to continue.', 'theme-my-login' ), 'message' );
  357. // Clear any stale cookies.
  358. if ( $reauth )
  359. wp_clear_auth_cookie();
  360. break;
  361. } // end switch
  362. } // endif has_filter()
  363. }
  364. /**
  365. * Used to add/remove filters from login page
  366. *
  367. * @since 6.1.1
  368. * @access public
  369. */
  370. function wp() {
  371. global $wp_version;
  372. if ( $this->is_login_page() ) {
  373. do_action( 'login_init' );
  374. remove_action( 'wp_head', 'feed_links', 2 );
  375. remove_action( 'wp_head', 'feed_links_extra', 3 );
  376. remove_action( 'wp_head', 'rsd_link' );
  377. remove_action( 'wp_head', 'wlwmanifest_link' );
  378. remove_action( 'wp_head', 'parent_post_rel_link', 10, 0 );
  379. remove_action( 'wp_head', 'start_post_rel_link', 10, 0 );
  380. remove_action( 'wp_head', 'adjacent_posts_rel_link_wp_head', 10, 0 );
  381. remove_action( 'wp_head', 'rel_canonical' );
  382. // Don't index any of these forms
  383. if ( version_compare( $wp_version, '3.3', '<' ) ) {
  384. add_filter( 'pre_option_blog_public', '__return_zero' );
  385. add_action( 'login_head', 'noindex' );
  386. } else {
  387. add_action( 'login_head', 'wp_no_robots' );
  388. }
  389. if ( force_ssl_admin() && !is_ssl() ) {
  390. if ( 0 === strpos( $_SERVER['REQUEST_URI'], 'http' ) ) {
  391. wp_redirect( preg_replace( '|^http://|', 'https://', $_SERVER['REQUEST_URI'] ) );
  392. exit();
  393. } else {
  394. wp_redirect( 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
  395. exit();
  396. }
  397. }
  398. }
  399. }
  400. /**
  401. * Returns link for login page
  402. *
  403. * @since 6.0
  404. * @access public
  405. *
  406. * @param string|array $query Optional. Query arguments to add to link
  407. * @return string Login page link with optional $query arguments appended
  408. */
  409. function get_login_page_link( $query = '' ) {
  410. global $wp_rewrite;
  411. $q = wp_parse_args( $query );
  412. $page = get_page( $this->options->get_option( 'page_id' ) );
  413. $link = $wp_rewrite->get_page_permastruct();
  414. if ( !empty( $link ) ) {
  415. $link = str_replace( '%pagename%', get_page_uri( $page->ID ), $link );
  416. $action = isset( $q['action'] ) ? $q['action'] : 'login';
  417. if ( $slug = $this->options->get_option( array( 'permalinks', $action ) ) ) {
  418. $link = str_replace( $page->post_name, $slug, $link );
  419. unset( $q['action'] );
  420. }
  421. $link = home_url( $link );
  422. $link = user_trailingslashit( $link, 'page' );
  423. } else {
  424. $link = home_url( "?page_id={$page->ID}" );
  425. }
  426. if ( !empty( $q ) )
  427. $link = add_query_arg( $q, $link );
  428. return apply_filters( 'tml_page_link', $link, $query );
  429. }
  430. /**
  431. * Changes login page link to custom permalink
  432. *
  433. * Callback for "page_link" filter in get_page_link()
  434. *
  435. * @see get_page_link()
  436. * @since 6.2
  437. * @access public
  438. *
  439. * @param string $link Page link
  440. * @param int $id Page ID
  441. * @return string Page link
  442. */
  443. function page_link( $link, $id ) {
  444. if ( $this->is_login_page( $id ) )
  445. return $this->get_login_page_link();
  446. return $link;
  447. }
  448. /**
  449. * Changes redirect URL to login page permalink for specific actions
  450. *
  451. * Callback for "tml_redirect_url" filter in Theme_My_Login_Template::get_redirect_url()
  452. *
  453. * @since 6.2
  454. * @access public
  455. *
  456. * @param string $url Redirect URL
  457. * @param string $action Requested action
  458. * @return string Redirect URL
  459. */
  460. function tml_redirect_url( $url, $action ) {
  461. global $wp_rewrite;
  462. if ( $wp_rewrite->using_permalinks() && $this->is_login_page() && $this->request_action == $action ) {
  463. if ( $slug = $this->options->get_option( 'permalinks', $action ) ) {
  464. switch ( $action ) {
  465. case 'lostpassword' :
  466. case 'retrievepassword' :
  467. case 'register' :
  468. $permalink = $this->get_login_page_link();
  469. $parsed_permalink = parse_url( $permalink );
  470. $parsed_url = parse_url( $url );
  471. $url = str_replace( $parsed_url['path'], $parsed_permalink['path'], $url );
  472. break;
  473. }
  474. }
  475. }
  476. return $url;
  477. }
  478. /**
  479. * Changes the_title() to reflect the current action
  480. *
  481. * Callback for "the_title" hook in the_title()
  482. *
  483. * @see the_title()
  484. * @since 6.0
  485. * @acess public
  486. *
  487. * @param string $title The current post title
  488. * @param int $post_id The current post ID
  489. * @return string The modified post title
  490. */
  491. function the_title( $title, $post_id = 0 ) {
  492. if ( is_admin() )
  493. return $title;
  494. if ( $this->is_login_page( $post_id ) ) {
  495. if ( !in_the_loop() ) {
  496. $title = is_user_logged_in() ? __( 'Log Out', 'theme-my-login' ) : __( 'Log In', 'theme-my-login' );
  497. } else {
  498. $action = empty( $this->request_instance ) ? $this->request_action : 'login';
  499. $title = Theme_My_Login_Template::get_title( $action );
  500. }
  501. }
  502. return $title;
  503. }
  504. /**
  505. * Changes single_post_title() to reflect the current action
  506. *
  507. * Callback for "single_post_title" hook in single_post_title()
  508. *
  509. * @see single_post_title()
  510. * @since 6.0
  511. * @access public
  512. *
  513. * @param string $title The current post title
  514. * @return string The modified post title
  515. */
  516. function single_post_title( $title ) {
  517. if ( $this->is_login_page() ) {
  518. $action = empty( $this->request_instance ) ? $this->request_action : 'login';
  519. $title = Theme_My_Login_Template::get_title( $action );
  520. }
  521. return $title;
  522. }
  523. /**
  524. * Excludes TML page if set in the admin
  525. *
  526. * Callback for "wp_list_pages_excludes" hook in wp_list_pages()
  527. *
  528. * @see wp_list_pages()
  529. * @since 6.0
  530. * @access public
  531. *
  532. * @param array $exclude_array Array of excluded pages
  533. * @return array Modified array of excluded pages
  534. */
  535. function wp_list_pages_excludes( $exclude_array ) {
  536. $exclude_array = (array) $exclude_array;
  537. if ( !$this->options->get_option( 'show_page' ) )
  538. $exclude_array[] = $this->options->get_option( 'page_id' );
  539. return $exclude_array;
  540. }
  541. /**
  542. * Changes login link to logout if user is logged in
  543. *
  544. * Callback for "wp_list_pages" hook in wp_list_pages()
  545. *
  546. * @see wp_list_pages()
  547. * @since 6.0
  548. * @access public
  549. *
  550. * @param string $output The output
  551. * @return string The filtered output
  552. */
  553. function wp_list_pages( $output ) {
  554. if ( is_user_logged_in() )
  555. $output = str_replace( '"' . $this->get_login_page_link() . '"', '"' . wp_logout_url() . '"', $output );
  556. return $output;
  557. }
  558. /**
  559. * Alters menu item title & link according to whether user is logged in or not
  560. *
  561. * Callback for "wp_setup_nav_menu_item" hook in wp_setup_nav_menu_item()
  562. *
  563. * @see wp_setup_nav_menu_item()
  564. * @since 6.0
  565. * @access public
  566. *
  567. * @param object $menu_item The menu item
  568. * @return object The (possibly) modified menu item
  569. */
  570. function wp_setup_nav_menu_item( $menu_item ) {
  571. if ( 'page' == $menu_item->object && $this->is_login_page( $menu_item->object_id ) ) {
  572. $menu_item->title = $this->the_title( $menu_item->title, $menu_item->object_id );
  573. $menu_item->url = is_user_logged_in() ? wp_logout_url() : $this->get_login_page_link();
  574. }
  575. return $menu_item;
  576. }
  577. /**
  578. * Handler for "theme-my-login" shortcode
  579. *
  580. * Optional $atts contents:
  581. *
  582. * - instance - A unqiue instance ID for this instance.
  583. * - default_action - The action to display. Defaults to "login".
  584. * - login_template - The template used for the login form. Defaults to "login-form.php".
  585. * - register_template - The template used for the register form. Defaults to "register-form.php".
  586. * - lostpassword_template - The template used for the lost password form. Defaults to "lostpassword-form.php".
  587. * - resetpass_template - The template used for the reset password form. Defaults to "resetpass-form.php".
  588. * - user_template - The templated used for when a user is logged in. Defalts to "user-panel.php".
  589. * - show_title - True to display the current title, false to hide. Defaults to true.
  590. * - show_log_link - True to display the login link, false to hide. Defaults to true.
  591. * - show_reg_link - True to display the register link, false to hide. Defaults to true.
  592. * - show_pass_link - True to display the lost password link, false to hide. Defaults to true.
  593. * - register_widget - True to allow registration in widget, false to send to register page. Defaults to false.
  594. * - lostpassword_widget - True to allow password recovery in widget, false to send to lost password page. Defaults to false.
  595. * - logged_in_widget - True to display the widget when logged in, false to hide. Defaults to true.
  596. * - show_gravatar - True to display the user's gravatar, false to hide. Defaults to true.
  597. * - gravatar_size - The size of the user's gravatar. Defaults to "50".
  598. *
  599. * @since 6.0
  600. * @access public
  601. *
  602. * @param string|array $atts Attributes passed from the shortcode
  603. * @return string HTML output from Theme_My_Login_Template->display()
  604. */
  605. function shortcode( $atts = '' ) {
  606. if ( $this->is_login_page() && in_the_loop() ) {
  607. $atts['instance'] = '';
  608. $atts['show_title'] = false;
  609. } else {
  610. if ( !isset( $atts['instance'] ) )
  611. $atts['instance'] = $this->get_new_instance();
  612. }
  613. $template =& new Theme_My_Login_Template( $atts );
  614. return $template->display();
  615. }
  616. /**
  617. * Incremenets $this->count and returns it
  618. *
  619. * @since 6.0
  620. * @access public
  621. *
  622. * @return int New value of $this->count
  623. */
  624. function get_new_instance() {
  625. $this->count++;
  626. return $this->count;
  627. }
  628. /**
  629. * Returns current URL
  630. *
  631. * @since 6.0
  632. * @access public
  633. *
  634. * @param string $query Optionally append query to the current URL
  635. * @return string URL with optional path appended
  636. */
  637. function get_current_url( $query = '' ) {
  638. $url = remove_query_arg( array( 'instance', 'action', 'checkemail', 'error', 'loggedout', 'registered', 'redirect_to', 'updated', 'key', '_wpnonce', 'reauth', 'login' ) );
  639. if ( !empty( $query ) ) {
  640. $r = wp_parse_args( $query );
  641. foreach ( $r as $k => $v ) {
  642. if ( strpos( $v, ' ' ) !== false )
  643. $r[$k] = rawurlencode( $v );
  644. }
  645. $url = add_query_arg( $r, $url );
  646. }
  647. return $url;
  648. }
  649. /**
  650. * Rewrites URL's containing wp-login.php created by site_url()
  651. *
  652. * @since 6.0
  653. * @access public
  654. *
  655. * @param string $url The URL
  656. * @param string $path The path specified
  657. * @param string $orig_scheme The current connection scheme (HTTP/HTTPS)
  658. * @return string The modified URL
  659. */
  660. function site_url( $url, $path, $orig_scheme ) {
  661. global $pagenow;
  662. if ( 'wp-login.php' != $pagenow && strpos( $url, 'wp-login.php' ) !== false && !isset( $_REQUEST['interim-login'] ) ) {
  663. $parsed_url = parse_url( $url );
  664. $url = $this->get_login_page_link();
  665. if ( 'https' == strtolower( $orig_scheme ) )
  666. $url = preg_replace( '|^http://|', 'https://', $url );
  667. if ( isset( $parsed_url['query'] ) ) {
  668. wp_parse_str( $parsed_url['query'], $r );
  669. foreach ( $r as $k => $v ) {
  670. if ( strpos($v, ' ') !== false )
  671. $r[$k] = rawurlencode( $v );
  672. }
  673. $url = add_query_arg( $r, $url );
  674. }
  675. }
  676. return $url;
  677. }
  678. /**
  679. * Enqueues the specified sylesheet
  680. *
  681. * First looks in theme/template directories for the stylesheet, falling back to plugin directory
  682. *
  683. * @since 6.0
  684. * @access public
  685. *
  686. * @param string $file Filename of stylesheet to load
  687. * @return string Path to stylesheet
  688. */
  689. function get_stylesheet( $file = 'theme-my-login.css' ) {
  690. if ( file_exists( get_stylesheet_directory() . '/' . $file ) )
  691. $stylesheet = get_stylesheet_directory_uri() . '/' . $file;
  692. elseif ( file_exists( get_template_directory() . '/' . $file ) )
  693. $stylesheet = get_template_directory_uri() . '/' . $file;
  694. else
  695. $stylesheet = plugins_url( '/theme-my-login/' . $file );
  696. return $stylesheet;
  697. }
  698. /**
  699. * Prints javascript in the footer
  700. *
  701. * @since 6.0
  702. * @access public
  703. */
  704. function print_footer_scripts() {
  705. if ( !$this->is_login_page() )
  706. return;
  707. $action = empty( $this->request_action ) ? 'login' : $this->request_action;
  708. switch ( $action ) {
  709. case 'lostpassword' :
  710. case 'retrievepassword' :
  711. case 'register' :
  712. ?>
  713. <script type="text/javascript">
  714. try{document.getElementById('user_login<?php echo $this->request_instance; ?>').focus();}catch(e){}
  715. if(typeof wpOnload=='function')wpOnload()
  716. </script>
  717. <?php
  718. break;
  719. case 'login' :
  720. $user_login = '';
  721. if ( isset($_POST['log']) )
  722. $user_login = ( 'incorrect_password' == $this->errors->get_error_code() || 'empty_password' == $this->errors->get_error_code() ) ? esc_attr( stripslashes( $_POST['log'] ) ) : '';
  723. ?>
  724. <script type="text/javascript">
  725. function wp_attempt_focus() {
  726. setTimeout( function() {
  727. try {
  728. <?php if ( $user_login ) { ?>
  729. d = document.getElementById('user_pass<?php echo $this->request_instance; ?>');
  730. <?php } else { ?>
  731. d = document.getElementById('user_login<?php echo $this->request_instance; ?>');
  732. <?php } ?>
  733. d.value = '';
  734. d.focus();
  735. } catch(e){}
  736. }, 200 );
  737. }
  738. wp_attempt_focus();
  739. if(typeof wpOnload=='function')wpOnload()
  740. </script>
  741. <?php
  742. break;
  743. }
  744. }
  745. /**
  746. * Calls "login_head" hook on login page
  747. *
  748. * Callback for "wp_head" hook
  749. *
  750. * @since 6.0
  751. * @access public
  752. */
  753. function login_head() {
  754. if ( $this->is_login_page() ) {
  755. do_action( 'login_enqueue_scripts' );
  756. do_action( 'login_head' );
  757. }
  758. }
  759. /**
  760. * Merges arrays recursively, replacing duplicate string keys
  761. *
  762. * @since 6.0
  763. * @access public
  764. */
  765. function array_merge_recursive() {
  766. $args = func_get_args();
  767. $result = array_shift( $args );
  768. foreach ( $args as $arg ) {
  769. foreach ( $arg as $key => $value ) {
  770. // Renumber numeric keys as array_merge() does.
  771. if ( is_numeric( $key ) ) {
  772. if ( !in_array( $value, $result ) )
  773. $result[] = $value;
  774. }
  775. // Recurse only when both values are arrays.
  776. elseif ( array_key_exists( $key, $result ) && is_array( $result[$key] ) && is_array( $value ) ) {
  777. $result[$key] = Theme_My_Login::array_merge_recursive( $result[$key], $value );
  778. }
  779. // Otherwise, use the latter value.
  780. else {
  781. $result[$key] = $value;
  782. }
  783. }
  784. }
  785. return $result;
  786. }
  787. /**
  788. * Returns active and valid TML modules
  789. *
  790. * Returns all valid modules specified via $this->options['active_modules']
  791. *
  792. * @since 6.0
  793. * @access public
  794. */
  795. function get_active_and_valid_modules() {
  796. $modules = array();
  797. $active_modules = apply_filters( 'tml_active_modules', $this->options->get_option( 'active_modules' ) );
  798. foreach ( (array) $active_modules as $module ) {
  799. // check the $plugin filename
  800. // Validate plugin filename
  801. if ( !validate_file( $module ) // $module must validate as file
  802. || '.php' == substr( $module, -4 ) // $module must end with '.php'
  803. || file_exists( TML_ABSPATH . '/modules/' . $module ) // $module must exist
  804. )
  805. $modules[] = TML_ABSPATH . '/modules/' . $module;
  806. }
  807. return $modules;
  808. }
  809. /**
  810. * Determine if $module is an active TML module
  811. *
  812. * @since 6.0
  813. * @access public
  814. *
  815. * @param string $module Filename of module to check
  816. * @return bool True if $module is active, false if not
  817. */
  818. function is_module_active( $module ) {
  819. $active_modules = apply_filters( 'tml_active_modules', $this->options->get_option( 'active_modules' ) );
  820. return in_array( $module, (array) $active_modules );
  821. }
  822. /**
  823. * Handles e-mail address login
  824. *
  825. * @since 6.0
  826. * @access public
  827. *
  828. * @param string $username Username or email
  829. * @param string $password User's password
  830. */
  831. function wp_authenticate( &$user_login ) {
  832. global $wpdb;
  833. if ( is_email( $user_login ) && $this->options->get_option( 'email_login' ) ) {
  834. if ( $found = $wpdb->get_var( $wpdb->prepare( "SELECT user_login FROM $wpdb->users WHERE user_email = %s", $user_login ) ) )
  835. $user_login = $found;
  836. }
  837. return;
  838. }
  839. /**
  840. * Handles sending password retrieval email to user.
  841. *
  842. * @since 6.0
  843. * @access public
  844. * @uses $wpdb WordPress Database object
  845. *
  846. * @return bool|WP_Error True: when finish. WP_Error on error
  847. */
  848. function retrieve_password() {
  849. global $wpdb, $current_site;
  850. $errors = new WP_Error();
  851. if ( empty( $_POST['user_login'] ) ) {
  852. $errors->add( 'empty_username', __( '<strong>ERROR</strong>: Enter a username or e-mail address.', 'theme-my-login' ) );
  853. } else if ( strpos( $_POST['user_login'], '@' ) ) {
  854. $user_data = get_user_by_email( trim( $_POST['user_login'] ) );
  855. if ( empty( $user_data ) )
  856. $errors->add( 'invalid_email', __( '<strong>ERROR</strong>: There is no user registered with that email address.', 'theme-my-login' ) );
  857. } else {
  858. $login = trim( $_POST['user_login'] );
  859. $user_data = get_user_by( 'login', $login );
  860. }
  861. do_action( 'lostpassword_post' );
  862. if ( $errors->get_error_code() )
  863. return $errors;
  864. if ( !$user_data ) {
  865. $errors->add( 'invalidcombo', __( '<strong>ERROR</strong>: Invalid username or e-mail.', 'theme-my-login' ) );
  866. return $errors;
  867. }
  868. // redefining user_login ensures we return the right case in the email
  869. $user_login = $user_data->user_login;
  870. $user_email = $user_data->user_email;
  871. do_action( 'retreive_password', $user_login ); // Misspelled and deprecated
  872. do_action( 'retrieve_password', $user_login );
  873. $allow = apply_filters( 'allow_password_reset', true, $user_data->ID );
  874. if ( !$allow )
  875. return new WP_Error( 'no_password_reset', __( 'Password reset is not allowed for this user', 'theme-my-login' ) );
  876. else if ( is_wp_error( $allow ) )
  877. return $allow;
  878. $key = $wpdb->get_var( $wpdb->prepare( "SELECT user_activation_key FROM $wpdb->users WHERE user_login = %s", $user_login ) );
  879. if ( empty( $key ) ) {
  880. // Generate something random for a key...
  881. $key = wp_generate_password( 20, false );
  882. do_action( 'retrieve_password_key', $user_login, $key );
  883. // Now insert the new md5 key into the db
  884. $wpdb->update( $wpdb->users, array( 'user_activation_key' => $key ), array( 'user_login' => $user_login ) );
  885. }
  886. $message = __( 'Someone requested that the password be reset for the following account:', 'theme-my-login' ) . "\r\n\r\n";
  887. $message .= network_home_url( '/' ) . "\r\n\r\n";
  888. $message .= sprintf( __( 'Username: %s', 'theme-my-login' ), $user_login ) . "\r\n\r\n";
  889. $message .= __( 'If this was a mistake, just ignore this email and nothing will happen.', 'theme-my-login' ) . "\r\n\r\n";
  890. $message .= __( 'To reset your password, visit the following address:', 'theme-my-login' ) . "\r\n\r\n";
  891. $message .= '<' . network_site_url( "wp-login.php?action=rp&key=$key&login=" . rawurlencode( $user_login ), 'login' ) . ">\r\n";
  892. if ( is_multisite() ) {
  893. $blogname = $current_site->site_name;
  894. } else {
  895. // The blogname option is escaped with esc_html on the way into the database in sanitize_option
  896. // we want to reverse this for the plain text arena of emails.
  897. $blogname = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
  898. }
  899. $title = sprintf( __( '[%s] Password Reset', 'theme-my-login' ), $blogname );
  900. $title = apply_filters( 'retrieve_password_title', $title, $user_data->ID );
  901. $message = apply_filters( 'retrieve_password_message', $message, $key, $user_data->ID );
  902. if ( $message && !wp_mail( $user_email, $title, $message ) )
  903. wp_die( __( 'The e-mail could not be sent.', 'theme-my-login' ) . "<br />\n" . __( 'Possible reason: your host may have disabled the mail() function...', 'theme-my-login' ) );
  904. return true;
  905. }
  906. /**
  907. * Retrieves a user row based on password reset key and login
  908. *
  909. * @since 6.1.1
  910. * @access public
  911. * @uses $wpdb WordPress Database object
  912. *
  913. * @param string $key Hash to validate sending user's password
  914. * @param string $login The user login
  915. *
  916. * @return object|WP_Error
  917. */
  918. function check_password_reset_key( $key, $login ) {
  919. global $wpdb;
  920. $key = preg_replace( '/[^a-z0-9]/i', '', $key );
  921. if ( empty( $key ) || !is_string( $key ) )
  922. return new WP_Error( 'invalid_key', __( 'Invalid key', 'theme-my-login' ) );
  923. if ( empty( $login ) || !is_string( $login ) )
  924. return new WP_Error( 'invalid_key', __( 'Invalid key', 'theme-my-login' ) );
  925. $user = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->users WHERE user_activation_key = %s AND user_login = %s", $key, $login ) );
  926. if ( empty( $user ) )
  927. return new WP_Error( 'invalid_key', __( 'Invalid key', 'theme-my-login' ) );
  928. return $user;
  929. }
  930. /**
  931. * Handles resetting the user's password.
  932. *
  933. * @since 6.0
  934. * @access public
  935. * @uses $wpdb WordPress Database object
  936. *
  937. * @param string $key Hash to validate sending user's password
  938. */
  939. function reset_password( $user, $new_pass ) {
  940. do_action( 'password_reset', $user, $new_pass );
  941. wp_set_password( $new_pass, $user->ID );
  942. do_action_ref_array( 'tml_user_password_changed', array( &$user ) );
  943. }
  944. /**
  945. * Handles registering a new user.
  946. *
  947. * @since 6.0
  948. * @access public
  949. *
  950. * @param string $user_login User's username for logging in
  951. * @param string $user_email User's email address to send password and add
  952. * @return int|WP_Error Either user's ID or error on failure.
  953. */
  954. function register_new_user( $user_login, $user_email ) {
  955. $errors = new WP_Error();
  956. $sanitized_user_login = sanitize_user( $user_login );
  957. $user_email = apply_filters( 'user_registration_email', $user_email );
  958. // Check the username
  959. if ( $sanitized_user_login == '' ) {
  960. $errors->add( 'empty_username', __( '<strong>ERROR</strong>: Please enter a username.', 'theme-my-login' ) );
  961. } elseif ( !validate_username( $user_login ) ) {
  962. $errors->add( 'invalid_username', __( '<strong>ERROR</strong>: This username is invalid because it uses illegal characters. Please enter a valid username.', 'theme-my-login' ) );
  963. $sanitized_user_login = '';
  964. } elseif ( username_exists( $sanitized_user_login ) ) {
  965. $errors->add( 'username_exists', __( '<strong>ERROR</strong>: This username is already registered, please choose another one.', 'theme-my-login' ) );
  966. }
  967. // Check the e-mail address
  968. if ( '' == $user_email ) {
  969. $errors->add( 'empty_email', __( '<strong>ERROR</strong>: Please type your e-mail address.', 'theme-my-login' ) );
  970. } elseif ( !is_email( $user_email ) ) {
  971. $errors->add( 'invalid_email', __( '<strong>ERROR</strong>: The email address isn&#8217;t correct.', 'theme-my-login' ) );
  972. $user_email = '';
  973. } elseif ( email_exists( $user_email ) ) {
  974. $errors->add( 'email_exists', __( '<strong>ERROR</strong>: This email is already registered, please choose another one.', 'theme-my-login' ) );
  975. }
  976. do_action( 'register_post', $sanitized_user_login, $user_email, $errors );
  977. $errors = apply_filters( 'registration_errors', $errors, $sanitized_user_login, $user_email );
  978. if ( $errors->get_error_code() )
  979. return $errors;
  980. $user_pass = apply_filters( 'tml_user_registration_pass', wp_generate_password( 12, false ) );
  981. $user_id = wp_create_user( $sanitized_user_login, $user_pass, $user_email );
  982. if ( !$user_id ) {
  983. $errors->add( 'registerfail', sprintf( __( '<strong>ERROR</strong>: Couldn&#8217;t register you... please contact the <a href="mailto:%s">webmaster</a> !', 'theme-my-login' ), get_option( 'admin_email' ) ) );
  984. return $errors;
  985. }
  986. update_user_option( $user_id, 'default_password_nag', true, true ); //Set up the Password change nag.
  987. do_action( 'tml_new_user_registered', $user_id, $user_pass );
  988. return $user_id;
  989. }
  990. }
  991. endif; // Class exists
  992. ?>