Inchoo http://inchoo.net Magento Design and Magento Development Professionals - Inchoo Tue, 20 Jun 2017 08:50:05 +0000 en-US hourly 1 https://wordpress.org/?v=4.7.3 Why so Sylius? http://inchoo.net/ecommerce/sylius-ecommerce-platform-roadmap-features/ http://inchoo.net/ecommerce/sylius-ecommerce-platform-roadmap-features/#respond Tue, 20 Jun 2017 08:46:58 +0000 http://inchoo.net/?p=29765 Inchoo went to a Sylius meetup, and all you got… is an overview of this Symfony-based open source eCommerce platform in the making. We all love PHP, and with the growing Symfony community in Croatia, we wanted to see what all the fuss is about. Here is our take on Sylius as an eCommerce platform...

The post Why so Sylius? appeared first on Inchoo.

]]>
Inchoo went to a Sylius meetup, and all you got… is an overview of this Symfony-based open source eCommerce platform in the making. We all love PHP, and with the growing Symfony community in Croatia, we wanted to see what all the fuss is about. Here is our take on Sylius as an eCommerce platform and, more importantly, its ecosystem.

Zagreb, and its hip startup incubator Hub385, were hosts to another Symfony meetup organized by several companies that are quite involved with this framework. Netgen, Locastic, Trikoder and web.burza are all common names in Croatian IT circles, and they are already quite involved in working on projects based on Symfony (using various platforms).

Last week was the time to get some insights into where Sylius is, and, more importantly, where it plans to be in the near future. Its founder Paweł Jędrzejewski and other members of his team took stage to present Sylius, and they were joined by other Croatian companies sharing their experiences with both frustrations and positives of working with a such young platform (did anyone mention Magento back in 2008?). We learned a lot, but we also got a glimpse of the community, and the entire ecosystem growing around this new player in the eCommerce software market.

What is Sylius and why is it interesting?

Well, for one – it’s a rather new and lean (at least it hopes to be) eCommerce platform, based on Symfony PHP framework, with doctrine as ORM, database abstraction and uses TWIG for templating.

It boasts with ease of customization and extending its core, but doesn’t have that many features out of the box. And right there are all the pros and cons of considering it as the eCommerce platform of choice 🙂

Potential project/merchant profiles

Even the companies working with it and having some nice project behind them position it as interesting to consider for:

  • smaller-scale, quick-to-market projects
  • highly custom projects

The nature of it is that there are not that many merchants or projects that would fall into either of these groups, especially in well-established eCommerce markets.

So, where we see the benefits of potentially using this platform are the markets similar to Croatian – smaller, growing markets with a lot of merchants still doing their baby steps when it comes to selling online. It appears as if the projects on Sylius should not be overly complex to set up, but at this time there is still an apparent lack of “extensions” if we are to use Magento’s terminology, on its marketplace (or out in the wild) to boost its feature set.

The team behind it all

The team behind Sylius is very young and enthusiastic one, open to suggestions from companies who got their hands on their products and used it to launch a number of websites, even before its first stable release. Pawel shares an interesting story of how Sylius came to be, from a custom built solution to power a family-owned cosmetics business to its rewrite on Symfony and current beta stage.

They are actively seeking additional investments to speed up the process of getting it to its first stable release. And it is also nice to see the community in Croatia being very active throughout past several years (I guess it helps that the founding team is from Poland).

The roadmap and the shape of things to come

Roadmap is, as is often the case with such software solutions, rather elusive 🙂 and features to go in and out from one release to another. However, they are putting a lot of effort in community and ecosystem development, and the response has been good so far – documentation is elaborate, translations are under way, contributions are welcome and, from what we were able to see, developers like working with it.

So, what’s missing? A stable release and more live projects, of course, which sort of go hand in hand.

How we see it, Sylius still needs to work a lot on its feature set, and presentation of it towards a broader public. Developers are the ones working on eCommerce projects, but they don’t usually make decisions on which platform a project is going to be developed.

Decision makers respond to something else, and that is in most cases the value proposition. Sylius still has its work cut out for them in that area. Showcasing eCommerce projects using Sylius will be something to work on, and we will be paying special attention to how things are rolling out. We will also be looking at giving it a test drive soon enough, to be able to give a decent overview from behind the scenes as well.

You can jump over to their demo pages (shop and admin) and check it out for yourself.

Stay tuned for more news from the world of Symfony and Sylius, and in the meantime, let us know if you had any experiences with this software.

The post Why so Sylius? appeared first on Inchoo.

]]>
http://inchoo.net/ecommerce/sylius-ecommerce-platform-roadmap-features/feed/ 0
Ground zero – planning phase http://inchoo.net/ecommerce/ground-zero-planning-phase/ http://inchoo.net/ecommerce/ground-zero-planning-phase/#respond Wed, 14 Jun 2017 14:16:32 +0000 http://inchoo.net/?p=29696 If you have plans to start a new website on Magento and don’t know where to start, or if you already have an existing website and you’re thinking of revamping it, then you might find this article interesting. Creating Magento websites might seem as a simple process that includes installing and configuring Magento, choosing some...

The post Ground zero – planning phase appeared first on Inchoo.

]]>
If you have plans to start a new website on Magento and don’t know where to start, or if you already have an existing website and you’re thinking of revamping it, then you might find this article interesting.

Creating Magento websites might seem as a simple process that includes installing and configuring Magento, choosing some of the predefined themes available, importing products and setting payment and shipping options.

However, there is more that meets the eye. The truth is, there will always be some additional things you’d like to improve on the purchased theme and custom functionalities you’d like to add on top of the default Magento, so something that might seem simple and straightforward at start can become more demanding and require a certain amount of planning.

Also, in many cases you won’t even be interested in a purchased theme and you would like your site to be unique and tailored to your customers needs. You also might want to add additional layer and connect your Magento with 3rd party extensions and some outside systems (such as order management, shipping and accounting system, or ERP).

So what would be the best first step to do in a situations like this?

Projects with high level of complexity and large scale projects require a throughout planning and making crucial decisions right at the project start. Here at Inchoo we approach to these type of projects starting with initial discovery and planning phase which is a standalone process that precedes development.

Why is this phase important?

We believe that quality planning process is imperative for making a stable foundation to build upon, rather than making changes in the middle of development process, which is costly and time consuming.

During the planning phase we put focus on the following:

  • getting to know Client’s business and Client’s current workflows better,
  • researching Client’s competitors and their solutions,
  • identifying the key architectural elements of the site,
  • preparing plan for overall database design (products, attributes, attribute sets),
  • helping Client with deciding which Magento edition to choose (Community or Enterprise),
  • analysing Client’s current solution (if they already have an existing website) including design, traffic data and customer’s behaviour which helps us to make data driven decision for achieving best results.

During this phase, in coordination with the Client, we also plan out the best way to integrate Magento with custom functionalities, 3rd party extensions and an outside systems, making sure that all of them work seamless together.

Result of this process is a detailed technical documentation file which outlines the desired workflows in detail, technologies selected and the process of how to achieve the integration(s) as well as the respective timelines and proposal for performing all the work.

Who is usually involved in this process?

We successfully engage clients in the planning phase as we require valuable input from persons who work closely with the business (sometimes this is a Project manager, eCommerce manager or even a business owner).

On our side, for overall business case and workflows analysis, feature planning and SEO considerations we have a team of eCommerce consultants (Inchoo Consulting Group) and they make sure we deliver the best possible e-commerce solutions to our clients and ensure long-term success for Clients.

We also involve certified senior Magento backend and frontend developers for architectural planning and as well as UI designer for high-level usability discussions. They are all experts with years of experience in the eCommerce industry.

With that being said, deliverable of this process and our consulting work is a direct result of the knowledge, experience and time.

To conclude

Different development companies have different approaches and sometimes planning phase is not perceived as that important. Behind Inchoo success stories lies a well planned process which allows us to deliver high quality solutions for all our Clients.

If you find this article and our approach appealing to your needs and your project, contact us for more details.

The post Ground zero – planning phase appeared first on Inchoo.

]]>
http://inchoo.net/ecommerce/ground-zero-planning-phase/feed/ 0
Inchoo won The Golden Marten Award http://inchoo.net/life-at-inchoo/zlatna-kuna-2016/ http://inchoo.net/life-at-inchoo/zlatna-kuna-2016/#comments Wed, 14 Jun 2017 08:56:11 +0000 http://inchoo.net/?p=29690 After 9 years in business, Inchoo won The Golden Marten Award (Zlatna kuna), traditionally given to the most successful local companies by the Croatian Chamber of Economy. We received it as the best small company in Osijek-Baranja County. Why did we win it for 2016? There were 21 distinct areas that were rated and Inchoo...

The post Inchoo won The Golden Marten Award appeared first on Inchoo.

]]>
After 9 years in business, Inchoo won The Golden Marten Award (Zlatna kuna), traditionally given to the most successful local companies by the Croatian Chamber of Economy. We received it as the best small company in Osijek-Baranja County. Why did we win it for 2016? There were 21 distinct areas that were rated and Inchoo had very high scores in employment increase, average salary, non-material assets, financial stability and self-funding.

Osijek-Baranja County

President of County department of Croatian Chamber of Economy, Zoran Kovačević, has noted that all awarded companies have very high export ratio in total income. Inchoo has 85% of exports. Total income of our County is growing last three years. And only in 2016, it grew by 11%.

Other results are also quite good. International exchange is growing. Last year it went over 5 billion Croatian Kuna (HRK). Investments in long term assest are booming with the rate of 40%, primarly in food and paper industry, agriculture and water supply.

Inchoo

Last year, 2016, was very important for the company. Major event was a move to a new office space because it really introduced a new level of business. Besides the eternal focus on clients and projects, we worked a lot on internal organisation upgrades and new processes. This made our work more efficient and teams stronger. Comparing 2016 and 2015, number of employees grew by 25% and the income grew by 22%.

Pillar of our growth are the people. Not only our team, but the local community. Through the Osijek Software City association, we are organising many meetups, conferences, seminars and talks that have the same goal: to improve local ecosystem and make it more attractive. It is important for us that the young people in the community understand that they have a great perspective here in Osijek, which will motivate them to stay. Our region is battling with the strong emigration and we hope that the rise of software industry will invert negative trends.

The post Inchoo won The Golden Marten Award appeared first on Inchoo.

]]>
http://inchoo.net/life-at-inchoo/zlatna-kuna-2016/feed/ 1
Declare static types to keep bugs away? http://inchoo.net/dev-talk/declare-static-types-keep-bugs-away/ http://inchoo.net/dev-talk/declare-static-types-keep-bugs-away/#respond Wed, 07 Jun 2017 13:50:34 +0000 http://inchoo.net/?p=29655 Introduction A lot of programmers feel that for any larger projects static types offer a huge benefit. Readability too, not only validation. Some argue that tests can replace types, I agree if we are only talking about code validation. But static types are empowering in other situations too. Reading code is easier since types describe...

The post Declare static types to keep bugs away? appeared first on Inchoo.

]]>
Introduction

A lot of programmers feel that for any larger projects static types offer a huge benefit.
Readability too, not only validation.
Some argue that tests can replace types, I agree if we are only talking about code validation.
But static types are empowering in other situations too. Reading code is easier since types describe code and fewer assumptions have to be made about inputs and outputs. Basically, additional documentation which is always in sync with the code.

What about functional style?

In the last iteration of talk about improving correctness and avoiding bugs, we tried to do things in a functional way.
http://inchoo.net/magento/programming-magento/less-bugs/
We tried to use some “higher” level constructs and to bring some benefits of functional programming with PHP, but in all honesty, it simply does not look so nice with currently available syntax.
I am still confident semantic benefits are real, but I am unsure because all that visual noise makes it hard to actually read and understand the code.

Here are 2 RFCs that would probably help a lot:
https://wiki.php.net/rfc/arrow_functions
https://wiki.php.net/rfc/pipe-operator

Since the chance of getting sexy syntax soonish is not so great (I hope PHP will get there) and closures do not automatically detect used variables and you have to list them explicitly let’s try something else.

Static types and immutability

2 obvious improvements which fit into low hanging fruit category: “immutability” and “strict typing”. Since I feel that being familiar with type systems will help in understanding huge benefits of immutability, let’s examine what kind of empowering restrictions can we place in our code!

I believe that benefits of static types rise with the complexity of software being written.
For example, I feel that Magento 2 would benefit a lot from static typing.

Humans have limited working memory. So, when writing software we can help ourselves by making code easier to understand. Having smaller pieces which operate on some contracts makes it simpler to both create and assemble those pieces. Static types bring a benefit of knowing what type of variable we have and which type of variable we need to return.

Input and Outputs

Functions should be tight in their return types and values and it can be argued that they should be wide in parameters accepted.
Functions which have return type being different depending on some logic flag can be hard to debug. Especially if error propagates further into the code and you gotta re-run debugger quite a few times to even get an idea about “how did that value get here?”.
With PHP7.0 we got the ability to declare return types on functions:
https://wiki.php.net/rfc/return_types

It looks and works OK, but it can be improved in some ways (from what I got by quickly skimming past versions of RFC, those issues could be covered).
First missing part is that it should be OK to tighten return type. (Only part of child classes, less generic)
This does not work (yet??):
Forgive me for bad OOP example 🙂

class Implementation {}
class BugFreeImplementation extends Implementation {}
 
class Software {
	public function produce() : Implementation {
		return new Implementation();
	}
}
 
class DifferentSoftware extends Software {
	// Does not work
	public function produce() : BugFreeImplementation {
		return new BugFreeImplementation();
	}
}
 
class DifferentSoftware extends Software {
	//Works, but consumers of our new and better method of producing software
	// can not know it is bug-free
	//Fact that it indeed is bug-free is just an implementation detail!
	//Program to interface, not to implementation!
	public function produce() : Implementation {
		return new BugFreeImplementation();
	}
}

Benefits

What are benefits of this? We are guaranteed that whenever we call product function, we will have a variable of type Implementation.
It will not be an array of somethings, a string or a null.

Future

While we are on the topic of null, there is actually RFC for that.
https://wiki.php.net/rfc/nullable_types
This would work like Option, Maybe or however they are called in other typed languages.

If the return type is ?Implementation, it can either be a null or Implementation AND NOTHING ELSE!

Powerful in cases where you call a function which may or may not return a value.
For example, retrieving a single entity from the database.

Hopefully, we will be able to use such type system improvements in future versions of PHP.

In all honesty: enforcing static type rules on large projects is a quite large improvement.
But, having more powerful type system would help a lot and make it easier.
PHP DocBLocks allows some of that power but does not really enforce it.

Classes vs Traits

I actually hoped to include traits in this post, but I think it is better to handle them separately.
Traits are really useful building blocks which we can use to compose classes.
While it may not initially seem so, when I think about their usages, they often overlap with dependency injection.
So hopefully, in next post we will cover traits, then a little on benefits on immutability and then perhaps an exploration of dependency injection and its benefits and drawbacks.

 

Reading Material:

https://pchiusano.github.io/2016-09-15/static-vs-dynamic.html

https://stackoverflow.com/questions/383947/what-does-it-mean-to-program-to-an-interface

http://wiki.c2.com/?DesignByContractAssertionsVsUnitTestsVsTypes

The post Declare static types to keep bugs away? appeared first on Inchoo.

]]>
http://inchoo.net/dev-talk/declare-static-types-keep-bugs-away/feed/ 0
Bypassing Magento 2 layout update restrictions in Admin http://inchoo.net/magento-2/bypassing-magento-2-layout-update-restrictions-admin/ http://inchoo.net/magento-2/bypassing-magento-2-layout-update-restrictions-admin/#comments Tue, 06 Jun 2017 10:42:28 +0000 http://inchoo.net/?p=29580 Magento’s layout system has been vastly improved in Magento 2 to be more accessible, more powerful and to be more streamlined. But, for some reason, only a very small subset of layout functions is made available for use in Magento 2 Admin (category layout XML updates, to be more precise). In this article, we’re going to...

The post Bypassing Magento 2 layout update restrictions in Admin appeared first on Inchoo.

]]>
Magento’s layout system has been vastly improved in Magento 2 to be more accessible, more powerful and to be more streamlined. But, for some reason, only a very small subset of layout functions is made available for use in Magento 2 Admin (category layout XML updates, to be more precise). In this article, we’re going to show a very simple way of bypassing this pesky restriction.

Layout update restrictions in Magento 2 Admin

In the interest of keeping the example simple and straightforward, let’s say we want to remove the page title element from a specific category. In Magento 2 admin, in the category layout update XML field we add the following line.

<referenceBlock name="page.main.title" remove="true" />

And when we click save, we get the following error:

Please correct the XML data and try again. Element ‘referenceBlock’: This element is not expected. Expected is one of (referenceContainer, container, update, move ). Line: 1

It’s important to note that this XML would be valid if added using XML files in a theme. It seems that different standards apply for the layout update field in Magento 2 Admin and for the theme layout files.

So, only the following XML is allowed:

  • referenceContainer – we can reference existing containers
  • container – we can create new containers
  • update – we can include various layout handles
  • move – we can move existing blocks around

This info will help us bypass the restriction.

Bypassing the layout update restrictions

We can simply bypass this restriction by wrapping our referenceBlock code in referenceContainer code. But we need to find the container which contains our page title element. By doing a simple search in IDE, we find the following code snippet.

<referenceContainer name="columns.top">
<!-- ... -->
    <block class="Magento\Theme\Block\Html\Title" name="page.main.title" template="html/title.phtml"/>
            <container name="page.messages" htmlTag="div" htmlClass="page messages">
                <block class="Magento\Framework\View\Element\Template" name="ajax.message.placeholder" template="Magento_Theme::html/messages.phtml"/>
                <block class="Magento\Framework\View\Element\Messages" name="messages" as="messages" template="Magento_Theme::messages.phtml"/>
            </container>
<!-- ... -->
</referenceContainer>

We use the columns.top container and reference it in our Layout Update XML in Admin and wrap it around our initial code.

<referenceContainer name="columns.top">
    <referenceBlock name="page.main.title" remove="true" />
</referenceContainer>

When we save this configuration, we do not get any errors on the category page in Admin and the page title block is removed on that specific category.

Conclusion

We hope to see these restrictions either removed from Magento 2 Admin XML layout update fields or better documentation that will explain the behavior in more detail. Magento 2 Admin would most certainly benefit of having unrestricted layout update features. Until then, we can hopefully use this bypass safely and hope that it’s upgrade-proof.

The post Bypassing Magento 2 layout update restrictions in Admin appeared first on Inchoo.

]]>
http://inchoo.net/magento-2/bypassing-magento-2-layout-update-restrictions-admin/feed/ 1
How to set Error / Maintenance page in Fastly CDN http://inchoo.net/magento-2/set-error-maintenance-page-fastly-cdn/ http://inchoo.net/magento-2/set-error-maintenance-page-fastly-cdn/#comments Tue, 06 Jun 2017 06:23:24 +0000 http://inchoo.net/?p=29629 The Fastly CDN will sometimes return a 503 error due to various issues that can occur. The generic text associated with a 503 error is “Service Unavailable” and it can mean variety of things. This default error response can be confusing to the customers and have a basic look and feel. This guide will show...

The post How to set Error / Maintenance page in Fastly CDN appeared first on Inchoo.

]]>
The Fastly CDN will sometimes return a 503 error due to various issues that can occur. The generic text associated with a 503 error is “Service Unavailable” and it can mean variety of things. This default error response can be confusing to the customers and have a basic look and feel.

This guide will show you how to set friendly or prettier 503 custom error page through Fastly module which will be served when:

  • When origin returns a response status greater than 500
  • When origin is down (i.e unhealthy, timeout, etc)

To set custom Error page, go to:

Magento admin > Stores > Configuration > Advanced > System > Full Page Cache > Fastly Configuration

Under the Fastly Configuration, click on the Error/Maintenance page:

The modal window will pop up. Paste your custom HTML code into the HTML textarea and press the Upload button to save changes.

Now when Fastly returns 503 error, instead of default error page which looks something like this:

You will serve your custom error page:

That’s it! Check our blog for more Fastly articles, or contact us if you are in need of it’s integration.

The post How to set Error / Maintenance page in Fastly CDN appeared first on Inchoo.

]]>
http://inchoo.net/magento-2/set-error-maintenance-page-fastly-cdn/feed/ 1
Learning and adrenaline – Inchoo Learning Day #9 http://inchoo.net/life-at-inchoo/learning-and-adrenaline-inchoo-learning-day-9/ http://inchoo.net/life-at-inchoo/learning-and-adrenaline-inchoo-learning-day-9/#respond Mon, 05 Jun 2017 12:47:30 +0000 http://inchoo.net/?p=29626 We had another Inchoo Learning Day in Baranja on Friday, May 26. It is a day when all of us Inchooers collectively leave our offices and enjoy the beauties of Slavonia and Baranja, and combine learning with team building activities. This was the 9th Inchoo Learning Day (ILD) in a row. This time; Zlatna Greda,...

The post Learning and adrenaline – Inchoo Learning Day #9 appeared first on Inchoo.

]]>
We had another Inchoo Learning Day in Baranja on Friday, May 26. It is a day when all of us Inchooers collectively leave our offices and enjoy the beauties of Slavonia and Baranja, and combine learning with team building activities.

This was the 9th Inchoo Learning Day (ILD) in a row. This time; Zlatna Greda, an eco center about 30 km from Osijek, in the middle of forest. Zlatna Greda is an organized concept that provides a practical experience of coexistence with nature as a place to learn, but also as a place to have fun; you can visit the adrenaline park, take a walk, or see the animals. It’s like a house in nature which functions through practical examples of sustainable growth, such as the renewable energy sources, waste separation, social entrepreneurship and responsible business conduct.

The learning part of Inchoo Learning Day took place in Zlatna Greda’s conference room. At the beginning, our CEO Tomislav commented on year 2016 and announced his plans for the current year, as well as the years to come. He made us all proud by showing the company’s good results and he also announced Inchoo Learning Day #10, so this is a good opportunity to make a written evidence of his promise. 🙂

Maja showed us some interesting facts from our social networks and web page:

News from our Sales department: Aron presented a new campaign on which they’re working on, and the processes they did so far that achieved good business results. He also talked about 130 inquiries we get monthly and assured us that none of them stay unanswered.

The designers, developers and consultants have presented the most interesting projects they have worked on so far. They told us about how they technically implemented certain features, extensions they used, new things they have learned, what they custom typed and what results they achieved. They also told us where they struggled and where they had fun while working on the projects.

After the working part of this event and a delicious barbecue, we also had a cake to celebrate Inchoo’s 9th birthday! We blew the candles and wished for many more successful years!

Besides all this, Zlatna Greda offers numerous sports activities: rowing in canoes or wooden boats, adrenaline park, artificial wall climbing, bicycle riding, archery, rope pulling, horseshoe throwing and many other activities. We chose climbing in the adrenaline park and riding bicycles through Baranja. The park consists of a basic and a higher level and the zipline. We had so much fun while climbing! Some of us even managed to “break” the adrenaline park, but nobody fell down since we were all tied together. The experience is amazing and if you haven’t already, you should definitely visit Zlatna Greda.

In the end, we had a farewell with our eCommerce consultant Tea, who is taking maternity leave. We wished her to have as few sleepless nights as possible with the twins she’s expecting.

It is hard to put all this experience into words, so check out all the pictures on our Facebook page!

The post Learning and adrenaline – Inchoo Learning Day #9 appeared first on Inchoo.

]]>
http://inchoo.net/life-at-inchoo/learning-and-adrenaline-inchoo-learning-day-9/feed/ 0
Version control systems in UI design http://inchoo.net/magento/design/version-control-systems-ui-design/ http://inchoo.net/magento/design/version-control-systems-ui-design/#comments Tue, 30 May 2017 10:58:43 +0000 http://inchoo.net/?p=29565 Our design team switched to working in Sketch a while ago but it wasn’t until version 43 we really started seeing some opportunities to change our workflows more significantly. It was also an opportunity for more designers to work on the same project as well as collaborate with developers more easily. The case of version...

The post Version control systems in UI design appeared first on Inchoo.

]]>
Our design team switched to working in Sketch a while ago but it wasn’t until version 43 we really started seeing some opportunities to change our workflows more significantly. It was also an opportunity for more designers to work on the same project as well as collaborate with developers more easily.

The case of version 43

With Sketch version 43, Bohemian Coding quietly announced – a revised file format. Behold. They introduced a new file format that allows reading and writing .sketch files manually or programmatically and go from Sketch straight to implementation. What does that mean for our workflow? Sketch had a file format that was workable not only from the design side but developer side too.

An unzipped Sketch file created .png preview and human-readable .json files. This created a question for us – could our design and development teams collaborate seamlessly? Are we finally to feed design assets directly to the development pipeline and integrate .sketch file at the same time as development?

By having similar repositories we could both edit the same designs.  That could be any element, modular component or an entire screen UI. Anything visual can now go back and forth between Sketch and UI frontend seamlessly – in theory. What does that mean for us? We’d have to apply distributed version control to support this new, high-level way of collaborating not only within our design team but with developers outside the team as well to create a safe and responsible environment for project development. We also needed to find a way of knowing which one of us made changes, when they were made and if we can roll back to them. Seeing visually what these changes would be an added bonus.

Just a side note, all of this also meant that documents created with Sketch 43 would not be compatible with previous versions. It was the quietest end of an era, perhaps for a reason.

Talking to our backend developer and testing this new file format we found that this new Sketch format offers a different workflow, but it wasn’t the smoothest one. We weren’t quite convinced in the widely spread “Design is code, code is design” line. Sure, this brings different disciplines closer, but it doesn’t equate them. At least not yet. The whole rename .sketch extension to .zip, unzip it and then connect to GitHub (which we use) process does work (and you get to see the changes in the preview .png). But, for starters, it would be a lot easier if there was some sort of Sketch launcher that would eliminate the extension renaming process.

It doesn’t seem possible to use branches in an effective way (they can’t be merged and all the integration work needs to be done manually) so we, designers can’t link our system with version control and as a consequence can’t have a good overview of the all the progress done on the design. Also, simply put, this is a great concept but we just don’t see a workflow where a developer might find himself changing design elements and checking that code back in so the Sketch app can render those changes next time we work on it.

Aaron Weyenberg (UX lead from TED) best described when our workflows would actually improve. “It’ll be from Sketch’s open format leading to more powerful plugins and third party tools to make the day to day collaboration of designers and developers faster while not upending their existing habits.”

Sharing is caring

Recently we had the issue of multiple designers working on the same project. There were constant debates as to which file is the “freshest” and manual overriding to create one master file. It moved us to explore versioning systems we could use within our design team. Libraries, as we’ve seen with Craft, works well if you’re willing to create separate text styles, color and uncategorised layers that can then be used through multiple .sketch files.

But, what if entire layouts and pages need to be changed and rearranged, not just styles and components. How do you update structure and flow?

Symbols work great for single-player, single-file mode, libraries are more multi-player, multi-file kind of situation, but what about multi-player, single-file scenario? At what point and how do we unify our work and keep a neat overview of it?

The tools of the trade

Developers already have tools like GitHub and Source Tree – we needed a similar version control system. Enter Folio, Plant and Abstract.

Folio

Folio is a Mac only app that allows you to join existing Git repositories. You can clone existing projects from anywhere, including Gitlab, Github, Bitbucket or your own Git server. Folio will automatically stay in sync. Unlike the other apps it has no Sketch plugin and is available for free in trial mode through a Free Viewer. It works with most files (Photoshop, Illustrator, Sketch, Antetype & SVG out of the box) and you can add support for most files that have Quicklook previews.

Folio makes it quite easy to add a Git repository and allows you to browse all files assets and work with them. When you update your Sketch file, Folio will automatically update (commit and push) it. It also keeps all versions of a file, so you can easily review them. However, it’s a bit messy since there is no folder organisation – just one library. Also, In Folio every commit you make is on a single file. Select a file on the left, show its version history on the right. Other than your written description, the only way to see which components on which artboards were changed is to compare them visually.

Plant

Plant is also a Mac only app with a Sketch plugin. It includes Cloud sync, version history, conflict resolution but seemingly you cannot use Plant with other version controlled softwares than the proprietary one (currently you get 1 GB). It’s based on pages (and has filtering options) – it recognises which artboards you made changes to and suggest them as changes ready to be sent. It has the ability to show only the modified artboards as well as comments to each version in a pretty neat preview mode of the artboard. It also syncs pretty fast. We only wish it was more clear as to what is the actual master file (since that’s our main goal). Right now, each version you change is listed in the history on the right and branching and merging is not as clear as we would like them to be.

Abstract

We have to give it up to Abstract as they seem to be our favourites. It took us no time to find our way around the app as it’s very clear what your commits and branches are as well as what the master file is. We had two questions for the crew that generously invited us to try out the Private Alpha – when can we buy Abstract and can we use our own GitHub (since that is what the company uses as a versioning tool) to clone projects and stay in sync. At the moment you can’t use Abstract with other version controlled softwares (i.e. Github and Bitbucket) than the proprietary one. We’re still waiting for a reply on if that would change. Currently it is available only for Mac and Sketch but it was announced that it would also be available for Adobe.

As they put it on their blog “Throw Abstract in the mix, and suddenly everyone on a team has access to a rich history of why certain things are the way they are, the decisions that led to the current state of the work, and a way to instantly start contributing in a meaningful way.” Can’t wait for the Public Beta!

 

I also have to give thanks where thanks is due – to the backend developer who helped create this article. Thanks for all the help and collaboration!

The post Version control systems in UI design appeared first on Inchoo.

]]>
http://inchoo.net/magento/design/version-control-systems-ui-design/feed/ 1
Are you in for some RWD workshop? Vitaly Friedman from Smashing Magazine is coming to Osijek, Croatia http://inchoo.net/dev-talk/rwd-workshop-vitaly-friedman-smashing-magazine-coming-osijek-croatia/ http://inchoo.net/dev-talk/rwd-workshop-vitaly-friedman-smashing-magazine-coming-osijek-croatia/#comments Thu, 25 May 2017 12:15:42 +0000 http://inchoo.net/?p=29534 We are proud to announce an awesome Responsive Web Design workshop by one and only Vitaly Friedman! This writer, speaker, author and editor-in-chief of Smashing Magazine will get up on stage at Inchoo’s hometown Osijek with smashing workshop “New Adventures in Responsive Web Design”. Faculty of Economics at Osijek will be the main point of...

The post Are you in for some RWD workshop? Vitaly Friedman from Smashing Magazine is coming to Osijek, Croatia appeared first on Inchoo.

]]>
We are proud to announce an awesome Responsive Web Design workshop by one and only Vitaly Friedman! This writer, speaker, author and editor-in-chief of Smashing Magazine will get up on stage at Inchoo’s hometown Osijek with smashing workshop “New Adventures in Responsive Web Design”.

Faculty of Economics at Osijek will be the main point of this event on June 17 from 9AM to 6PM.

What’s the “New Adventures in Responsive Web Design” about?

With HTTP/2, Service Workers, Responsive Images, Flexbox, SVG and Font Loading API now available in browsers, we all are still trying to figure out just the right strategy for designing and buildings responsive websites just in time. We want to use all of these technologies, but how can we use them efficiently, and how do we achieve it within a reasonable amount of time?

In this talk, Vitaly Friedman will be looking into a strategy for crafting fast, resilient and flexible responsive design systems by utilizing all of those wonderful shiny web technologies we have available today. We’ll also talk about dealing with legacy browsers and will cover a few “dirty” little techniques that might ensure that your responsive websites will stay relevant, flexible and accessible in the years to come.

This workshop is intended for frontend designers, developers and everybody else who is dealing with responsive design regularly or wants to better understand responsive design in general. Day before, on June 16 from 7PM, Vitaly will have a free presentation. A case study about improving Smashing Magazine’s performance, HTTP/2 transition and working with fonts will be spiced with a pinch of online advertising. Don’t miss it!

Who is Vitaly Friedman?

Vitaly Friedman is the co-founder and editor-in-chief of Smashing Magazine. He’s also famous for giving inspiring talks, responsive Web design workshops, online workshops and his love for solving complex UX, frontend and performance problems in large companies.

Hear the long story of how he got into web design, how he found his passion for the industry and how he ended up starting Smashing Magazine in 2006, one of the largest online design magazines.

How to get a ticket?

Tickets are available on Entrio, an event management platform commonly used in Croatia for selling tickets. Price is 400,00 kn, approximately 54 euros or 61 dollar and include covered lunch and coffee break.


Together with DaFED, this event is organised by “Osijek Software City”, a non-profit association that’s now shaping the identity of modern Osijek, making it recognised as a strong technology centre.

Those of you who are traveling to Osijek and need help with accommodation, give us a ping and we’ll help you out! And for those willing to see our new office, we’ll give you a tour! For additional informations, check the official Facebook event. See you in Osijek!

The post Are you in for some RWD workshop? Vitaly Friedman from Smashing Magazine is coming to Osijek, Croatia appeared first on Inchoo.

]]>
http://inchoo.net/dev-talk/rwd-workshop-vitaly-friedman-smashing-magazine-coming-osijek-croatia/feed/ 3
More/Less functionality in Magento2 http://inchoo.net/magento-2/more-less-functionality-in-magento2/ http://inchoo.net/magento-2/more-less-functionality-in-magento2/#comments Thu, 18 May 2017 11:29:49 +0000 http://inchoo.net/?p=29489 Everything you need to know on how to setup more/less functionality in Magento 2

The post More/Less functionality in Magento2 appeared first on Inchoo.

]]>
While working on a Magento 2 project for our client, I was supposed to create more/less button, which is not part of neither Blank or Luma themes. The button should be on product page, but only inside of Details tab on desktop (accordion on mobile), which displays product description field in Admin.

Before we get started, I have created a custom theme (Inchoo/MoreLess that is extending Blank theme), make sure to update the correct path for your theme as we go along. The code was written on latest (2.1.6) installation with sample data.

First of all, we need to create several files:

touch app/design/frontend/Inchoo/MoreLess/Magento_Catalog/layout/catalog_product_view.xml
touch app/design/frontend/Inchoo/MoreLess/requirejs-config.js
touch app/design/frontend/Inchoo/MoreLess/web/js/toggle-product-description.js
touch app/design/frontend/Inchoo/MoreLess/Magento_Catalog/templates/more-less.phtml
touch app/design/frontend/Inchoo/MoreLess/web/css/source/_theme.less

Let’s go over these files and explain for each one what code will be placed inside of them:

requirejs-config.js

Use this file to register your own JavaScript component:

var config = {
    map: {
        "*": {
            // alias: path-to-corresponding-js-file
            toggleProductDescription: 'js/toggle-product-description'
        }
    }
};
  • toggleProductDescription is arbitrary component alias that points to arbitrary location of a Javascript file (Magento will automatically append .js extension to the filename).

catalog_product_view.xml

This is main layout file for product page, I believe there is no need to explain its purpose. Inside of the content  container, new block is created with specified template file that is going to used:

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">    <body>
        <referenceContainer name="content">
            <block class="Magento\Framework\View\Element\Template" name="more-less-js" template="Magento_Catalog::more-less.phtml" />
        </referenceContainer>
    </body>
</page>

more-less.phtml

This file contains basic configuration of the more/less functionality. Given the fact that Magento utilizes the same template file for each tab, it is advisable to separate the JavaScript initialization part into a different file.

<script type="text/x-magento-init">
{
    ".product.data.items .product.attribute.description .value":{
       "toggleProductDescription":{
            "contentMaxHeight": 200
        }
    }
}
</script>

Let me explain briefly what are the elements and what is their purpose:

  • .product.data.items .product.attribute.description .valuestring (but in fact, CSS selector) that is used as a container for further JavaScript processing
  • toggleProductDescription – alias of the JavaScript file registered in RequireJS config file
  • contentMaxHeight – declaration of a variable that is going to be used inside of main JavaScript file
  • 200 – arbitrary value of a variable

toggle-product-description.js

Place all of your JavaScript logic in this file. Skeleton of such a JavaScript component should be like this:

define([
	"jquery", // declare your libraries, if you are using them
], function ($) { // delare library aliases
	'use strict';
 
	return function (config, node) {
		// paste snippet #1 here
		// paste snippet #2 here
	}
});

Here comes the most important part – the passing of parameters from .phtml file and sending back some output:

  • config – global variable that contains all of your custom variables. In this case, you are supposed to use config.contentMaxHeight to get the value of the variable
  • node – selector that can be used for initialising jQuery objects

Inside of the anonymous function, I have created a simple JSON object that holds all of the parameters for the more/less functionality: a link that triggers the change and a target element that the change gets applied to.

// snippet #1
 
var moreLess = {
    button: {
        el: $("<a>", {
            id: "toggle-description",
            href: "#"
        }),
        expanded_text: "Show less",
        collapsed_text: "Show more"
    },
    target: {
        el: $(node),
        height: $(node).height(),
        maxHeight: config.contentMaxHeight,
        collapsedClassName: "collapsed",
    }
};

 The snippet utilizes the function parameters which makes it possible to resolve the more/less state of the target element.

// snippet #2
 
if (moreLess.target.height > moreLess.target.maxHeight) {
    // update button text value
    moreLess.button.el.text(moreLess.button.collapsed_text);
 
    moreLess.target.el
        // add css class to apply some styling
        .addClass(moreLess.target.collapsedClassName)
        // append link to product description
        .parent().append(moreLess.button.el);
}
 
moreLess.button.el.on("click", function (e) {
    e.preventDefault();
 
    if (moreLess.target.el.hasClass(moreLess.target.collapsedClassName)) {
        moreLess.target.el.removeClass(moreLess.target.collapsedClassName);
        moreLess.button.el.text(moreLess.button.expanded_text);
    } else {
        moreLess.target.el.addClass(moreLess.target.collapsedClassName);
        moreLess.button.el.text(moreLess.button.collapsed_text);
    }
});

 When the component gets loaded, it is making a check to see if the height of the content is greater than the threshold defined and if so, append the more/less button and assign an event listener to it.

_theme.less

This is optional file for you to create, I have created some minimal styling (transparent-to-solid background) as a nice effect towards the the more/less button.

.product.attribute.description .value{
  max-height: none;
  position: relative;
  max-height: none;
  border-bottom: 1px solid #d1d1d1;
 
  &.collapsed {
    max-height: 200px;
    overflow: hidden;
 
    &:after {
      content: "";
      position: absolute;
      width: 100%;
      height: 160px;
      z-index: 1;
      display: block;
      bottom: 0;
 
      background: -moz-linear-gradient(top, rgba(255,255,255,0) 0%, rgba(255,255,255,1) 70%, rgba(255,255,255,1) 100%); /* FF3.6-15 */
      background: -webkit-linear-gradient(top, rgba(255,255,255,0) 0%,rgba(255,255,255,1) 70%,rgba(255,255,255,1) 100%); /* Chrome10-25,Safari5.1-6 */
      background: linear-gradient(to bottom, rgba(255,255,255,0) 0%,rgba(255,255,255,1) 70%,rgba(255,255,255,1) 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */
      filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#00ffffff', endColorstr='#ffffff',GradientType=0 ); /* IE6-9 */
    }
  }
}
 
#toggle-description {
  margin-top: 20px;
  display: inline-block;
}

Here is how it looks like on the frontend:

Leave a comment below if you have a question or if this blog post helped you out in your project.
Until next time, keep calm and code on! =)

The post More/Less functionality in Magento2 appeared first on Inchoo.

]]>
http://inchoo.net/magento-2/more-less-functionality-in-magento2/feed/ 4
A Developer’s Guide to Communicating With Clients http://inchoo.net/life-at-inchoo/developers-guide-communicating-clients/ http://inchoo.net/life-at-inchoo/developers-guide-communicating-clients/#comments Tue, 16 May 2017 07:04:23 +0000 http://inchoo.net/?p=29494 If you are a developer that does not always feel comfortable to communicate with the clients and all you want to do is just code and more code, then this article is created with you in my mind. While working with clients on daily basis, monitoring the communication between clients and developers and occasionally assisting...

The post A Developer’s Guide to Communicating With Clients appeared first on Inchoo.

]]>
If you are a developer that does not always feel comfortable to communicate with the clients and all you want to do is just code and more code, then this article is created with you in my mind.

While working with clients on daily basis, monitoring the communication between clients and developers and occasionally assisting developers in complicated dialogues, I have collected a good understanding of what’s the good way to communicate in given situation. And although each situation requires an individual approach, it was possible for me to standardize it a bit and share with you few situations and examples on how I think communication should go.

We all need to understand that each day there are big challenges on the plate for developers. They work really hard to provide solutions for complex problems, they are sometimes handling several projects at the same time and dealing with different cultures on a daily basis. They are in most cases introverts that don’t easily get comfortable to communicate so they just need some time to adapt to the newly situation and the client.

So let us see what are the situations I wanted to highlight in this blog post.

1) Informing clients that you have received a task

The first thing that crossed my mind as important is noting clients you have received a task that has been assigned to you. Maybe some of you might think how this is a no brainer but this little step is very important in everyday communication.

Let’s put this in context:

Situation A) The client assigns a task. A developer is available to look at it.

Solution: You should inform the client that you will look at it right away and come back to him with the more informed feedback or you can take a quick look and in the first response provide some questions to better understand what needs to be done.

Situation B) The client assigns a task. A developer is not free to look at it immediately.

Solution: Thank them for providing information regarding the task and inform them that you will start with it as soon as possible. This way you have let them know that you are not available at the moment, but as soon as you will be, you will work on it.

Do not:

  • Ignore the task for a day or couple of days while you don’t become available for resolving process.
  • Share additional information of why you cannot take this task right away. You will just complicate things that shouldn’t be complicated.

2) Frequently updating the client about the task progress

In most cases, a developer would inform the client that he has started with the task and he would not give any updates until he’s not finished. If we are talking about a task that needs a day or two to be completed, it is definitely right approach, as we don’t want to burden the client with too much updates. However, more time-consuming tasks that need at least 7-10 days to be fulfilled should be given updates from time to time.

The status updates shouldn’t be:

  • Too big or too short
  • Too often (i.e. if you are working on it for 7 days, 3 updates are enough)

Always have in mind to write only relevant and important information such as what you have done so far and what is the next step in the task progress. It is good to ask some questions too.

But what to do in the situation if you have not yet started with the task (it happens) and it is time to post a status update?

No one is proud of situations like this, but let’s see what you can do!

  1. Solution: You can start with it now and at the end of the day update the client about the progress. At least you have done something. 🙂
  2. Solution:  You should be honest with what is going on. You were busy with the emergency task(s) and you are starting with this task now. You will apologies and prioritise this task. Maybe the client will not be satisfied with these explanations at the moment, but don’t be afraid. He will appreciate your honesty after some time.

Do not:

3) Avoiding writing too long posts

You should remember that the client doesn’t have the time to read long posts, especially if something can be said in short and without complications. If you have written too long post, it might seem that you didn’t understand the task well. So always try to simplify things, if you can.

Since writing a long post would take a lot of your time, why shouldn’t you ask the client for a quick Skype call to discuss it?

You will know right away what he thinks of proposed solution and it will be less time consuming than writing a long post. Also, a voice communication is better for creating a bond with the client.

4) Notifying the client on the time about your vacations and obligations

Inform the client about your planned vacation in advance so that he can plan tasks towards you. Also, don’t take any complex tasks knowing that in the middle of their progress you will be gone and not available to check upon them.

When you are about to go on a vacation, name another developer to be on the service if something is urgent.

In the situation when you got sick or have some unexpected things to deal with, ask your teammates or team leader to write a quick note that you will be unavailable for a specific period of time on projects you work. With these approaches you will receive a lot of respect from the client.

But what should you do if the project is progressing slowly because of the client and now you have a 2 weeks delay from release?

(You have planned on taking a vacation in a week because the project supposed to be finished).

This is something that definitely requires individual approach and a deeper analysis of the situation. If you are very indecisive about how to react, the following question will maybe help to make a right decision:

  1. How important is this project for your company?
  2. Will this project really be launched in 2 weeks or maybe in 4-6 weeks?
  3. Are you able to move your vacation for few weeks or not?
  4. Can someone fulfil your position while you are away?

If you are willing to give it a try and move your vacation towards the project, you should let the client know that you’ve decided to stay in order to get things done, but make a clear deadline for how long you will be available. This way you will not feel guilty if another deadline is passed.

If you have mastered these skills in your everyday work then clients probably enjoy working with you. Some advanced things that you could do:

  • From time to time make jokes with the client because it would make your everyday work more pleasant.
  • Wish them all the best for birthday and holidays you know they celebrate.

And as an icing on the cake, the hardest question is left for the end.

What to do in the situation when the client is angry and rude?

From my experience, it is important to not be emotionally involved with a message and to respond cool-headed. The tone of the message should be calm and with respect. Don’t be afraid even if it is your mistake. Examine the situation – why did this happen and can it be fixed. Try to propose a solution. If you are not sure how to handle this situation, ask for your team leader to jump in.

I have written all of this from my personal experience, and I really do believe if you are following these suggestions that you shouldn’t have any big problems with the project communication.

Sharing is caring

What is your experience with working with clients? Do you have any tip to include in this post?

Feel free to share your thoughts with us!

The post A Developer’s Guide to Communicating With Clients appeared first on Inchoo.

]]>
http://inchoo.net/life-at-inchoo/developers-guide-communicating-clients/feed/ 1
Stable business means change http://inchoo.net/life-at-inchoo/stable-business-means-change/ http://inchoo.net/life-at-inchoo/stable-business-means-change/#respond Thu, 11 May 2017 11:00:42 +0000 http://inchoo.net/?p=29480 Inchoo is a company that operates with stability, one can say. It grows year after year by the number of employees, value of projects, annual income and many other components. From outside it looks like everything is set up, and business just grows by itself. Well… Not everything is how it looks Well, it’s not...

The post Stable business means change appeared first on Inchoo.

]]>
Inchoo is a company that operates with stability, one can say. It grows year after year by the number of employees, value of projects, annual income and many other components. From outside it looks like everything is set up, and business just grows by itself. Well…

Not everything is how it looks

Well, it’s not exactly like that. What looks like a quiet and steady conduct of a business for somebody looking from the outside, it’s quite different from the inside! If you want things to run smoothly, you have to constantly monitor, review and, if needed, improve every business process, from ones in office management to those in project management. Company’s management and team leaders are in charge of that, but other employees might also contribute to making processes better and more efficient. It’s vibrant and exciting!

Of course, not every change is good. You often have to choose between keeping on working with a decent tool or moving to a cool new one, and decide to stay with the old one if it’s too much effort and not so much gain from switching tools. Changes cost time, money or both. Be sure you really need that change before you go for it.

Also, you have to think about company values. Improvements and changes shouldn’t interfere with your company character and attitude! Your company’s values tell who you are (or want to be), so you have to be careful not to endanger or lose them.

Small, medium, big

When the company is small, you don’t have to set a strict hierarchy, middle management or communication processes. You can change things faster, decide and implement something on the fly, share it with a few colleagues of yours while you drink together your morning coffee and move on.

When your company grows, with time it becomes a little bit more difficult (you have to write your infos on some notice boards or send it via e-mail, Slack or some other communication channel), but it’s still not a big problem to change some business processes.

Then your company grows even more. Now you need company policies and routine. You have to be aware of many elements, predict potential problems and prevent or solve them quickly. You don’t want a minor issue to become a bigger one!

War never changes, but running business does. 😉

The post Stable business means change appeared first on Inchoo.

]]>
http://inchoo.net/life-at-inchoo/stable-business-means-change/feed/ 0
Pagination with rel=”next” and rel=”prev” in Magento 2 http://inchoo.net/magento-2/pagination-relnext-relprev-magento-2/ http://inchoo.net/magento-2/pagination-relnext-relprev-magento-2/#respond Wed, 10 May 2017 07:31:35 +0000 http://inchoo.net/?p=29466 Out of the box, Magento 2 offers fair amount of search engine optimization options but when it comes to category pages, we only have option to add canonical meta tags. In today’s blog post, we will try to spice that up a bit by implementing our own variation of canonical tag and by adding rel=”next” and...

The post Pagination with rel=”next” and rel=”prev” in Magento 2 appeared first on Inchoo.

]]>
Out of the box, Magento 2 offers fair amount of search engine optimization options but when it comes to category pages, we only have option to add canonical meta tags. In today’s blog post, we will try to spice that up a bit by implementing our own variation of canonical tag and by adding rel=”next” and rel=”prev” tags to help bots with paginated content.

There are several ways to implement said functionality but the first step will most likely involve creating new Magento 2 module. I decided to implement our logic using event observer approach, so the first thing we do is configure our module to watch certain events. We do this by creating events.xml file in our modules etc/frontend folder followed by creating our observer class.

<?xml version="1.0"?>
 
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
    <event name="layout_generate_blocks_after">
        <observer name="categorySeo" instance="Inchoo\CategorySeo\Observer\Category" />
    </event>
</config>

As you can see from the XML above, we are observing layout_generate_blocks_after event. Since this event is not exclusive to category pages, first thing we do in our observer execute method is check if we are indeed on category view page. This is trivial since we already have full action name included in event object data.

if ('catalog_category_view' != $observer->getEvent()->getFullActionName()) {
    return $this;
}

 Replacing default canonical tag

We do this because in default implementation, canonical tag always points to root category URL, regardless of the page or filter combination applied.

To remove default canonical tag we will need category model instance. You could use registry (current_category) to retrieve it. In this example I used layout object instead since it’s also a part of the event object data.

/** @var \Magento\Catalog\Block\Product\ListProduct $productListBlock */
$productListBlock = $observer->getEvent()->getLayout()->getBlock('category.products.list');
$category = $productListBlock->getLayer()->getCurrentCategory();
 
/**
 * Remove default canonical tag
 */
if ($this->categoryHelper->canUseCanonicalTag()) {
    $this->pageConfig->getAssetCollection()->remove($category->getUrl());
}

We can now add our own canonical tag. To do that we will use pager block instance (\Magento\Theme\Block\Html\Pager) to generate our canonical URL and page config (\Magento\Framework\View\Page\Config) to insert it.

/** @var \Magento\Catalog\Block\Product\ProductList\Toolbar $toolbarBlock */
$toolbarBlock = $productListBlock->getToolbarBlock();
/** @var \Magento\Theme\Block\Html\Pager $pagerBlock */
$pagerBlock = $toolbarBlock->getChildBlock('product_list_toolbar_pager');
$pagerBlock->setAvailableLimit($toolbarBlock->getAvailableLimit())
    ->setCollection($productListBlock->getLayer()->getProductCollection());
 
/**
 * Add rel canonical with page var
 */
$this->pageConfig->addRemotePageAsset(
    $this->getPageUrl([
        $pagerBlock->getPageVarName() => $pagerBlock->getCurrentPage()
    ]),
    'canonical',
    ['attributes' => ['rel' => 'canonical']]
);

You might notice we are using our own getPageUrl method. It’s a slightly customized version of the method which can be found in \Magento\Theme\Block\Html\Pager class.

/**
* Retrieve page URL by defined parameters
*
* @param array $params
* @return string
*/
protected function getPageUrl($params = [])
{
    $urlParams = [];
    $urlParams['_current'] = false;
    $urlParams['_escape'] = true;
    $urlParams['_use_rewrite'] = true;
    $urlParams['_query'] = $params;
 
    return $this->urlBuilder->getUrl('*/*/*', $urlParams);
}

 Adding rel=”prev” and rel=”next”

Final step involves adding rel=”prev” and rel=”next” to indicate paginated content. By doing this we are informing search engine bots to treat these pages as a logical sequence, thus consolidating their linking properties and usually sending searchers to the first page.

/**
 * Add rel prev and rel next
 */
if (1 < $pagerBlock->getCurrentPage()) {
    $this->pageConfig->addRemotePageAsset(
        $this->getPageUrl([
            $pagerBlock->getPageVarName() => $pagerBlock->getCollection()->getCurPage(-1)
        ]),
        'link_rel',
        ['attributes' => ['rel' => 'prev']]
    );
}
if ($pagerBlock->getCurrentPage() < $pagerBlock->getLastPageNum()) {
    $this->pageConfig->addRemotePageAsset(
        $this->getPageUrl([
            $pagerBlock->getPageVarName() => $pagerBlock->getCollection()->getCurPage(+1)
        ]),
        'link_rel',
        ['attributes' => ['rel' => 'next']]
    );
}

Final thoughts

And that’s it! You should now have a working code which adds canonical, rel=”prev” and rel=”next” meta tags. While this is not a complete SEO solution, I like to think it’s a nice improvement of default functionality. Obviously there is a lot of room for improvement, for example we are not even considering product_list_limit and product_list_ordervariables or layered navigation filters, but that’s a story for another time.

The post Pagination with rel=”next” and rel=”prev” in Magento 2 appeared first on Inchoo.

]]>
http://inchoo.net/magento-2/pagination-relnext-relprev-magento-2/feed/ 0
This is why our clients never get penalized by Google http://inchoo.net/online-marketing/this-is-why-our-clients-never-get-penalized-by-google/ http://inchoo.net/online-marketing/this-is-why-our-clients-never-get-penalized-by-google/#comments Fri, 05 May 2017 10:02:26 +0000 http://inchoo.net/?p=29439 Often, during an SEO audit, we figure out that the store that came to us for the audit suffered a manual or an algorithmical penalty from Google which resulted in a significant loss of organic traffic. During the years we got pretty experienced in removing such penalties and getting the website back on the right...

The post This is why our clients never get penalized by Google appeared first on Inchoo.

]]>
Often, during an SEO audit, we figure out that the store that came to us for the audit suffered a manual or an algorithmical penalty from Google which resulted in a significant loss of organic traffic.

During the years we got pretty experienced in removing such penalties and getting the website back on the right track for clients that listened to our advice.

But, did you know our own clients who have a consulting retainer with us never got penalized by Google?

Here’s why…

Our clients never get penalized by Google because…

…we obey the rules. And we proactively warn our clients when they’re breaking the rules and getting themselves in danger of penalty. We monitor their websites to make sure none of their competitors are doing any negative SEO either.

This resulted in one simple fact that all of our clients in almost a decade of our existence that had a consulting retainer with us are completely free of Google penalties.

What are those secret rules that you obey?

Those rules are not secret at all. As the matter of fact, Google has them written down for you. Here’s exactly what causes penalties written by Google for everyone to easily see and understand.

But if that’s all it takes not to get penalized then why do so many online stores with professional SEO agencies get penalized anyway?

Because they don’t really follow the rules. They take “shortcuts” to ranking. They bend the rules. They feel comfortable in a “gray” area and risk penalties which eventually catch up to them.

How many times have you had an offer from an SEO agency to do link building for you? And they claim to be white hat because their specific link building technique is white hat?

Let me tell you the truth – no link building technique is white hat. They’re all breaking Google’s rules.

Only white-hat link that passes PageRank is a link you didn’t know you’ll get before you got it. That means links can’t possibly be built in a white-hat way. They can only be earned naturally.

But without breaking the rules there can’t be improvements in organic traffic

That is totally not true. As the matter of fact, we have a lot of happy clients whose cases prove the opposite is true. Playing by the rules and investing in quality technical on-site SEO instead of concentrating on link building pays off big time in the long run.

Here’s an example of a year over year organic traffic growth for one of our largest clients. We’re talking millions in extra revenue here. This is all achieved without breaking a single rule in Google’s eyes which means these results are here to stay and they don’t risk client’s business with potential penalties. As you can see, new user growth is larger than total traffic growth which means that this organic traffic increase is not caused by increase in brand awareness and growth in other acquisition channels. It’s actually the best traffic you can get, the organic traffic that’s acquiring new customers.

White hat year over year organic growth SEO case study 2017

This is not a coincidence. We have a habit of delivering such results. We’ve been working with this client for quite a long time. Here’s organic traffic improvement for the same client which was achieved in 3 years time:

3 years case study organic traffic growth on-site technical

White-hat all the way

Following rules and being the best you can be on-site pays off big time in the long run. If you believe your store could be our next success story, get in touch with us today!

The post This is why our clients never get penalized by Google appeared first on Inchoo.

]]>
http://inchoo.net/online-marketing/this-is-why-our-clients-never-get-penalized-by-google/feed/ 1
Magento 2: How to display static block content in modal overlay http://inchoo.net/magento-2/magento-2-how-to-display-static-block-content-in-modal-overlay/ http://inchoo.net/magento-2/magento-2-how-to-display-static-block-content-in-modal-overlay/#respond Thu, 04 May 2017 10:01:02 +0000 http://inchoo.net/?p=29451 Many times we need to show some sort of information in modal overlay when customer comes to the site. We can use it for many kind of purposes like newsletter subscription form, coupon codes or just some general information. In this article I’ll show you how to create the most basic functionality around this. The...

The post Magento 2: How to display static block content in modal overlay appeared first on Inchoo.

]]>
Many times we need to show some sort of information in modal overlay when customer comes to the site.
We can use it for many kind of purposes like newsletter subscription form, coupon codes or just some
general information.
In this article I’ll show you how to create the most basic functionality around this.

The challenge

When customer comes to our site, we want to show load specific static block content
into the modal overlay and show it only once to every customer.

Solution:

We should start by creating new module in Magento 2.

For that purpose start by creating app/code/Inchoo/ModalOverlay/registration.php
with following content:

<?php
/**
 * @category    Inchoo
 * @package     Inchoo_ModalOverlay
 * @copyright   Copyright (c) Inchoo (http://inchoo.net/)
 */
\Magento\Framework\Component\ComponentRegistrar::register(
    \Magento\Framework\Component\ComponentRegistrar::MODULE,
    'Inchoo_ModalOverlay',
    __DIR__
);

Continue by creating app/code/Inchoo/ModalOverlay/etc/module.xml.
Put the following inside:

<?xml version="1.0"?>
<!--
  @category    Inchoo
  @package     Inchoo_ModalOverlay
  @copyright   Copyright (c) Inchoo (http://inchoo.net/)
-->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="Inchoo_ModalOverlay" setup_version="1.0.0">
    </module>
</config>

That will create a new module in Magento 2.
What we want to do now is to create block that will be shown in modal.
For that purpose, let’s continue by creating another file called
app/code/Inchoo/ModalOverlay/Block/ModalOverlay.php
This one should have the following content:

<?php
 
namespace Inchoo\ModalOverlay\Block;
 
use Magento\Cms\Api\BlockRepositoryInterface;
use Magento\Cms\Api\Data\BlockInterface;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\View\Element\Template;
use Magento\Framework\View\Element\Template\Context;
 
/**
 * Class ModalOverlay
 *
 * @category    Inchoo
 * @package     Inchoo_ModalOverlay
 * @copyright   Copyright (c) Inchoo (http://inchoo.net/)
 */
class ModalOverlay extends Template
{
    /**
     * @var BlockRepositoryInterface
     */
    private $blockRepository;
 
    /**
     * ModalOverlay constructor.
     *
     * @param BlockRepositoryInterface $blockRepository
     * @param Context $context
     * @param array $data
     */
    public function __construct(
        BlockRepositoryInterface $blockRepository,
        Context $context,
        array $data = []
    ) {
        $this->blockRepository = $blockRepository;
 
        parent::__construct($context, $data);
    }
 
    /**
     * Retrieve modal overlay content
     *
     * @param $identifier
     * @return bool|string
     */
    public function getContent($identifier)
    {
        try {
            /** @var BlockInterface $block */
            $block = $this->blockRepository->getById($identifier);
            $content = $block->getContent();
        } catch (LocalizedException $e) {
            $content = false;
        }
 
        return $content;
    }
}

Newly created block needs to have a template, so let’s create it and initialize our JavaScript app/code/Inchoo/ModalOverlay/view/frontend/templates/modal_overlay.phtml

<?php
/**
 * @category    Inchoo
 * @package     Inchoo_ModalOverlay
 * @copyright   Copyright (c) Inchoo (http://inchoo.net/)
 */
?>
<?php /** @var Inchoo\ModalOverlay\Block\ModalOverlay $block */ ?>
<?php if ($content = $block->getContent('this-should-be-renamed')) :?>
<div id="modal-overlay" style="display:none;">
    <?php /* @noEscape */ echo $content ?>
</div>
<script type="text/x-magento-init">
    {
        "*": {
            "Magento_Ui/js/core/app": {
                "components": {
                    "modal_overlay": {
                        "component": "Inchoo_ModalOverlay/js/modal_overlay"
                    }
                 }
            }
        }
    }
</script>
<?php endif;?>

Let’s add previously created block into layout on every page.
For that purpose, create app/code/Inchoo/ModalOverlay/view/frontend/layout/default.xml and
put the following inside:

<?xml version="1.0"?>
<!--
  @category    Inchoo
  @package     Inchoo_ModalOverlay
  @copyright   Copyright (c) Inchoo (http://inchoo.net/)
-->
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceContainer name="content">
            <block class="Inchoo\ModalOverlay\Block\ModalOverlay"
                   template="Inchoo_ModalOverlay::modal_overlay.phtml"
                   name="modalOverlay"
                   as="modalOverlay"/>
        </referenceContainer>
    </body>
</page>

And finally, let’s add app/code/Inchoo/ModalOverlay/view/frontend/web/js/modal_overlay.js
with the following content:

/**
 * @category    Inchoo
 * @package     Inchoo_ModalOverlay
 * @copyright   Copyright (c) Inchoo (http://inchoo.net/)
 */
define([
    'uiComponent',
    'jquery',
    'Magento_Ui/js/modal/modal',
    'Magento_Customer/js/customer-data'
], function (Component, $, modal, storage) {
    'use strict';
 
    var cacheKey = 'modal-overlay';
 
    var getData = function () {
        return storage.get(cacheKey)();
    };
 
    var saveData = function (data) {
        storage.set(cacheKey, data);
    };
 
    if ($.isEmptyObject(getData())) {
        var modal_overlay = {
            'modal_overlay': false
        };
        saveData(modal_overlay);
    }
 
    return Component.extend({
 
        initialize: function () {
 
            this._super();
            var options = {
                type: 'popup',
                responsive: true,
                innerScroll: false,
                title: false,
                buttons: false
            };
 
            var modal_overlay_element = $('#modal-overlay');
            var popup = modal(options, modal_overlay_element);
 
            modal_overlay_element.css("display", "block");
 
            this.openModalOverlayModal();
 
        },
 
        openModalOverlayModal:function(){
            var modalContainer = $("#modal-overlay");
 
            if(this.getModalOverlay()) {
               return false;
            }
            this.setModalOverlay(true);
            modalContainer.modal('openModal');
        },
 
        setModalOverlay: function (data) {
            var obj = getData();
            obj.modal_overlay = data;
            saveData(obj);
        },
 
        getModalOverlay: function () {
            return getData().modal_overlay;
        }
 
    });
});

Conclusion

That is it. All that’s left is to create a static block and activate the module.
This should give you a basic module that you can modify however fits you best.

If you want to see how we can help you with these types of custom work on your Magento store, get in touch!

The post Magento 2: How to display static block content in modal overlay appeared first on Inchoo.

]]>
http://inchoo.net/magento-2/magento-2-how-to-display-static-block-content-in-modal-overlay/feed/ 0
3 things you should check before you continue with your PPC campaigns http://inchoo.net/ecommerce/3-things-start-continue-paying-incoming-traffic/ http://inchoo.net/ecommerce/3-things-start-continue-paying-incoming-traffic/#comments Tue, 02 May 2017 11:23:30 +0000 http://inchoo.net/?p=29419 So you have been running an eCommerce site for some time now but in order to increase sales, natural thing to do is to increase traffic towards your site. Regardless of your site’s SEO health and organic ranking, PPC traffic is also something you shouldn’t miss out, because hey, your competitors are also doing it...

The post 3 things you should check before you continue with your PPC campaigns appeared first on Inchoo.

]]>
So you have been running an eCommerce site for some time now but in order to increase sales, natural thing to do is to increase traffic towards your site. Regardless of your site’s SEO health and organic ranking, PPC traffic is also something you shouldn’t miss out, because hey, your competitors are also doing it and being within the first 3 organic results today (if you are lucky) isn’t the same like a few years ago.

Paying for incoming clicks is natural thing to do but before you continue (start) investing money in driving traffic to your site, pay attention to these three essential things that we noticed many site owners miss out.

1. Functionality & usability check

Yeah, you played a giant role in setting everything up on your store and making sure it works for your visitors (because you are the one who knows your business the best). But stop just for a second and think about when did you do your last serious functionality and usability check.

This is your site and you know its every pixel as well as the right steps to take in order to find and buy specific product. But this probably doesn’t apply to your visitors. They might experience some real world issues that you haven’t notice and addressed as something that should be fixed. Each and every unnecessary questions in users head while browsing through your shop might prevent them from from proceeding to checkout… and that isn’t something you want.

Seriously consider adding a few objective parties to the whole story: ask your friends to test your site or hire some ecommerce professionals to do it for you. Actually you should do both. Although your site worked great some time ago, the world around you, the competitor’s sites and your customers’ habits changed so make sure you identify the new trends and functionalities in the checkout funnel and try implementing those on your site.

If you are struggling with the budget and that is the main reason why you haven’t hired proper help yet, just think about how much money each click costs – if it drives visitor to non functional site with poor usability – then regardless of the click price, it costs too much.

2. Observe & analyze your competitors and reconsider your current offers

By offers, I mean product prices, shipping and returns conditions, special offers, etc. Today’s customers get very well informed before they make the final buying decision because they are just a few clicks away from figuring out the place with the best bargain. They just need to open a few tabs more and they are ready to make a final decision. Don’t let your site to be only one of the “opened tabs”.

If your current conditions aren’t attractive as those on your competitors sites, maybe your should pause specific campaigns or bid less aggressively until you start offering a better deal.

Does this means that if I don’t have the best conditions out-there, I shouldn’t advertise at all? No, of course not, but if this is the case then you shouldn’t be surprised if you see poor ROAS. In order for someone to conclude that you are not offering the best conditions and that they are not going to buy from you, one has to click on your ad first (in many cases) – and all those clicks eat your advertising budget.

Be aware of the things your competitors do and make sure you are not missing out the conversions due to slightly higher product price.

3. Perform an in-depth analysis of your current campaigns to make sure your ads are correct and trustworthy

We had a few clients that didn’t pay enough attention to their ads and messages they convey through them. This means that they haven’t updated their campaigns for a while which lead to following situations:

  • Misleading ads. They have been driving traffic towards their site with incorrect messages about their special offers. Having something like “Up to 40% on all T-Shirts…” isn’t helping if you currently don’t have that offer on your site. It actually does you harm – because you are getting people that are about to become disappointing with the fact that they were misleadand you are spending your money on those clicks. Few days later, when you start your remarketing campaign and advertise the correct discount info, people will probably ignore your new ads as they won’t trust your anymore. Check all your ads and make sure they are correct and honest.
  • Incorrect or broken destination URLs. You’ve finally managed to attract person’s attention and made him to click on your ad. Instead of providing a state of the art landing page and user flow, you bring a person to the wrong landing page or even 404 page. Speaking of leaving a great first impression, right? Check your destination links to make sure this paid click lead a person to the thing he wants to find so he can add an item to cart and head over to checkout.

Conclusion

Think about these three common mistakes that we outlined in this blog post and make sure you are not repeating them. If you don’t have enough time to check everything by yourself, seriously consider to allocate a part of the PPC budget and hire a professional who could help you with that. You are maybe just a few dozens of consultation and development hours away from having much more intuitive and better functioning site that will convert much better than it does right now. If you don’t know where to start, check out our top selling audit service.

The post 3 things you should check before you continue with your PPC campaigns appeared first on Inchoo.

]]>
http://inchoo.net/ecommerce/3-things-start-continue-paying-incoming-traffic/feed/ 1
External database connection in Magento http://inchoo.net/magento/magento-database/external-database-connection-magento/ http://inchoo.net/magento/magento-database/external-database-connection-magento/#comments Thu, 27 Apr 2017 14:58:39 +0000 http://inchoo.net/?p=29408 Most of the time working with Magento, a single database connection is just enough. Magento has excellent system of adding new tables in database or extending existing ones. So, why would there be a need for an external database connection outside the Magento system? Well, one of the examples is data migration from another ecommerce...

The post External database connection in Magento appeared first on Inchoo.

]]>
Most of the time working with Magento, a single database connection is just enough. Magento has excellent system of adding new tables in database or extending existing ones. So, why would there be a need for an external database connection outside the Magento system? Well, one of the examples is data migration from another ecommerce system. In this article, a simple connection to external database is explained with CRUD (create, read, update, delete) examples.

Configuration

This external database connection is similarly defined as the Magento default one – in an XML configuration. The difference is that foreign connection is defined inside particular module’s XML configuration. It defines read and write adapters, setup and database credentials information. Foreign tables are defined in the same way as magento tables. They are under inchoo_foreignconnection_resource node so the model resource can be invoked later in the code. For demonstration purpose, there’s a frontend node in XML configuration that defines front name of the controller (fconn).

<?xml version="1.0"?>
<config>
    <modules>
        <Inchoo_ForeignConnection>
            <version>1.4.2</version>
        </Inchoo_ForeignConnection>
    </modules>
    <global>
        <models>
            <inchoo_foreignconnection>
                <class>Inchoo_ForeignConnection_Model</class>
                <resourceModel>inchoo_foreignconnection_resource</resourceModel>
            </inchoo_foreignconnection>
            <inchoo_foreignconnection_resource>
                <class>Inchoo_ForeignConnection_Model_Resource</class>
                <entities>
                    <product>
                        <table>product_description</table>
                    </product>
                </entities>
            </inchoo_foreignconnection_resource>
        </models>
        <resources>
            <inchoo_foreignconnection_write>
                <connection>
                    <use>inchoo_foreignconnection_database</use>
                </connection>
            </inchoo_foreignconnection_write>
            <inchoo_foreignconnection_read>
                <connection>
                    <use>inchoo_foreignconnection_database</use>
                </connection>
            </inchoo_foreignconnection_read>
            <inchoo_foreignconnection_setup>
                <connection>
                    <use>core_setup</use>
                </connection>
            </inchoo_foreignconnection_setup>
            <inchoo_foreignconnection_database>
                <connection>
                    <host><![CDATA[localhost]]></host>
                    <username><![CDATA[username]]></username>
                    <password><![CDATA[password]]></password>
                    <dbname><![CDATA[db_name]]></dbname>
                    <initStatements><![CDATA[SET NAMES utf8]]></initStatements>
                    <model><![CDATA[mysql4]]></model>
                    <type><![CDATA[pdo_mysql]]></type>
                    <pdo_type><![CDATA[]]></pdo_type>
                    <active>1</active>
                </connection>
            </inchoo_foreignconnection_database>
        </resources>
    </global>
    <frontend>
        <routers>
            <inchoo_foreignconnection>
                <use>standard</use>
                <args>
                    <module>Inchoo_ForeignConnection</module>
                    <frontName>fconn</frontName>
                </args>
            </inchoo_foreignconnection>
        </routers>
    </frontend>
</config>

Model

Next thing is a model that will use defined foreign connection to get data or to save data in a foreign database. Here, the model is initialized with the product table from XML configuration, that in this case defines product_description table.

class Inchoo_ForeignConnection_Model_Product extends Mage_Core_Model_Abstract
{
    protected $_eventPrefix = 'inchoo_foreignconnection_product';
    protected $_eventObject = 'product';
 
    protected function _construct()
    {
        $this->_init('inchoo_foreignconnection/product');
    }
}

Model resource class is also defined with the same xml configuration node in _init() function, but with the TABLE_PRIMARY_KEY parameter. In this class, several functions can be created that will work with external data.

First example is createDataInResource function, which inserts data in model’s table. It takes array of parameters that will be inserted.

Second example is a readDataFromResource function that fetches all data from model’s table. Read adapter must be defined first. It is a configuration node from xml that defines read connection. After read adapter definition, Magento database functions can be used (select(), from(), limit(), etc..). When query is constructed completely, it can be executed with read adapter. Data can be retrieved with fetchPairs() or fetchAll() function. fetchAll() is used to get all records returned from mysql.

updateDataInResource and deleteDataFromResource functions take additional $id parameter that defines which record will be updated or deleted.

class Inchoo_ForeignConnection_Model_Resource_Product extends Mage_Core_Model_Resource_Db_Abstract
{
    const TABLE_PRIMARY_KEY = 'product_id';
 
    protected function _construct()
    {
        $this->_init('inchoo_foreignconnection/product', self::TABLE_PRIMARY_KEY);
    }
 
    public function createDataInResource($values = array())
    {
        $writeAdapter = $this->_getWriteAdapter();
        try {
            $writeAdapter->insert(
                $this->getMainTable(),
                $values
            );
        } catch (Exception $e) {
            Mage::log('Unable to insert data to external resource. ' . $e->getMessage(), null, null, true);
        }
    }
 
    public function readDataFromResource()
    {
        $data = array();
        $readAdapter = $this->_getReadAdapter();
        $select = $readAdapter->select()
            ->from($this->getMainTable(), '*')
            ->limit(20);
 
        try {
            $data = $readAdapter->fetchAll($select);
        } catch (Exception $e) {
            Mage::log('Unable to fetch data from external resource. ' . $e->getMessage(), null, null, true);
        }
 
        return $data;
    }
 
    public function updateDataInResource($id, $values = array())
    {
        $writeAdapter = $this->_getWriteAdapter();
        try {
            $writeAdapter->update(
                $this->getMainTable(),
                $values,
                self::TABLE_PRIMARY_KEY . '=' . $id
            );
        } catch (Exception $e) {
            Mage::log('Unable to update data in external resource. ' . $e->getMessage(), null, null, true);
        }
    }
 
    public function deleteDataFromResource($id)
    {
        $writeAdapter = $this->_getWriteAdapter();
        try {
            $writeAdapter->delete(
                $this->getMainTable(),
                self::TABLE_PRIMARY_KEY . '=' . $id
            );
        } catch (Exception $e) {
            Mage::log('Unable to delete data from external resource. ' . $e->getMessage(), null, null, true);
        }
    }
}
class Inchoo_ForeignConnection_Model_Resource_Product_Collection extends Mage_Core_Model_Resource_Db_Collection_Abstract
{
    public function _construct()
    {
        $this->_init('inchoo_foreignconnection/product');
    }
}

Usage in controller

All these functions are demonstrated in IndexController class but since they are defined in model’s resource class, they can be called in any controller class.

class Inchoo_ForeignConnection_IndexController extends Mage_Core_Controller_Front_Action
{
    public function indexAction()
    {
        // Create
        $foreignProductCreate = Mage::getModel('inchoo_foreignconnection/product')->getResource();
        $foreignProductCreate->createDataInResource(
            array(
                'product_name' => 'Product name',
                'product_description' => 'Product description'
            )
        );
 
        // Read
        $foreignProductRead = Mage::getModel('inchoo_foreignconnection/product')->getResource();
        $result = $foreignProductRead->readDataFromResource();
        var_dump($result);
 
        // Update
        $foreignProductUpdate = Mage::getModel('inchoo_foreignconnection/product')->getResource();
        $foreignProductUpdate->updateDataInResource(
            3394,
            array(
                'product_name' => 'Product name updated',
                'product_description' => 'Product description updated'
            )
        );
 
        // Delete
        $foreignProductDelete = Mage::getModel('inchoo_foreignconnection/product')->getResource();
        $foreignProductDelete->deleteDataFromResource(3394);
    }
}

In most scenarios, Magento will use different type of external connection to retrieve or send data, but sometimes an external database connection like this will be the best way to go. One of the examples would be when you want to import products from another system to Magento with their xsell or upsell products. In that case, read connection would be used to retrieve product data and write connection would be used to save xsell or upsell product ids in a temporary table so they can be assigned to Magento product when all products from external system are imported. 

The post External database connection in Magento appeared first on Inchoo.

]]>
http://inchoo.net/magento/magento-database/external-database-connection-magento/feed/ 2
Javascript Bundling in Magento 2 http://inchoo.net/magento-2/javascript-bundling-magento-2/ http://inchoo.net/magento-2/javascript-bundling-magento-2/#comments Fri, 21 Apr 2017 09:32:09 +0000 http://inchoo.net/?p=29344 Javascript bundling is a technique that groups separate files in order to reduce the number of HTTP requests that are required to load a page. Bundling is commonly used in today’s “module-based” development where some functionalities are basically split into Modules (roughly explained). For loading modules, we usually use some of popular module loaders such...

The post Javascript Bundling in Magento 2 appeared first on Inchoo.

]]>
Javascript bundling is a technique that groups separate files in order to reduce the number of HTTP requests that are required to load a page. Bundling is commonly used in today’s “module-based” development where some functionalities are basically split into Modules (roughly explained). For loading modules, we usually use some of popular module loaders such as rollup.js or RequireJS (which is Magento’s weapon of choice).

HTTP2 is here so this technique will be probably deprecated in the future. You could still use bundling for reducing the number of requests for a specific page but I don’t think it will be worth of it.
Right before we start with “reverse” optimisation, we can use bundling to help us organise our assets and serve less files to the client which will (should) result in faster website.

One of our services is Technical audit which covers various tests on both Frontend and Backend part of the client’s store. Since i’m Frontend Developer, performance is my key point during analysis.

First thing I check is wether Javascript and CSS files are merged/minified/bundled (hello bundle). When I was Junior Developer, I was so happy/angry when I discovered someone didn’t turn these ON since I was thinking that technical level of Developers who worked on site was low and we can do a lot to improve site… and of course, I could get a “quick win” with turning merging/minifying ON.

Well, in theory that was great. Usually I was right about their expertise level but I was wrong about one thing – they didn’t “forgot” to turn these ON.

Explaining to the client that you would probably have to refactor 80% of the code to change that “simple option” is something I wouldn’t want to go through again.

We were doing Technical audit of the Magento 2 store and when I found out that Javascript and CSS files were not merged/minified/bundled I was in shock and first question that was going through my head was “shall I report this to the client?!”.

Strange question, I know. But it does make sense because if I report it, I’ll have to fix it.

Just kidding, of course this was included in our report and was first thing I changed when we took over the project.
How did it go? Well, do you write articles about stuff that work as expected?

Magento 2 Bundling

I must note that official docs do not give us a lot of information and there are only few discussions online about it.
Therefore, I may be wrong in some of my conclusions so feel free to correct me in comments 🙂

For start, let’s see 2 proper ways to load assets in Magento 2.
In this example, you can see how assets are loaded on two different Magento pages – Homepage and product page.

As you can see on example above, requireJS loaded different assets through different pages while all bundles were loaded regardless of wether they are needed or not.
With RequireJS, we can load specific JS modules on specific pages which means you will load only necessarily assets and reduce number of requests.

(If you wish to know more about how to load Javascript files with RequireJS, you can read this excelent article from my coleague Domagoj Potkoc. )

While RequireJS did help us with reducing number of requests through the page, we still have few JS files being loaded and “few” in Magento 2 means 40-50. We need a way to merge those assets into just few files. We need to create 5 files out of 50.
Files are being loaded asynchronously but still, if we could merge these files into just few, we could improve performance even more.
Bundling comes as a problem solver since it is used to merge modules and it dependencies into single file.
Bundling denies main benefit of using module loaders such as RequireJS since assets aren’t loaded asynchronously. Bundles are included with <script> tag, inside <head> section of the page.

So, why use it?

With bundling we could decide on where to load specific bundle and that’s the best part of it! For example, we want to put all checkout-related stuff into one bundle and load it only on checkout page!

Feeling happy?

Well, Magento folks didn’t implement RequireJS optimizer which is required for ordering and organising module load across different pages. You can exclude some scripts from bundle but you CAN’T decide on bundle content for a specific page.

So, why use it?

With Merging, you can only merge Javascript files that are NOT being loaded through RequireJS. If you wish to “merge” JS modules, you will have to use bundling.

You probably have so many questions in your head right now. So do I. And I’m still searching for the answers.

Here is a random Zen image, just to chill you down.

Bundling misses key features (imho) but you can still change few things in order to organize your bundles.

Bundle size and exclude list

In Vendor/Theme/etc/view.xml you can change bundle size and exclude some scripts from bundle.

Default size for bundle is 1MB.
Bundle size determines number of bundles that will be created. For example, if you have 4MB of script files and bundle size is set to 1MB, you will have 4 bundles created.

If number is too low, you will probably have 10 and more small bundles which will block each other during rendering so be careful with this.
Remember that bundles are not loaded asynchronously.

We can also exclude certain scripts from bundles. They will be loaded with RequireJS when needed.
Keep in mind that Luma and Blank themes have their own exclude lists and if you are not properly fallbacking and don’t have your own exclude list, bundles will be huge since all JS modules will be bundled, regardless of whether you need them or not.

<exclude> handle takes care of files that should be excluded from bundle. As far Magento 2 is concerned – since we can’t decide on bundle content for each page, at least we can exclude assets that will not be required through the whole site, therefore bundles will consist only files that are required everywhere. As you can see in above example (Luma theme exclude list), jQuery assets are probably required everywhere so i don’t understand idea behind excluding these from bundles. Probably Magento folks wanted to leave most important stuff under RequireJS control.

Activating bundling

After we have configured our bundle size and exclude list, it is time that we turn bundling on and enjoy great performance impact.

We can turn bundling on here: Stores > configuration > advanced >developer

After bundling is ON, clear cache and switch to production mode (bundling will not work in “Developer” mode). Static files will be deployed and you will see your bundles being loaded on the Frontend.

What about performance?

We did a lot in order to reduce number of requests through the site. But, there is one small problem with performance.

This is Homepage of the Luma theme.
Testing was done on Magento 2.2.0 “dev” version, with following setting in Dev console (Chrome):

Before turning bundling ON:

  • Number of JS requests : 137
  • Size: 2.0MB
  • Loadtime: 9.46sec

With bundling turned ON:

  • Number of JS requests : 8
  • Size: 4.2MB
  • Loadtime: 20.12sec

Take a look at size and load time?
We did reduce the number of JavaScript files being loaded, but the total filesize of generated bundles is larger than the total filesize of all non-bundled JavaScript files on the frontend.
Reason? With RequireJS you load only needed JS files on a specific page. Bundling merges all JS  assets and serves them on all pages.

Conclusion

I must say I am disappointed with bundling, especially with the fact that we don’t have RequireJS optimizer by default. Without it, whole idea behind bundling is missed.

Pros:

  • Bundles multiple files into single file

Cons:

  • negates benefits of using module loader
  • filesize of bundles is larger than all non-bundled javascript files size in total (per page)
  • you can’t define bundle content precisely
  • you can’t decide in which pages which bundle will be loaded

I don’t see any reason we should use bundling right now.
Bundling will make sense in the future if Magento folks create additional functionalities for us to use.
We need configuration file where we will be able to decide on :

  • number of bundles
  • bundle size
  • bundle content
  • which pages specific bundle will be loaded

Thanks for reading and i hope we can roll up some discussion about this topic in comments 🙂

The post Javascript Bundling in Magento 2 appeared first on Inchoo.

]]>
http://inchoo.net/magento-2/javascript-bundling-magento-2/feed/ 9
Experiences of running Magento 1 on PHP 7 http://inchoo.net/magento/experiences-running-magento-1-php-7/ http://inchoo.net/magento/experiences-running-magento-1-php-7/#comments Tue, 18 Apr 2017 11:29:50 +0000 http://inchoo.net/?p=29318 How time flies! It’s been almost a year and a half since we released Inchoo_PHP7 extension for Magento 1 (https://github.com/Inchoo/Inchoo_PHP7), and announced that in a blog post (http://inchoo.net/magento/its-alive/). We were just scratching our own itch – wanting to use all the performance benefits PHP 7 brought to run Magento faster. But, as the cover image...

The post Experiences of running Magento 1 on PHP 7 appeared first on Inchoo.

]]>
How time flies! It’s been almost a year and a half since we released Inchoo_PHP7 extension for Magento 1 (https://github.com/Inchoo/Inchoo_PHP7), and announced that in a blog post (http://inchoo.net/magento/its-alive/).

We were just scratching our own itch – wanting to use all the performance benefits PHP 7 brought to run Magento faster. But, as the cover image of that post inadvertently prophesied, we created a monster that escaped, and is continuing to terrorize the villagers to present day.

So, what happened in the meantime?

  • M1 is still going strong. M2 will take over eventually, but, in my humble personal opinion, that’s going be a very slow process.
  • On the other hand, PHP 7 is overtaking PHP 5 much quicker than previous versions used to replace their predecessors. (https://seld.be/notes/php-versions-stats-2016-2-edition). This is logical, because it really brings huge performance improvements, and it really is quite compatible, considering the major version number change.
  • Magento core became PHP 5.6 compatible in 1.9.3.x. Inchoo_PHP7 became PHP 7.1 compatible.
    • But, believe it or not, my humble personal opinion is that it’s better to run Magento on PHP 7.0 than 7.1 (https://github.com/Inchoo/Inchoo_PHP7/wiki/RunningOnPHP7.1).
      It’s really difficult to say, but I guess there are hundreds of M1 sites powered by Inchoo_PHP. Just Inchoo alone built from scratch or upgraded double figure of sites to PHP 7. Community seems to be going strong with it too, so I think I can say that it is quite tried and true by now.
  • With help from community, we found and fixed a lot of edge cases, and can say quite comfortably that we can make pretty much any M1 site work on PHP 7 without a problem.
    • And, in the last release, we even created a testing shell script, which can be very useful to find and fix potential problems.
    • Just keep in mind that this still is, and always will be, a developer-level extension. It can be “install and forget” if you are lucky, but, it would be good to have someone knowledgeable to set up, test everything and fix any issues. We had clients who came to us just for this, and we were always able to help them upgrade to PHP 7. And I don’t even want to say you need Inchoo to set it up. There are a number of developers and agencies in the Magento community that can help you out.

What’s ahead?

  • Looks like M1 core will continue it’s evolution. Going to Composer install, PHP 7, full page cache on CE, etc. – these are all things that clients are demanding and Magento experts are able to provide. Whether someone likes it or not, the whole ecosystem is large enough to be able to live and evolve on its own, directed by market pressures, and not someone’s will.
  • 3rd party extensions are the part of code we can’t fix with our extension. So, whether you are a 3rd party extension creator, a client, an integrator or anywhere else in community, please help spread the awareness that it’s good for everyone to be PHP 7 compatible.
  • PHP 7.2 will remove Mcrypt extension, and M1 core is quite dependant on it. There are a few workarounds we already tried out, but it’s not going to be pretty. For the time being, stick to PHP 7.0, and you won’t have problems.
  • Personally, I can’t wait for the moment when I’ll be able to use PHP 7 features when programming Magento, not just it’s performance. Stronger typing, for one, should bring less bugs and a more secure system. But that is still in far future from now, unfortunately.

 

TL;DR;

M1 runs (much) faster on PHP 7. Quite easy to set up due to a 3rd party module Inchoo_PHP7. MIT license. Great community support.

If you are having issues with performance of your Magento store, feel free to contact us to check technical state of your shop!

See you around!

The post Experiences of running Magento 1 on PHP 7 appeared first on Inchoo.

]]>
http://inchoo.net/magento/experiences-running-magento-1-php-7/feed/ 1
Making FedEx api show shipping estimate http://inchoo.net/magento/make-magento-fedex-api-show-shipping-estimate/ http://inchoo.net/magento/make-magento-fedex-api-show-shipping-estimate/#comments Mon, 10 Apr 2017 12:42:56 +0000 http://inchoo.net/?p=29265 There always comes the time when shopkeeper decides that he want’s to inform his customer of shipping estimate on checkout, so they could know approximately when they will get their goods. And for that, many shops today rely on API-s like ones from USPS or FedEx. Both of which are available for Magento. In this article...

The post Making FedEx api show shipping estimate appeared first on Inchoo.

]]>
There always comes the time when shopkeeper decides that he want’s to inform his customer of shipping estimate on checkout, so they could know approximately when they will get their goods. And for that, many shops today rely on API-s like ones from USPS or FedEx. Both of which are available for Magento.

In this article I will be showing you how to override FedEx carrier to return shipping estimate for given rates.

Overriding carrier

FedEx carrier works by sending request with given flags to FedEx server, who then, based on given flags, prepares response. After Magento receives response, it parses each rate as “Mage_Shipping_Model_Rate_Result” which he will later pass on to “Mage_Sales_Model_Quote_Address_Rate”. From which we will be able to access in template to show in frontend. For that, we will first override “Mage_Usa_Model_Shipping_Carrier_Fedex”.

Adding a flag for api

For FedEx API to know that it needs to return shipping estimate it needs to be given a “ReturnTransitAndCommit” flag. If we look into “Mage_Usa_Model_Shipping_Carrier_Fedex::_formRateRequest()” method, we will see that all it does is prepare flags into an array before it is sent to be parsed into request.

All we need to do here is rewrite original method and at the end of the array add our own flag.

Like in given example:

public function _formRateRequest($purpose)
{
   $ratesRequest = parent::_formRateRequest($purpose);
   $ratesRequest['ReturnTransitAndCommit'] = true ;//Here we are adding flag
   return $ratesRequest;
}

Storing the response data

After we receive data from api it will be parsed into stdClass,and in that class we are only interested in ‘RateReplyDetails’ array, which holds all our rates and their details, including their shipping estimates.

What we need to do here is pass our shipping estimate data into rate that will be passed on. For that we will be rewriting “Mage_Usa_Model_Shipping_Carrier_Fedex::_prepareRateResponse()” method.

protected function _prepareRateResponse($response)
{
   $costArr = array();
   $priceArr = array();
   // Array in which to store timestamp
   $deliveryTimeStamp = array();         //
   $errorTitle = 'Unable to retrieve tracking';
 
   if (is_object($response)) {
       if ($response->HighestSeverity == 'FAILURE' || $response->HighestSeverity == 'ERROR') {
           if (is_array($response->Notifications)) {
               $notification = array_pop($response->Notifications);
               $errorTitle = (string)$notification->Message;
           } else {
               $errorTitle = (string)$response->Notifications->Message;
           }
       } elseif (isset($response->RateReplyDetails)) {
           $allowedMethods = explode(",", $this->getConfigData('allowed_methods'));
 
           if (is_array($response->RateReplyDetails)) {
               foreach ($response->RateReplyDetails as $rate) {
                   $serviceName = (string)$rate->ServiceType;
                   if (in_array($serviceName, $allowedMethods)) {
                       $amount = $this->_getRateAmountOriginBased($rate);
                       $costArr[$serviceName]  = $amount;
                       $priceArr[$serviceName] = $this->getMethodPrice($amount, $serviceName);
                       //Store timestamp into prepared array
                       $deliveryTimeStamp[$serviceName] = $rate->DeliveryTimestamp; //
                   }
               }
               asort($priceArr);
           } else {
               $rate = $response->RateReplyDetails;
               $serviceName = (string)$rate->ServiceType;
               if (in_array($serviceName, $allowedMethods)) {
                   $amount = $this->_getRateAmountOriginBased($rate);
                   $costArr[$serviceName]  = $amount;
                   $priceArr[$serviceName] = $this->getMethodPrice($amount, $serviceName);
               }
           }
       }
   }
 
   $result = Mage::getModel('shipping/rate_result');
   if (empty($priceArr)) {
       $error = Mage::getModel('shipping/rate_result_error');
       $error->setCarrier($this->_code);
       $error->setCarrierTitle($this->getConfigData('title'));
       $error->setErrorMessage($errorTitle);
       $error->setErrorMessage($this->getConfigData('specificerrmsg'));
       $result->append($error);
   } else {
       foreach ($priceArr as $method=>$price) {
           $rate = Mage::getModel('shipping/rate_result_method');
           $rate->setCarrier($this->_code);
           $rate->setCarrierTitle($this->getConfigData('title'));
           $rate->setMethod($method);
           $rate->setMethodTitle($this->getCode('method', $method));
           $rate->setCost($costArr[$method]);
           $rate->setPrice($price);
	   //Store timestamp into rate
           $rate->setDeliveryTimeStamp($deliveryTimeStamp[$method]); //
           $result->append($rate);
       }
   }
   return $result;
}

Almost done..

Before we start celebrating we will notice that we are still not getting that data in fronted. That is because we stored that data into “Mage_Shipping_Model_Rate_Result_Method” which is is not same type of rate as in template, where we have “Mage_Sales_Model_Quote_Address_Rate”. So we will additionally rewrite method “Mage_Sales_Quote_Address_Rate::importShippingRate()” and just pass our data whether its present or not.

public function importShippingRate(Mage_Shipping_Model_Rate_Result_Abstract $rate)
{
   parent::importShippingRate($rate);
   if ($rate instanceof Mage_Shipping_Model_Rate_Result_Method) {
       $this->setDeliveryTimeStamp($rate->getDeliveryTimeStamp());
   }
   return $this;
}

And we are done. Wherever you call for rates (in my case it was checkout/onepage/shipping_method/available.phtml – onepages shipping methods) fedEx api will provide shipping estimate.

Thanks for being with me and happy coding.

The post Making FedEx api show shipping estimate appeared first on Inchoo.

]]>
http://inchoo.net/magento/make-magento-fedex-api-show-shipping-estimate/feed/ 1