Wordpress one time access to password protected page - wordpress

I am creating a wordpress page which is password protected. It holds a form which needs to be submitted after a timed period of 3h. After that period the user should be logged out, no matter wether he completed the form or not. He should not be able to log in again.
As of now I achieved to set a timer after which the content of the page disappears. Now I need a tool that prevents a particular user to log back in and resubmit the form. Users do not get registered on my site. I want to email them a password for the protected page.
I can't simply change the password after login because as of now the page is protected by one password that every potential user needs to use.
To me the easiest way to avoid relogin seems to be the issuing of one time passwords for this particular page, so upon request every user gets his own OTP.
I am looking for a plugin which generates a list of OTPs for a specific wp page.
Easy solutions are greatly appreciated, since I am not seasoned at coding!
THANK YOU FOR YOUR HELP. Everybody starts somewhere...😔

Something like this (not tested):
$token = $_GET[ 'token' ];
if( is_numeric( $token ) AND metadata_exists( 'post', get_the_ID(), 'token_' . $token ) ):
if( empty( get_metadata( 'post', get_the_ID(), 'token_' . $token, true ) ) )
update_metadata( 'post', get_the_ID(), 'token_' . $token, time() + ( HOUR_IN_SECONDS * 3 );
if( $stamp = get_metadata( 'post', get_the_ID(), 'token_' . $token, true ) < time() ):
echo 'Here goes your form';
echo 'You have ' . $stamp - time() . ' seconds.';
else:
echo 'nope';
delete_metadata( 'post', get_the_ID(), 'token_' . $token )
endif;
else:
echo 'nope';
endif;
So you just have to create a empty postmeta field like token_98751328475 and share the url like example.com/myformpage?token=98751328475.
I would probably create a confirmation page to start the timer so that it doesn't start on first call.

Related

STOP sending new user registration password as plain text in Wordpress through email

When a new user register on a WooCommerce site user got an email about confirmation message which contain the current registration info with username and password. The main issue is the password is pain text like
Username = xcorola
Password = 123456
How can I stop sending plain text password to user email. or is there any way to override the wp_new_user_notification() ?
$message = sprintf(__('Username: %s'), $user - > user_login)."\r\n";
$message. = sprintf(__('Password: %s'), $plaintext_pass)."\r\n";
I saw your question as I ran into to the exact same problem! I have spend over 10 hours digging into the Wordpress backend to find the responsible function, and lucky for anyone in the future, I found the following neat solution!
How to make Wordpress new user registration email contain a 'set password'-link, instead plain-text password:
In the first step we will create our own function to return a set-password url. You can simply add this codeblock in Themes → Theme editor → functions.php (right pane)
/**
* This function invokes the get_password_reset_key to invoke generation of a nonce in the backend db,
* and returns the key. It then constructs a http query to the lost-password endpoint
* M.G.Poirot 2021
*/
function get_password_reset_link( $user_login = null ) {
$base_url = wc_get_endpoint_url( 'lost-password', '', wc_get_page_permalink( 'myaccount' ) );
$userdata = get_user_by('login', $user_login);
$user_id = $userdata -> ID;
$key = get_password_reset_key( $userdata );
if ( ! is_wp_error( $key ) ) {
$base_url .= '?' . http_build_query( array ( 'key' => $key, 'id' => $user_id ) ) ;
}
// If retrieving the key fails, we still return the url that sends the user
// to enter their e-mail and start the regular password reset procedure.
return $base_url;
}
In this second step we will make the e-mail template editable that is currently sending plain text passwords. For me I had to follow the following buttons, but it might differ depending on your application:
Go to Woocommerce → Settings → E-mails → New account → Manage
Press Copy to Theme. This will make it possible to edit this
e-mail template
Now go to this template. You can find it at Themes → Theme editor → Theme files (right pane) → woocommerce → emails → customer_new_account.php
Here, replace:
 
<p>
<?php printf( esc_html__( 'Your password has been automatically generated: %s', 'woocommerce' ), '<strong>' . esc_html( $user_pass ) . '</strong>' ); ?>
</p>
With:
<p>
<a class="link" href="<?php echo ; ?>"><?php // phpcs:ignore ?>
<?php esc_html_e( 'Click here to set your password', 'woocommerce' ); ?>
</a>
</p>
Hope this works for everyone. People with more knowledge about PHP can probably add the clarity and robustness of the function!

Wordpress plugin form submitting to database on every browser refresh

I am developing a wordpress plugin, backend is working as I need but I am facing issue in frontend, I have created a shortcode page from I am posting few values to next page but when I refresh the next it is sending values to database again and again. I want to stop it, here is function:
function technician_checklist_report_generated(){
global $current_user;
global $wpdb;
$submit="";
if($_POST['customerid']!=""){
$crow = $wpdb->get_row( 'SELECT customer_id, firstname, lastname, createdon, marina, vesselmodel, vesselname, vesselyear
FROM wp_yacht_customers
WHERE customer_id= '.$_POST['customerid']
);
}
if($crow->customer_id!=""){
$table = 'wp_yatch_vessel_config_checklist';
array_pop($_POST); // delete last element in post array (submit)
$data = $_POST;
$format;
$wpdb->insert( $table, $data, $format );
}
require(dirname(__FILE__) .'/view/technician-start-reporting.php');
}
add_shortcode('technician-start-reporting',
'technician_checklist_report_generated');
When I reach to technician-start-reporting page it is sending data to MySQL again and again on browser refresh.
Is there any other way to go another page because I used wp_redirect and it showing error "header already sent... :
You can only use wp_redirect before content is sent to the browser.
Rather than process the form in the template[insite shortcode], you can hook an earlier action, like wp_loaded (this will be triggered before headers being sent).
<?php
add_action( 'wp_loaded', 'wpv_process_form' );
function wpv_process_form(){
if( isset( $_POST['customerid'] ) ):
// process form, and then
wp_redirect( get_permalink( $pid ) ); // redirect to desired page id
exit();
endif;
}
this way you'll be using less queries too.

Link login of two completely separate wordpress websites

I have two wordpress websites running on sub-domain of a server like http://first.mywebsites.net and http://second.mywebsites.net
They both are just like private sites, I can see the content of pages if I am logged in to the website otherwise redirected to the login page.
Now what I want is, if I am log in my first website and go to the link of second website in same browser then I am able to see the content of pages as a logged in user.
This must be happen only in a case when the user which is logged in first website having the same user(user registered with same mail id) in database of second website. As in case of my website, mostly users are registered with same mail id in both the websites.
Trying to achieve this by two approaches but still unable to get this by any of them :
Approach 1 : Adding a table to second website and save the user email and a auth key. Using curl to fetch the details and then logged in. This Approach is as mentioned in here : http://carlofontanos.com/auto-login-to-wordpress-from-another-website
But as I have mentioned it previous, that both the website is in my case are having private content, so in this case I am unable to fetch the details using curl. My code for curl is like :
$api_url = "http://second.mywebsites.net/autologin-api/";
// If you are using WordPress on website A, you can do the following to get the currently logged in user:
global $current_user;
$user_email = $current_user->user_email;
// Set the parameters
$params = array(
'action' => 'get_login_key', // The name of the action on Website B
'key' => '54321', // The key that was set on Website B for authentication purposes.
'user_email' => $user_email // Pass the user_email of the currently logged in user in Website A
);
// Send the data using cURL
$ch = curl_init($api_url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params));
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$gbi_response = curl_exec($ch);
curl_close($ch);
// Parse the response
parse_str($gbi_response);
print_r($gbi_response);
In this case I am not getting the response, My page redirect me to the login page of second website.
Approach 2 : Trying to do it with the use of cookies as I want to logged in to second website in same browser.
I have added a new cookie in my first website like :
global $current_user;
$user_email = $current_user->user_email;
if($user_email != ''){
$_COOKIE['current_user_mail_id'] = $user_email;
}
echo "<pre>";
print_r($_COOKIE);
echo "</pre>";
and added cookie is showing with the other cookies. But when I am checking this in my second website on same browser like :
echo "<pre>";
print_r($_COOKIE);
echo "</pre>";
The cookie which I have added in my first website is not showing on my second website.
I am not much familiar with cookies, setting auth cookies etc.
Please suggest a solution, how can I achieve this.
You can accomplished by using "Single Signon".
Instruction-
To simplify passing users between our systems I have created this PHP class
that you are welcome to use.
To check if a user is signed in:
$signon = new SingleSignon();
$userId = $signon->checkCookie();
if($userId){
// user is logged in and this is their id
}
else{
// user is not logged in or they are exipred
}
If the user is not logged in then use our api to login then use the following code if the api call is successful.
To set a user as logged in:
$signon = new SingleSignon();
$signon->setCookie($userId);
NOTE: You need to be using ssl for the cookie to be read.
I have gone through the solution provided by Gaurav and find a idea to make this possible for wordpress websites.
Place below mentioned code at the place where you want to put the link to go to your second website :
<?php global $current_user;
$user_email = $current_user->user_email;
$user_login = $current_user->user_login;
if($user_email != ''){
$email_encoded = rtrim(strtr(base64_encode($user_email), '+/', '-_'), '=');
$user_login_encoded = rtrim(strtr(base64_encode($user_login), '+/', '-_'), '=');
echo '<div class="dtNode">Link to second website</div>';
}?>
Now prepare a sso.php file and place it to the root installation of your second site where you want to logged in automatically. Now put the below code there :
<?php
require_once( 'wp-load.php' ); //put correct absolute path for this file
global $wpdb;
if(isset($_GET['key']) && !empty($_GET['key'])){
$email_decoded = base64_decode(strtr($_GET['key'], '-_', '+/'));
$username_decoded = base64_decode(strtr($_GET['detail'], '-_', '+/'));
$received_email = sanitize_text_field($email_decoded);
$received_username = sanitize_text_field($username_decoded);
if( email_exists( $received_email )) {
//get the user id for the user record exists for received email from database
$user_id = $wpdb->get_var($wpdb->prepare("SELECT * FROM wp_users WHERE user_email = %s", $received_email ) );
wp_set_auth_cookie( $user_id); //login the user
wp_redirect( 'http://second.mywebsites.net');
}else {
//register those user whose mail id does not exists in database
if(username_exists( $received_username )){
//if username coming from first site exists in our database for any other user,
//then the email id will be set as username
$userdata = array(
'user_login' => $received_email,
'user_email' => $received_email,
'user_pass' => $received_username, // password will be username always
'first_name' => $received_username, // first name willl be username
'role' => 'subscriber' //register the user with subscriber role only
);
}else {
$userdata = array(
'user_login' => $received_username,
'user_email' => $received_email,
'user_pass' => $received_username, // password will be username always
'first_name' => $received_username, // first name willl be username
'role' => 'subscriber' //register the user with subscriber role only
);
}
$user_id = wp_insert_user( $userdata ) ; // adding user to the database
//On success
if ( ! is_wp_error( $user_id ) ) {
wp_set_auth_cookie( $user_id); //login that newly created user
wp_redirect( 'http://second.mywebsites.net');
}else{
echo "There may be a mismatch of email/username with the existing record.
Check the users with your current email/username or try with any other account.";die;
}
}
die;
} ?>
Above code works for me, you can modify the code as per your needs. For more clear explanation, you can check here : http://www.wptricks24.com/auto-login-one-website-another-wordpress

Wordpress Signed On User Lost

I programmatically log in a user in Wordpress (before headers are sent), using a session variable from a previous page. Later in this same page, in the body section, I var_dump: wp_get_current_user(). This returns the WP_User I logged in with. In the 'log in' section I have tried combinations of wp_signon(), wp_set_current_user() and wp_set_auth_cookie().
The problem comes, when I navigate away from this page, the user isn't logged in anymore. When I use wp-login.php, the user stays logged in. I've struggled with this for quite a while and can't seem to find, why the user won't stay logged in.
Can someone help please. I'll add snippets of currently used code below:
$creds = array(
"user_login" => $_SESSION['email'],
"user_password" => $newPass,
"remember" => true
);
$user = wp_signon( $creds );
if ( is_a( $user, 'WP_User' ) ) {
wp_set_current_user( $user->ID, $user->user_login );
wp_set_auth_cookie( $user->ID, true );
}
// Code follows ...
<body>
<?php if ( is_user_logged_in() ) var_dump(wp_get_current_user()); ?>
Where is it being executed? You'll need to put it in an action. Use:
add_action('theme_setup','your_code');
function your_code(){
//signin code block goes here
};
I eventually moved a segment of the code to another file. Something I failed to include was that I used wp_create_user on the same page. As soon as I replaced wp_set_current_user and wp_set_auth_cookie with wp_signon and moved it to a separate page, everything worked perfectly.

Wordpress hook to authenticate user for pre-defined URLs

I'm building a fairly complex project that has many frontend editing pages. For example, add/edit/list custom post types, edit profile, and so on, all from the frontend.
At the moment I can of course check if user is logged in on each frontend login-walled page. However, this seems like a bad way of solving this problem as I'll have the same conditional on many pages and thus lots of repeated code.
I was thinking perhaps there is a better way where I could authenticate based on some hook (that I can't finds). I hoped I could do something like:
# create array of URLs where login is required
$needLoginArr = array(url1, url2, url3, ...)
# If current requested URL is in above array, then redirect or show different view based on whether or not user is logged in
It might not be practical in future to have conditional on each page as I plan on integrating within different plugins, so would be useful to use URL to authenticate.
I'm probably missing something here so if there's a better way please let me know.
Thanks
You could add your list of page IDs into an option:
$need_login = array(
'page1',
'page1/subpage',
'page2',
// and so forth
);
$need_login_ids = array();
foreach( $need_login as $p ) {
$pg = get_page_by_path( $p );
$need_login_ids[] = $pg->ID;
}
update_option( 'xyz_need_login', $need_login_ids );
Then, to check if your page is in the $need_login group:
add_filter( 'the_content', 'so20221037_authenticate' );
function so20221037_authenticate( $content ) {
global $post;
$need_login_ids = get_option( 'xyz_need_login' );
if( is_array( $need_login_ids ) && in_array( $post->ID, $need_login_ids ) ) {
if( is_user_logged_in() ) {
// alter the content as needs
$content = 'Stuff for logged-in users' . $content;
}
}
return $content;
}
References
get_page_by_path()
is_user_logged_in()
update_option()
get_option()

Resources