Generally, changing the look and feel of the user experience in concrete5 is possible either through creating new pages in your theme or adding templates for the different blocks your page uses. Here are some good resources on creating templates:
Sometimes, you need to change a page type or single page that is included in a package or part of core. Other times, it just isn't enough to change how something looks: you need to have extra data fields, or you want to do different calculations on some data. In this case the best choice is to use concrete5's override feature.
Creating an override is a way to change one part of an add-on or the base CMS without modifying any files that are in the core folder or the add-on's folder. This way, it is possible to perform an update without losing your changes.
Possibly the best reason: if you look in your site's environment info on the dashboard, you will see a list of all overrides. This will let you know at a glance where you have changed things, which is much more helpful than having to dig through your site, remembering all your changes.
The basic override structure works like this: Copy any file in your [site root]/concrete/ or [site root]/packages/packaged_add_on/ folder --where packaged_add_on is the name of the package-- up to its equivalent path in your site root. Concrete5 will now use this file in favor of the one in its default location.
core functionality: public_html/concrete/single_pages/login.php --> public_html/single_pages/login.php
NOTE for concrete 5.6 and later: You will notice that if you copy any kind of model, library, etc. up, the contents of the class will be blank. You can add any new functions you need. The original version will be in concrete/core/(model, libraries, etc) if you need a reference for what you're extending.
See the following how-to for more information:
Overriding Core Files and Extending Core Classes in concrete5.6 and later
package functionality: public_html/packages/packaged_add_on/models/some/data/model.php --> public_html/models/some/data/model.php
That's it. Now you can upgrade both concrete5's core and any add-on and your modified code will still be in place. Keep in mind your modifications will not always be compatible with upgrades, so it is a good idea to set up a stage copy of your site, move your customizations out of the way temporarily, test the upgrade, then move them back in place to test before upgrading your live site.
One more note: concrete 5.6 and later also includes an "override cache" so you may not see the changes you are making. Like any other development task, it's a good idea to turn off all caching before you do any modifications.
If you are working with an older site, and simply copying up and modifying your helper's files in the site root doesn't work, try the following:
Helper files do not override like regular files. When you copy them up you need to rename the class with "Site" prefixed. So concrete/helpers/url.php you would copy up to helpers/url.php but then
class UrlHelper becomes
class SiteUrlHelper in the class declaration at the top of the file.
For a package, you remove the package's name from the class and replace that with
SiteThingHelper if your helper was originally in packages/my_packaged/helpers/thing.php.
To override a packaged tool the tool needs to be moved into folder with the add-on's name. So if you have a package in packages/add_on/ you will copy packages/add_on/tools/some_tool.php up to tools/some_tool.php and make your changes there.
You can not override a theme by copying the theme from its packaged directory up to the themes/ folder. If you modify a theme's description.txt you can install it as a new theme from your dashboard. Also, a page within your active theme will take precedence over one within your site's page_types/ folder. So for example, putting something in page_types/default.php will have no effect on your site.
Packaged elements do not override right now. The reason you would need to override an element would be the case where you might have a view.php that looks like this:
<div class="first_thing"> Loader::packageElement('some_element','add_on'); </div> <div class="second_thing"> Loader::packageElement('other_element','add_on'); </div>
Elements and package elements are both very useful because they let you reuse code, and if you change some data display in that one file you can reference it anywhere else and it will show up identically without rewriting anything. However, this is frustrating when you do not want to it to look the same in a certain place.
The bad option here is to create a template for your block, or override the page_type /single_page and actually paste all of the code from that element into your view at the line where the element is called. This will make your file big and messy which elements are meant to avoid.
Using the view above as an example, we are going to "override" 'some_element' by not using it anymore. Create override the page or create a template for the block and then change the line
Now your custom view will no longer be looking for the element inside the packages/ folder, which is what we want anyway. Everywhere else the add-on is used, it will be pulling in the default element.
Now copy packages/add_on/elements/some_element.php/ up to elements/my_some_element.php. That file will be used by your template / page override instead. Any edits you make here won't be reflected anywhere else.
This technique is useful for modifying complicated add-ons such as the eCommerce add-on without messing with any of its core functionality, allowing you to upgrade without any problems.
For more information on this technique, check out this example in the eCommerce documentation.