Installation:
composer require oro/customer-portal
Ensure your project extends OroPlatformBundle and OroCustomerBundle in config/bundles.php.
First Use Case:
CustomerUser entity.
// src/Entity/CustomerUser.php
use Oro\Bundle\UserBundle\Entity\User;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity]
class CustomerUser extends User
{
#[ORM\Column(type: 'string', length: 255, nullable: true)]
private ?string $customField = null;
// Getters/Setters...
}
templates/OroCustomerBundle/registration/register.html.twig.Key Configuration:
config/routes/oro_customer_portal.yaml:
oro_customer_portal:
resource: "@OroCustomerBundle/Resources/config/routing.yml"
prefix: /
CustomerUserRepository and CustomerRepository for database interactions.
$customer = $customerRepository->findOneBy(['email' => 'user@example.com']);
$customerUser = $customer->getUser();
CustomerAddress and CustomerUserAddress entities with validation:
$address = new CustomerAddress();
$address->setFirstName('John');
$address->setValidatedAt(new \DateTime()); // Auto-populated via validation
$customer->addAddress($address);
$customerRepository->save($customer);
templates/OroFrontendBundle/layouts/default/layout.html.twig.
{# Add custom header #}
{% block oro_frontend_header %}
{{ parent() }}
<div class="custom-header">{{ app.user }}</div>
{% endblock %}
config/packages/oro_frontend.yaml:
oro_frontend:
theme_configuration:
product_page_template: 'custom_template'
frontend_api_secured firewall (renamed from frontend_api_wsse_secured in v6.1).
# config/packages/security.yaml
firewalls:
frontend_api_secured:
pattern: ^/api/frontend
wsse: true
oro_frontend:
frontend_api:
use_absolute_urls_for_api: true
AddressValidationClientInterface for FedEx/UPS:
class FedExAddressValidator implements AddressValidationClientInterface
{
public function findSuggestions(string $address): array
{
// Call FedEx API
return $suggestions;
}
}
Register the service:
services:
oro_address_validation.fedex:
class: App\Service\FedExAddressValidator
tags:
- { name: oro_address_validation.channel }
FrontendCustomerTypedAddressType in forms:
$builder->add('shippingAddress', FrontendCustomerTypedAddressType::class, [
'label' => 'Shipping Address',
'validation_groups' => ['Default', 'oro_address_validation'],
]);
base_storefront template for custom emails:
{# templates/layouts/custom_theme/email-templates/customer_user_welcome_email.html.twig #}
{% extends 'OroCustomerBundle:Emails:base_storefront.html.twig' %}
{% block subject %}{{ parent() }} - Welcome to Our Store!{% endblock %}
oro_customer.user.register for post-registration actions:
$eventDispatcher->addListener('oro_customer.user.register', function (CustomerUserRegisterEvent $event) {
$user = $event->getUser();
// Send welcome email or log activity
});
CurrentCustomerUserViewList for filtered grids:
$grid->setViewList('current_customer_user_view');
config/packages/oro_frontend.yaml:
oro_frontend:
theme_configuration:
svg_icons_support: true
sticky-element-view for persistent UI elements:
require(['orofrontend/js/app/views/sticky-element-view'], function (StickyElementView) {
new StickyElementView('.sticky-element', {
offset: 100
});
});
fa-icon mixin with SVG icons (e.g., <svg class="icon">...</svg>).oro/frontend-dialog-widget to oro/dialog-widget in custom templates.sticky-element-view instead.use_absolute_urls_for_api is set to true for API consistency.oro_customer.validate_shipping_addresses__my_account) before enabling validation.oro_form_csrf_token Twig function:
<input type="hidden" name="_csrf_token" value="{{ oro_form_csrf_token('register') }}">
theme.yml in config/packages/oro_frontend.yaml for global theme settings:
oro_frontend:
theme_configuration:
product_page_template: 'custom_template'
templates/layouts/{theme}/email-templates/ for inheritance.php bin/console oro:asset:install --symlink
frontend_api.use_absolute_urls_for_api for URL issues in API responses.AddressValidationClientInterface implementations are tagged with oro_address_validation.channel.CustomerUser or CustomerAddress:
#[ORM\Entity]
class CustomCustomerUser extends CustomerUser
{
#[ORM\Column(type: 'string', nullable: true)]
private ?string $loyaltyTier;
}
class CustomContentProvider implements ContentProviderInterface
{
public function getName(): string
{
return 'custom_provider';
}
public function getConfig(): array
{
return ['label' => 'Custom Content'];
}
}
services:
app.custom_content_provider:
class: App\ContentProvider\CustomContentProvider
tags:
- { name: oro_frontend.content_provider }
{# templates/layouts/custom_theme/email-templates/customer_user_reset_password.html.twig #}
{% extends 'OroCustomerBundle:Emails:customer_user_reset_password.html.twig' %}
{% block content %}
{{ parent() }}
<p>Custom reset instructions here.</p>
{% endblock %}
$grid->addAction(
new FrontendResetCollectionAction(
'reset',
['icon' => 'undo']
)
);
theme.yml:
grid_render_parameters:
themeOptions:
actionOptions:
resetAction:
hiddenIfIsNotResettable: true
AddressValidationClientInterface for custom providers:
How can I help you explore Laravel packages today?