If you're new to Magento, this answer likely will not make sense. So either get an experienced Magento developer on this or start brushing up. With that, here's what you can try.
Prerequisites
Ensure that you have defined terms in Magento under Sales > Terms and conditions
Ensure that you have terms enabled in System Configuration > Sales > Checkout > Checkout Options > Enable Terms and Conditions
And please note, these instructions may vary greatly depending on your version of Magento/checkout extension in use, and where you actually want to display the agreements. This will show you how to work it out on a stock CE installation.
How Agreements are Rendered
See app/design/frontend/base/default/layout/checkout.xml
:
...
<checkout_onepage_review translate="label">
...
<block type="checkout/agreements" name="checkout.onepage.agreements" as="agreements" template="checkout/onepage/agreements.phtml"/>
...
</checkout_onepage_review>
...
The middle line tells Magento that the layout on the review step will contain a checkout/agreements
block named checkout.onepage.agreements
. It also sets up the template there.
So when the checkout reaches the review step, this file comes into play.
app/design/frontend/base/default/template/checkout/onepage/review/info.phtml
:
...
<div id="checkout-review-submit">
<?php echo $this->getChildHtml('agreements') ?>
<div class="buttons-set" id="review-buttons-container">
...
And that 2nd line is asking to render the block we defined in the layout XML above.
How to Require Agreements at Checkout Step 1
If you've followed me so far, then you can infer to start by moving/copying the layout XML block node (checkout.onepage.agreements
) into another area (called a 'layout handle') of the same file. Find the layout handle checkout_onepage_index
, and get to its child block named checkout.onepage.billing
or whatever block you want to display the agreements. Extend it by adding that agreements XML, so that it looks like this:
...
<checkout_onepage_index translate="label">
...
<block type="checkout/onepage_billing" name="checkout.onepage.billing" as="billing" template="checkout/onepage/billing.phtml">
<block type="checkout/agreements" name="checkout.onepage.agreements" as="agreements" template="checkout/onepage/agreements.phtml"/>
</block>
...
</checkout_onepage_index>
...
Now we're ready to call and render that block from within the billing step's template. Open that up, get to the place where you want the agreements to appear, and add this line:
<?php echo $this->getChildHtml('agreements') ?>
If you clear your cache and get to the checkout, you should see the agreements appear. That handles rendering, now we have to tie that into validation.
How to Validate Agreements
Because this is normally done at the end of the checkout, we can figure out how it works by examing the checkout's main controller:
app/code/core/Mage/Checkout/controllers/OnepageController.php::saveOrderAction
:
public function saveOrderAction()
{
...
if ($requiredAgreements = Mage::helper('checkout')->getRequiredAgreementIds()) {
$postedAgreements = array_keys($this->getRequest()->getPost('agreement', array()));
if ($diff = array_diff($requiredAgreements, $postedAgreements)) {
$result['success'] = false;
$result['error'] = true;
$result['error_messages'] = $this->__('Please agree to all the terms and conditions before placing the order.');
$this->getResponse()->setBody(Mage::helper('core')->jsonEncode($result));
return;
}
}
...
You will essentially copy this condition into the top of the saveBillingAction
method, like so:
...
public function saveBillingAction()
{
...
if ($this->getRequest()->isPost()) {
if ($requiredAgreements = Mage::helper('checkout')->getRequiredAgreementIds()) {
$postedAgreements = array_keys($this->getRequest()->getPost('agreement', array()));
if ($diff = array_diff($requiredAgreements, $postedAgreements)) {
$result['success'] = false;
$result['error'] = true;
$result['message'] = $this->__('Please agree to all the terms and conditions before placing the order.');
$this->getResponse()->setBody(Mage::helper('core')->jsonEncode($result));
return;
}
}
...
Notice a key difference here. The $result['error_messages']
was changed to $result['message']
. This is done because, unfortunately for the stock checkout, its JavaScript is inconsistent in implementation. So while the order review step will check for error_messages
, the billing step looks for messages
on the result.
Now that you've displayed your agreements, and wired them up to the controller, you should be able to test this step out. If you don't check the agreements, and continue to the next step, you would get an alert box that says, "Please agree to all the terms and conditions before placing the order."
A long-winded answer, but also very necessary if you have no idea where to begin. Hopefully this helps.
The issue is with how
skin/frontend/base/default/js/checkout/review.js
interacts with
design/frontend/base/default/template/paypal/express/review.phtml
review.js has not been updated since 1.7 (or maybe before)
review.phtml has been updated with 1.9
When a virtual order happens, there is no shipping section on the review page, and the logic of the "OrderReviewController" tells it to observe all the inputs of the form 'order_review_form', and if they change, to disable the "Place Order" button.
This seems to be a legacy behaviour, because the only remaining input in the 'order_review_form' is the checkbox to agree with Terms and Conditions - and you actually want precisely the opposite behaviour with that checkbox.
The solution:
Create a copy of review.js in your theme's "skin" area, eg:
skin/frontend/default/modern/js/checkout/review.js
Edit this review.js, and replace line 358
Event.observe(input, 'change', this._onElementChange.bindAsEventListener(this));
with
if (typeof input.id !== 'string' || input.id.substr(0,9) !== 'agreement') {
Event.observe(input, 'change', this._onElementChange.bindAsEventListener(this));
}
A proper solution would require review.js being rewritten to be compatible with review.phtml...
Best Answer
Just edit
template/checkout/onepage/agreements.phtml
and addchecked="checked"
on the checkbox input.