Onepage checkout - magento

i'm trying to introduce an additional step in the one step checkout process (at the start, just after login). This is on Magento v1.8 and the items being sold are virtual product types (therefore the only sections that should appear at checkout are: [new section], billing, payment, and order review.
I've had a look at a number of articles - this one being most suited to my needs (albeit written for v1.4 i think, and uses a the overloading of existing pages instead of writing a new module). I've also followed along with this article however it aims to introduce a module - something which I don't think is absolutely required for this. SO article Magento Adding Step to Onepage Checkout was also referenced.
My problem:
I have the additional step appearing on the OPC page, however the accordion which should be expanding the active section isn't. This is due to the CSS class active not being set, which is in turn not set since the new module is not marked as active.
My question:
What have I missed from the steps below to ensure that the new module is set as the ActiveStep?
What I've attempted to so far:
In short, I've introduced <?php echo $this->getActiveStep(); ?>statement on onepage.phtml and it's indicating that 'billing' is still the active page (the default first page).
I've made the following changes so far specifically around the ordering of pages:
added the new section (registerkids) to _getStepCodes() in abstract.php
return array('login', 'registerkids', 'billing', 'shipping', 'shipping_method', 'payment', 'review');
created a app/code/local file in Checkout/Block/Onepage/registerkids.php with
class Mage_Checkout_Block_Onepage_Registerkids extends Mage_Checkout_Block_Onepage_Abstract
{
protected function _construct()
{
$this->getCheckout()->setStepData('registerkids', array(
'label' => Mage::helper('checkout')->__('Assign your kids to the booking'),
'is_show' => $this->isShow()
));
if ($this->isCustomerLoggedIn()) {
$this->getCheckout()->setStepData('registerkids', 'allow', true);
}
parent::_construct();
}
}
removed the if ($this->isCustomerLoggedIn()) statement from Checkout\Block\Onepage\billing.php that sets the next step
updated Checkout\Model\Type\Onepage.php initCheckout() with
if (!($step==='login' || $customerSession->isLoggedIn() && $step==='registerkids')) {
$checkout->setStepData($step, 'allow', false); // where 'registerkids' used to say 'billing'
made the following changes to opcheckout.js -
this.steps = ['login', 'registerkids', 'billing', 'shipping', 'shipping_method', 'payment', 'review']; (added new section)
this.currentStep = 'registerkids';
updated setMethod: function() so that next section after login is this.gotoSection('registerkids', true);
updated template/persistent/checkout/onepage/login.phtml JS customMethod() to checkout.gotoSection('registerkids');
updated Checkout/Onepage.php getActiveStep() to return $this->isCustomerLoggedIn() ? 'registerkids' : 'login';

after quite a bit of investigation, the function that controls the initial Active step is:
public function getActiveStep()
{
return $this->isCustomerLoggedIn() ? 'yoursection' : 'login';
}
this can be found in Mage\Checkout\Block\Onepage.php, and the function that calls it from onepage.phtml is $this->getActiveStep()
The reason it wasn't working for me was that the file was in the wrong place. Working fine now.
Hope this helps someone

Related

Invalidate Shopware 6 page cache on entity update via API

We created a custom CMS element which displays entries which are managed via API.
Now when entries are updated and Shopware 6 runs ins production mode, the changes are not reflected on the page. I believe this is due to the page cache. (APP_ENV=prod)
What do we have to do to invalidate the cache automatically?
I checked the docs, but did not find the necessary information.
For the product box it works: When I place a product CMS element on the main page and change the product, the page is updated when I reload in the browser.
I was expecting to find some hint in \Shopware\Core\Content\Product\Cms\ProductBoxCmsElementResolver but there are no cache tags or something like this added there.
EDIT: Actually I was a bit inaccurate. The page I have lists the entities, and it is a category page.
So I believe I have too hook into CategoryRouteCacheTagsEvent.
For testing I hard-coded into:
\Shopware\Core\Content\Category\SalesChannel\CachedCategoryRoute::extractProductIds
$slots = $page->getElementsOfType('jobs');
/** #var CmsSlotEntity $slot */
foreach ($slots as $slot) {
$box = $slot->getData();
$ids = array_merge($ids, $box['jobs']->getIds());
}
But this does not yet work.
PS: Also I noticed some code duplication in the core in \Shopware\Core\Content\Category\SalesChannel\CachedCategoryRoute::extractProductIds and \Shopware\Core\Content\LandingPage\SalesChannel\CachedLandingPageRoute::extractIds
The Shopware\Core\Framework\Adapter\Cache\CacheInvalidationSubscriber listens to a lot of events, including indexer and entity-written events. This in turn uses the CacheInvalidator to invalidate cached data based on tags/cache keys.
You should be able to add invalidation based on your own entity in a similar fashion.
For this to work with a custom entity, you will probably have to tag any cache entries with something you can generate on invalidation. For CMS pages, I would probably start with the CachedLandingPageRoute as a reference.
I suggest you should have a look at the CacheInvalidationSubscriber and its service definition. You can see that there are already a bunch of events that are dispatched when write operations to certain entities occur. When you then look at the respective handler you can see how it invalidates the cache for whatever kind of routes it should affect.
When you speak of entries I assume you implemented your own custom entities for use in your CMS element? If that is the case just replicate the listener for your own entities. Otherwise you'll have to look for another event that is dispatched once you save your changes and then invalidate the cache likewise.
Based on the answers of dneustadt and Uwe, as for the job listings I solved it like with this two subscribes. I do not need any single ID here, because the full listing page has to be invalidated in case a job is deleted or added. This is why I went with the any-jobs tag:
use Shopware\Core\Content\Category\Event\CategoryRouteCacheTagsEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class CacheKeyEventSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents(): array
{
return [
CategoryRouteCacheTagsEvent::class => 'generateTags'
];
}
public function generateTags(CategoryRouteCacheTagsEvent $event): void
{
$page = $event->getResponse()->getCategory()->getCmsPage();
$slots = $page->getElementsOfType('jobs');
if (!empty($slots)) {
$event->setTags(
array_merge($event->getTags(), ['any-jobs'])
);
}
}
}
and
class CacheInvalidationSubscriber implements EventSubscriberInterface
{
private CacheInvalidator $cacheInvalidator;
public static function getSubscribedEvents(): array
{
return [
EntityWrittenContainerEvent::class => 'invalidateJobs'
];
}
public function __construct(CacheInvalidator $cacheInvalidator)
{
$this->cacheInvalidator = $cacheInvalidator;
}
public function invalidateJobs(EntityWrittenContainerEvent $event): void
{
if (!empty($event->getPrimaryKeys(\ApplicationManagement\Core\Content\JobAd\JobAdDefinition::ENTITY_NAME))) {
$this->cacheInvalidator->invalidate(
['any-jobs']
);
}
}
}

How to render a cms page with default theme AND variables from controllers in OctoberCMS?

I'm wondering how I can render a view, or display a page with my default theme in OctoberCMS, via a route that executes a function in a controller.
If I have the following route:
Route::get('bransje', [
'uses' => 'Ekstremedia\Cityportal\CPController#bransje'
]);
And in my controller CPController ive tried several things, like I used to with Laravel:
public function bransje() {
$stuff = Stuff::with('info');
return View::make('cms::bransje')->with('stuff',$stuff);
}
But I cannot seem to get it to work, and I've tried to search the web, but it's hard to find answers. I have found a workaround, and that is to make a plugin component, then I can include that component and do:
public function onRun()
{
$this->eventen = $this->page['stuff'] = $this->stuff();
}
protected function stuff()
{
return ...
}
Is there any way so I can make pages without using the Cms, and that are wrapped in my default theme? I've tried
return View::make('my-theme-name::page');
and a lot of variants but no luck.
I know I can also do a:
==
public function onRun()
{
}
in the start of my page in the cms, but I'm not sure how to call a function from my plugin controller via there.
You can bypass frontend routing by using routes.php file in your plugin.
Full example in this video turotial.
If this answer can still be useful (Worked for October v434).
I have almost the same scenerio.
What I want to achieve is a type of routing like facebook page and profile.
facebook.com/myprofile is the same url structure as facebook.com/mypage
First I create a page in the CMS for each scenario (say catchpage.htm)
Then a created a catchall route at the buttom of routes.php in my plugin that will also not disturb the internal working of octobercms.
if (!Request::is('combine/*') && !Request::is('backend/*') && !Request::is('backend')) {
// Last fail over for looking up slug from the database
Route::get('{slug}/{slug2?}', function ($slug, $slug2 = null) {
//Pretend this are our routes and we can check them against the database
$routes = ["bola", "sade", "bisi", "ade", "tayo"];
if(in_array($slug, $routes)) {
$cmsController = new Cms\Classes\Controller;
return $cmsController->render("/catchpage", ['slug' => $slug]);
}
// Some fallback to 404
return Response::make(View::make('cms::404'), 404);
});
}
The if Request::is check is a list of all the resource that october uses under the hood, please dont remove the combine as it is the combiner route. Remove it and the style and script will not render. Also the backend is the url to the backend, make sure to supply the backend and the backend/*.
Finally don't forget to return Response::make(View::make('cms::404'), 404); if the resource is useless.
You may put all these in a controller though.
If anyone has a better workaround, please let us know.

Magento OnePage modification, need to skip a step

I am completely new to Magento and we are using version 1.4 currently. The steps on the OnePage checkout are:
Checkout Method (Guest or sign-in)
Billing Information
Shipping Information
Delivery Information
Payment Information
Order Review
I want to skip Delivery Information. To do this I have done two things:
1. Changed (actually extended) the core Checkout class to not include #4 Delivery Information ('shipping_information'),
2. in the Controller, call the Checkout class method saveShippingMethodAction( ) inside of saveShippingAction( ) (since there is never a submission of shipping method by user), with a data value passed manually.
Everything works as expected, and the step is skipped, however inside Checkout::saveShippingMethodAction( ) there are these two lines:
Mage::dispatchEvent('checkout_controller_onepage_save_shipping_method', array('request'=>$this->getRequest(), 'quote'=>$this->getOnepage()->getQuote()));
$this->getResponse()->setBody(Mage::helper('core')->jsonEncode($result));
The problem is in the usage of 'request'=>$this->getRequest(). The actual request is not shipping_method but rather shipping, so the output (i.e. the HTML form string that should be passed to step #5, Payment information) is not loaded, and so step #5 is blank.
My first instict is how can I simulate a request, but there is probably a "Magento Way" to do this. Can anyone tell me what that might be, or how I can prep getRequest( ) and maybe getResponse( ) as if I'd submitted that specific form? Thanks!
I understood what you want to do but i didn't understood what you did.
Ok, i will explain you something here.If you are talking about magento default onepage checkout than the thing you are talking about Delivery Information it is actually the shipping method.
You also were asking about something
Mage::dispatchEvent('checkout_controller_onepage_save_shipping_method', array('request'=>$this->getRequest(), 'quote'=>$this->getOnepage()->getQuote()));
$this->getResponse()->setBody(Mage::helper('core')->jsonEncode($result));
It actually don't have anything to do with your code because it is the place to insert your event, Its like a hook.
Now the real problem and its solution.I haven't tried it yet but this should work.
If you see the
app/code/core/Mage/checkout/controllers/OnepageController.php
file.You need to make changes in this file. First override this controller to your own module, this is the preferred way but you can test in core files too.
Now in this file you will see two function
public function saveShippingAction()
{
//This function saves the shipping information of customer
}
and
public function saveShippingMethodAction()
{
//this function saves the shipping method
}
In the first function you will see some code like this
if (!isset($result['error'])) {
$result['goto_section'] = 'shipping_method';
$result['update_section'] = array(
'name' => 'shipping-method',
'html' => $this->_getShippingMethodsHtml()
);
}
this redirects to shipping method.If you want to by pass the shipping method steps(in your case delivery information) then replace the above code by
if (!isset($result['error'])) {
$result['goto_section'] = 'payment';
$result['update_section'] = array(
'name' => 'payment-method',
'html' => $this->_getPaymentMethodsHtml()
);
}
This will complete your redirection part from controller side now remove the block that displays the shipping method block from the layout file. and that's it.
Hope this helps.

CakePHP validation not working for contact form

I am trying to do some very simple validation in my CakePHP contact form, but validation does not work eventhough I think I did everything necessary. Here's what I did:
I made a model like this:
class Office extends AppModel
{
var $name = 'Office';
var $useTable = false;
public $validate = array('onderwerp' => 'notEmpty');
}
(I also tried many other values for $validate from the CakePHP online manual)
In Config/bootstrap.php I made this rule for not letting CakePHP expect plural "Offices":
Inflector::rules('plural', array('rules' => array(),
'irregular' => array(),
'uninflected' => array('office')));
In OfficeController, I do this in my method contact():
$this->Office->set($this->request->data);
if($this->Office->validates()){
echo "code validates";
} else {
print_r($this->Office->validationErrors);
}
And in my Office/contact.ctp view, I have (amongst other code like starting and ending the form) this code:
$this->Form->input('onderwerp', array('label'=>false, 'size' => 60));
Now, even when I fill in the form, leaving empty the field 'onderwerp', it executes the code that should be executed when the code is executed.
When I print_r($this->request->data) or print_r($this->Office) I see that my onderwerp field is there and that it is empty (or filled when I do fill in something).
Now, when I add a public function validates() in my model and echo something there, it IS being displayed. So I'd say CakePHP knows where to find my model, and does execute my controller code. I also tried adding return parent::validates(); in my validates() function, but this also yielded no validation error, or any other error for that matter. My debug level is set to 2.
I guess I'm missing a needle in this haystack. Thanks for helping me finding it!
so drop all the inflector stuff.
and use the right model in your Form->create()
either
$this->Form->create(null)
or
$this->Form->create('Office');
and if you follow my advice to use a table less model with schema you will also have more power over input creation and validation.

Magento - how to add new product status

I'm trying to make new product statuses but i can't figure out how to do it and all the stuff set on the web is not consistent or simply talks about order status which i don't want to change.
What is your motivation to have new product statuses? I think it's little bit risky to change this part of app. I suggest you to add new attribute and use this one instead system product's attribute 'status', this attribute tells to system if product is enabled or disabled. I guess there is nothing between :)
Override class Mage_Catalog_Model_Product_Status to the local folder. Then open the file
\app\code\local\Mage\Catalog\Model\Product\Status.php
At the top of the file you can see the constants
const STATUS_ENABLED = 1;
const STATUS_DISABLED = 2;
Add your custom status below them, for example
const STATUS_SUSPENDED = 3;
Then edit the function getOptionArray
static public function getOptionArray()
{
return array(
self::STATUS_ENABLED => Mage::helper('catalog')->__('Enabled'),
self::STATUS_DISABLED => Mage::helper('catalog')->__('Disabled'),
self::STATUS_SUSPENDED => Mage::helper('catalog')->__('Suspended')
);
}
That's it. Don't forget to clear the cache.

Resources