Jump to content

[Solved] PW3 - Set Field Value Using Checkbox Query


ridgedale
 Share

Recommended Posts

Reference: PW 3.0.62 and uikit3 based site using the Regular-Master profile.

I'm trying to automatically set and save a value to a field when a checkbox is checked on the same page under the backend.

I've tried adding the following php code to the page without success:

// Test 1
$maintenance = $pages->get("/site-upgrade/")->maintenance;
$maintainer = $pages->get("/site-upgrade/")->maintainer;
if ( ! $page->maintenance == 1) {
	$page->set('maintainer', null);
    $maintmessage = "Status: This site is not currently undergoing maintenance.";
} else {
	$page->set('maintainer', $user->name);
    $maintainer = $page->get('maintainer');
    $maintmessage = "Status: This site is currently undergoing maintenance by " . $maintainer . ".";
}

// Test 2
$maintenance = $pages->get("/site-upgrade/")->maintenance;
$maintainer = $pages->get("/site-upgrade/")->maintainer;
if ( ! $page->maintenance == 1) {
    $page->of(false);
	$page->maintainer = '';
	$page->save();
    $maintmessage = "Status: This site is not currently undergoing maintenance.";
} else {
    $page->of(false);
	$page->maintainer = $user->name;
	$page->save();
    $maintainer = $page->get('maintainer');
    $maintmessage = "Status: This site is currently undergoing maintenance by " . $maintainer . ".";
}

// Test 3
$maintenance = $pages->get("/site-upgrade/")->maintenance;
$maintainer = $pages->get("/site-upgrade/")->maintainer;
if ( ! $page->maintenance == 1) {
	$page->setAndSave('maintainer', null);
    $maintmessage = "Status: This site is not currently undergoing maintenance.";
} else {
	$page->setAndSave('maintainer', $user->name);
    $maintainer = $page->get('maintainer');
    $maintmessage = "Status: This site is currently undergoing maintenance by " . $maintainer . ".";
}

In all cases the maintainer remains blank when the maintenance checkbox is checked.

Any guidance as to where I'm going wrong would be greatly appreciated.

 

Link to comment
Share on other sites

Hi Tom.,

Thanks again for the reply.

I wasn't trying to hook anything. I was simply adding the code to the page template file.

I've subsequently tried adding the following to the page template file also without any success:

<?php namespace ProcessWire;
// site-maint.php template file for managing site upgrades and displaying maintenance status message.	
$page->addHookAfter("save", null, "hookSiteMaintSave");

public function hookSiteMaintSave($event) {

	$page = $event->arguments[0];

    $maintenance = $pages->get("/site-upgrade/")->maintenance;
    $maintainer = $pages->get("/site-upgrade/")->maintainer;

    if ( ! $page->maintenance == 1) {
	    $page->setAndSave('maintainer', null);
        $maintmessage = "Status: This site is not currently undergoing maintenance.";
    } else {
    	$page->setAndSave('maintainer', $user->name);
        $maintainer = $page->get('maintainer');
        $maintmessage = "Status: This site is currently undergoing maintenance by " . $maintainer . ".";
    }
}
?>

This code applies to this page only - not to any other pages or templates. Is the code in the wrong location?

Link to comment
Share on other sites

Humm, I'm slightly confused by what you are trying to achieve. For example if you are clicking a checkbox on the backend and it updates then you can't really do that though a template. Templates are only run on the frontend. However, there is a very easy way of injecting code in to the backend without having to create a module. This is under /site/ready.php, you'll have to create that file. 

If I'm guessing correctly you are going to need something like this in ready.php:

wire()->addHookBefore("Pages::save", function($event) {
	$page = $event->arguments(0);
	if($page->template == 'site_upgrade') { // Replace 'site_upgrade' with your template name for the maintenance page
		if($page->maintenance) {
			$page->maintainer = $user->name; // If this field is a Page Relationship field it just needs to be $user
		} else {
			$page->maintainer = '';
		}
	}
});

Then you can add this at the very top of your pages:

<?php
	$upgradePage = $pages->get('/site-upgrade/');
	if($upgradePage->maintenance) {
		echo "<h1>Site is currently under maintenance by $upgradePage->maintainer</h1>";
		exit;
	}
?>

 

Link to comment
Share on other sites

Thanks again for your reply, @Tom.

3 hours ago, Tom. said:

Templates are only run on the frontend.

OK, understood.

The maintainer field is currently Type: Text. The only field types currently available are as attached.

I'll read up on the Page Relationship field type, try the implementation suggested and let you know how I get on.

PW3-FieldTypes.png

Link to comment
Share on other sites

Hi @Tom. ,

I've reviewed the Page Relationship field type. I don't think that field type is a applicable in this case. I'm simply using the Text field type for the maintainer field.

Below is exactly the code tested in each of the files following your latest input:

site-maintenance.php:

<?php namespace ProcessWire;
// site-maintenance.php template file for managing site upgrades and displaying maintenance status message.	

// Update the 'maintainer' field each time the maintenance checkbox is checked/unchecked.
    if ( ! $page->maintenance == 1) {
	    // $page->setAndSave('maintainer', null);
        $mntmessage = "Status: This site is not currently undergoing maintenance.";
    } else {
    	// $page->setAndSave('maintainer', $user->name);
        $mntnr = $page->get('maintainer');
        $mntmessage = "Status: This site is currently undergoing maintenance by " . $mntnr . ".";
    }
?>

<div pw-append='content-body'>
<?php echo $mntmessage; ?>
</div>

<?php include('./_news-sidebar.php'); ?>

ready.php:

<?php namespace ProcessWire; 

wire()->addHookAfter("Pages::save", function($event) {
	$page = $event->arguments(0);
	if($page->template == 'site-maintenance') { // Replace 'site_upgrade' with your template name for the maintenance page
		if($page->maintenance) {
		    // $page->setAndSave('maintainer', $user->name);
			$page->maintainer = $user->name; // If this field is a Page Relationship field it just needs to be $user
		} else {
		    // $page->setAndSave('maintainer', '');
			$page->maintainer = '';
		}
	}
});

Note: I've tried both the setAndSave alternatives in the if statement as well.

admin.php:

<?php namespace ProcessWire;

/**
 * Admin template just loads the admin application controller, 
 * and admin is just an application built on top of ProcessWire. 
 *
 * This demonstrates how you can use ProcessWire as a front-end 
 * to another application. 
 *
 * Feel free to hook admin-specific functionality from this file, 
 * but remember to leave the require() statement below at the end.
 * 
 */

$upgradePage = $pages->get('/site-upgrade/');
if($upgradePage->maintenance && $user->isLoggedin() && $user->name !== $upgradePage->maintainer) {
	$session->logout();
    $session->redirect("/maintenance.html", false);
	exit;
}


require($config->paths->adminTemplates . 'controller.php'); 

Note: If the $upgradePage ... } is added everyone gets redirected to the maintenance.html page unless the maintainer field is manually updated.

header.php:

<?php namespace ProcessWire; 
$upgradePage = $pages->get('/site-upgrade/');
if($upgradePage->maintenance && $user->name !== $upgradePage->maintainer) {
	$session->logout();
    $session->redirect("/maintenance.html", false);
	exit;
}
?>

<!DOCTYPE html>
...

Note:  && $user->name !== $upgradePage->maintainer needs to be included otherwise everyone including the site upgrade admin gets redirected. I need to ensure that the admin who checks the maintenance checkbox can login and review the sites to make sure everything is OK with the Processwire upgrade before making them live again.

The maintainer field is still not being updated whether I use AddHookBefore or AddHookAfter methods or the setAndSave alternative instructions.

When the checkbox is ticked by a logged in admin only the users with hasRole = guest get redirected. Anyone with a login is not redirected and could potentially interfere or cause problems for the site upgrade process. The only way the code works as intended is if I enter the admin username into the maintainer field manually.

I just don't get why the maintainer field is not being updated. ?Any further thoughts?

Link to comment
Share on other sites

Having found Ryan's post in this thread, I've also tried replacing the ready.php with the following code both without any success. The maintainer field does not get updated in the backend or the MySQL database:

Further Testing 1:

<?php namespace ProcessWire; 

wire()->addHookBefore("Pages::save", function($event) {
	$page = $event->arguments(0);
	if($page->template == 'site-maintenance') { // Replace 'site_upgrade' with your template name for the maintenance page
		if($page->maintenance) {
		    // $page->setAndSave('maintainer', $user->name);
		    $page->of(false);
			$page->maintainer = $user->name; // If this field is a Page Relationship field it just needs to be $user
			$page->save();
		} else {
		    // $page->setAndSave('maintainer', '');
		    $page->of(false);
			$page->maintainer = '';
			$page->save();
		}
	}
});

Further Test 2:

<?php namespace ProcessWire; 

wire()->addHookBefore("Pages::save", function($event) {
	$page = $event->arguments(0);
	if($page->template == 'site-maintenance') { // Replace 'site_upgrade' with your template name for the maintenance page
		if($page->maintenance) {
		    // $page->setAndSave('maintainer', $user->name);
		    $page->of(false);
			$page->maintainer = $user->name; // If this field is a Page Relationship field it just needs to be $user
			$page->save('maintainer');
		} else {
		    // $page->setAndSave('maintainer', '');
		    $page->of(false);
			$page->maintainer = '';
			$page->save('maintainer');
		}
	}
});

I've also double-checked the logs and no errors are generated when the maintenance checkbox is ticked/unticked and the page saved.

Changing addHookBefore to addHookAfter makes no difference.

The only thing I can think of is to create a required dropdown menu field that just includes the current username, but I don't know how that can be achieved.

Even so it is somewhat worrying that it appears field values cannot be set in the backend via the API.

Any further input/thoughts would be very welcome.

 

Link to comment
Share on other sites

I don't think this $user is available in the scope.

$page->maintainer = $user->name;
$page->maintainer = wire("user")->name;

I don't think if you use hook BEFEORE, the page save is going to have the page field already updated. So if a value is changed you won't see it yet in the page object changed at that point. Also a hook on Page::save and you save the page in your hook gonna create a infinite loop.

You should try either hook after save or use Pages::saveReady where it's right before saving the data. You can update the field and don't even need to save the page as it's already doing that after your hook.

Link to comment
Share on other sites

Hi @Soma ,

Thank you for your reply.

5 hours ago, Soma said:

I don't think this $user is available in the scope.


$page->maintainer = $user->name;

$page->maintainer = wire("user")->name;

I'm not sure I understand what you mean by this. Do you mean I should be using the second statement instead of the first? Otherwise what replacement should I be using?

5 hours ago, Soma said:

You should try either hook after save or use Pages::saveReady where it's right before saving the data. You can update the field and don't even need to save the page as it's already doing that after your hook.

 

On 7/2/2018 at 9:41 AM, ridgedale said:

Changing addHookBefore to addHookAfter makes no difference. 

That makes sense and is why I also tried addHookAfter as well.

5 hours ago, Soma said:

Also a hook on Page::save and you save the page in your hook gonna create a infinite loop.

Shouldn't an error have been displayed in the log to that effect?

Neither of the following code changes for the ready.php file make any difference. The maintainer field still does not get updated without any errors being generated in the logs:

<?php namespace ProcessWire; 

wire()->addHookAfter("Pages::save", function($event) {
	$page = $event->arguments(0);
	if($page->template == 'site-maintenance') {
		if($page->maintenance) {
		    $page->of(false);
			$page->maintainer = wire("user")->name;
			$page->save('maintainer');
		} else {
		    $page->of(false);
			$page->maintainer = '';
			$page->save('maintainer');
		}
	}
});
<?php namespace ProcessWire; 

wire()->addHookBefore("Pages::saveReady", function($event) {
	$page = $event->arguments(0);
	if($page->template == 'site-maintenance') {
		if($page->maintenance) {
		    $page->of(false);
			$page->maintainer = wire("user")->name;
			$page->save('maintainer');
		} else {
		    $page->of(false);
			$page->maintainer = '';
			$page->save('maintainer');
		}
	}
});
5 hours ago, Soma said:

You can update the field and don't even need to save the page as it's already doing that after your hook.

That may be the case but the user cannot leave the page without saving it first.

The user needs to check the maintenance field and save that field status (which actually does take place on saving the page) and the maintainer field automatically needs to be updated with the current username (which does not take place).

Any further guidance would be greatly appreciated.

 

Link to comment
Share on other sites

This in site/ready.php works just fine for me (using basic-page and the summary field instead)

<?php namespace ProcessWire;

wire()->addHookBefore("Pages::saveReady", function($event) {
	$page = $event->arguments(0);
	if($page->template == 'basic-page') {
		if($page->maintenance) {
		    $page->of(false);
			$page->summary = wire("user")->name;
		} else {
		    $page->of(false);
			$page->summary = '';
		}
	}
});

Does you hook even trigger. Easy test would be to add exit("hooked"); in your hook.

  • Like 2
Link to comment
Share on other sites

@Soma,

46 minutes ago, Soma said:

This in site/ready.php works

Despite @Tom. mentioning this earlier for idiotic reason I have been placing the hook code in a ready.php file located in the site-xxx/templates directory instead of the site-xxx directory alongside the config.php file. Placing the code in the correct location resolves the issue and now everything is working as required.

Sincere apologies for the oversight and thanks again to both of you for your assistance and patience.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...