I have a Drupal 8.7 site and the Drupal Commerce 2.14 module
In the template of my store to display the field field_professionnel_cgv I use this code TWIG :
{{ store.field_professionnel_cgv }}
How to display this field from the template of my products.
You could add to your module mymodule_preprocess_commerce_product() hook function and inside that function get store entity and set twig variable with data from it so it will be available inside your template.
Check how original function looks like at:
/modules/contrib/commerce/modules/product/commerce_product.module
function template_preprocess_commerce_product(array &$variables) {
/** #var Drupal\commerce_product\Entity\ProductInterface $product */
$product = $variables['elements']['#commerce_product'];
$variables['product_entity'] = $product;
$variables['product_url'] = $product->isNew() ? '' : $product->toUrl();
$variables['product'] = [];
foreach (Element::children($variables['elements']) as $key) {
$variables['product'][$key] = $variables['elements'][$key];
}
}
So you'll have to fetch store object and assign twig variable like it's done here.
Related
I would like to assign a template on my PageLayoutView preview in order to avoid writing HTML on my PHP files and better maintain it. How can i achieve that using TYPO3 10?
I would like to use it for example on the textmedia content element and add the subheader in.
In order to achieve that, you will have to use the Standalone view. I would write a function which i can call it whenever i want to use it. Normally i would include the function on a Helper Class but for the sake of this answer i will put it on the same class. So lets say we have the textmedia content element and we want to add fields on the backend Preview.
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Fluid\View\StandaloneView;
/**
* Contains a preview rendering for the page module of CType="textmedia"
*/
class TextMediaPreviewRenderer implements PageLayoutViewDrawItemHookInterface
{
/**
* Preprocesses the preview rendering of a content element of type "textmedia"
*
* #param \TYPO3\CMS\Backend\View\PageLayoutView $parentObject Calling parent object
* #param bool $drawItem Whether to draw the item using the default functionality
* #param string $headerContent Header content
* #param string $subheaderContent Subheader content
* #param string $itemContent Item content
* #param array $row Record row of tt_content
*/
public function preProcess(
PageLayoutView &$parentObject,
&$drawItem,
&$headerContent,
&$subheaderContent,
&$itemContent,
array &$row
) {
if ($row['CType'] === 'textmedia') {
$standaloneView = $this->getStandAloneConfig();
/*Disable TYPO3's default backend view configuration */
$drawItem = false;
/*Assign all the results to the backend */
$standaloneView->assignMultiple([
'title' => $parentObject->CType_labels[$row['CType']],
'type' => $row['CType'],
'content' => $row,
]);
$itemContent .= $standaloneView->render();
}
}
public function getStandAloneConfig()
{
$standaloneView = GeneralUtility::makeInstance(StandaloneView::class);
$standaloneView->setLayoutRootPaths([10,'EXT:your_extension/Resources/Private/Backend/Layouts/']);
$standaloneView->setTemplateRootPaths([10,'EXT:your_extension/Resources/Private/Backend/Templates/']);
$standaloneView->setPartialRootPaths([10,'EXT:your_extension/Resources/Private/Backend/Partials/']);
$standaloneView->setFormat('html');
$standaloneView->setTemplate('PageLayoutView.html');
return $standaloneView;
}
What is happening is the following
First, we get the StandAlone configuration. In this configuration (getStandAloneConfig()) we set the path to where our templates, partials and layouts are. Then we assign the type (html) and then the name of the template where our preview is going to be built on (PageLayoutView.html).
After that we reset everything that TYPO3 writes on the Preview ($drawItem = false;) so we can write our own.
Last and not least we assign the variables which we are going to use on the HTML file.
Under your_extension/Resources/Private/Backend/Templates/PageLayoutView.html
<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers" data-namespace-typo3-fluid="true">
<f:switch expression="{type}">
<f:case value="textmedia">
<f:render partial="Textmedia" arguments="{_all}"/>
</f:case>
<f:case value="text">
<f:render partial="Text" arguments="{_all}"/>
</f:case>
<f:defaultCase>
<f:render partial="Header" arguments="{_all}"/>
</f:defaultCase>
</f:switch>
</html>
I personally use the PageLayoutView.html as a controller which decides, which partial should be rendered. So i assign the variable {type} and i render the partial based on its value.
Under your_extension/Resources/Private/Backend/Partials/Textmedia.html
<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers" data-namespace-typo3-fluid="true">
<p><strong class="element_title">{title}</strong></p>
<table class="element_table">
<tbody>
<tr>
<th>Subheader</th>
<td>{content.subheader}</td>
</tr>
</tbody>
</table>
</html>
Now you can look what is inside the {content} variable and render it on your HTML.
If you want to style your Preview you can do the following: Under your ext_tables.php add the following line:
$GLOBALS['TBE_STYLES']['stylesheet'] = 'EXT:your_extension/Resources/Public/Css/Backend/page-layout-view.css';
There's a pretty easy way. Just set an alternative path for the preview templates.
\TYPO3\CMS\Backend\View\PageLayoutView::tt_content_drawItem():
// If the previous hook did not render something,
// then check if a Fluid-based preview template was defined for this CType
// and render it via Fluid. Possible option:
// mod.web_layout.tt_content.preview.media = EXT:site_mysite/Resources/Private/Templates/Preview/Media.html
if ($drawItem) {
$fluidPreview = $this->renderContentElementPreviewFromFluidTemplate($row);
if ($fluidPreview !== null) {
$out .= $fluidPreview;
$drawItem = false;
}
}
Laravel Scout: Is there a way that I search in only a specific field?
At the moment this line is working fine:
$es = Element::search($q)->get();
But it searches title, shortdescription and description fields. I need it to only search in title field.
You just need to change your toSearchableArray method from your model by adding the following code:
/**
* Get the indexable data array for the model.
*
* #return array
*/
public function toSearchableArray()
{
$array = $this->only('title', 'description');
$related = $this->user->only('name', 'email');
// Customize array...
return array_merge($array, $related);
}
Then call php artisan scout:import "App\YourModel" to reindex the new records.
Note:
$this->only('title', 'description') will search only for its title and description fields
$this->user->only('name', 'email') will also search for its name and email from a related Model
So you can retrieve the related data by adding ->load('user') in your search method like the following code:
public function search(Request $request)
{
$query = $request->get('q');
return Task::search($query)->get()->load('user');
}
UPDATE
If you're trying to retrieve the data using ->paginate() method, you must need to load the relations separately:
...
$tasks = Task::search($query)->paginate($request->get('per_page'));
$tasks->load('user');
return $tasks;
Enjoy!
for meilisearch this worked
Element::search('test',
function ($searchEngine, string $query, array $options) use ($filter) {
$searchEngine->resetSearchableAttributes();
$searchEngine->updateSearchableAttributes(['field_name']);
return $searchEngine->search($query, $options);
}
)
You can do that by adding a callback function to the scout builder instance,
Person::search($searchString)->query(function($query) {
$query->select(['title']);
})->get();
You can do that by adding a callback function to the scout builder instance,
Person::search($searchString)->query(function($query) {
$query->addSelect(['title']);
})->get();
Worked on laravel 7
If you want standard query result, but search only in a specific column (field), you can try this solution:
Element::search($query)->rule(function($builder) {
return [
'must' => [
'match' => [
'some_column_name' => $builder->query
]
]
];
});
Tested on Laravel 6, but I think it will work on later versions to...
Good Afternoon,
I cannot figure out how to remove the key board divider key after my favicon in the browser tab. Please see the image below.
Note: I am developing with Drupal 8.
Drupal construct, by default, the page title such: [Entity-Title] | [Site Name].
It's seems you don't have a title on this page.
It depends which page(s) you try to change. For an Entity, just set the title field would fix your probleme.
Titles on routes now can be set on various ways, depending on your use case.
Previously (drupal-7) just drupal_set_title() was called in whatever place. The following use cases exist:
Override title tag
You may override the title tag in the head of your HTML document using the HOOK_preprocess_html.
function mymodule_preprocess_html(&$variables) {
// Change the Title
$variables['head_title']['title'] = 'Title';
// Change the Suffix (sitename)
$variables['head_title']['name'] = 'Suffix';
}
Static title
For static titles you set a '_title' on the routing definition:
block.admin_add:
path: '/admin/structure/block/add/{plugin_id}/{theme}'
defaults:
_controller: '\Drupal\block\Controller\BlockAddController::blockAddConfigureForm'
_title: 'Configure block'
requirements:
_permission: 'administer blocks'
Dynamic title
If you write a controller and you need a dynamic title, for example depending on the site configuration, use _title_callback in the route defaults.
mymodule.test:
path: '/mymodule/test'
defaults:
_controller: '\Drupal\mymodule\Controller\TestController::getContent'
_title_callback: '\Drupal\mymodule\Controller\TestController::getTitle'
<?php
class TestController {
/**
* Returns a page title.
*/
public function getTitle() {
// The \Drupal::config() should be injected instead of using static call.
return 'Foo: ' . \Drupal::config()->get('system.site')->get('name');
}
/**
* Returns a page render array.
*/
public function getContent() {
$build = array();
$build['#markup'] = 'Hello Drupal';
return $build;
}
}
Final title override
If you write a controller and you need to override the title from the route, you can return #title in the render array. This should generally to be avoided, since the title for the page when fully rendered could be different from the title in other contexts (like in the breadcrumb).
<?php
class TestController {
/**
* Renders a page with a title.
*
* #return array
* A render array as expected by drupal_render()
*/
public function getContentWithTitle() {
$build = array();
$build['#markup'] = 'Hello Drupal';
// The \Drupal::config() should be injected instead of using static call.
$build['#title'] = 'Foo: ' . Drupal::config()->get('system.site')->get('name');
return $build;
}
}
drupal_set_title() in Drupal 8
As you can see here that drupal_set_title() is deprecated in Drupal 8.
$request = \Drupal::request();
if ($route = $request->attributes->get(\Symfony\Cmf\Component\Routing\RouteObjectInterface::ROUTE_OBJECT)) {
$route->setDefault('_title', 'New Title');
}
I am working on Xcart-5 website customization. And I created my own module and doing work on that. I just created some Global Attributes (" As a Plain text ") field and assign these attributes to some product. Now I want to access these fields value in programming in the product details page for assigning some other value programatically at run time.
How can I achieve this task. Kindly provide me the solution .
In your module you should decorate the \XLite\Model\Attribute class and extend the getAttributeValue() method there.
For instance, if I use a module with developer ID Tony and module ID AttributesDemo, then I would need to create the XCartDirectory/classes/XLite/Module/Tony/AttributesDemo/Model/Attribute.php file with the following content:
<?php
// vim: set ts=4 sw=4 sts=4 et:
namespace XLite\Module\Tony\AttributesDemo\Model;
/**
* Attribute
* #MappedSuperClass
*/
abstract class Attribute extends \XLite\Model\AttributeAbstract implements \XLite\Base\IDecorator
{
public function getAttributeValue(\XLite\Model\Product $product, $asString = false)
{
$result = parent::getAttributeValue($product, $asString);
if (!$asString) {
foreach ($result as $obj) {
if ($obj->asString() == 'Mac') {
$obj->getAttributeOption()->setName('Windows');
}
}
}
return $result;
}
}
Such implementation will change Mac values to Windows ones in all attributes.
I need to put a search box within a list of objects as a result of a typical indexSuccess action in Symfony. The goal is simple: filter the list according to a criteria.
I've been reading the Zend Lucene approach in Jobeet tutorial, but it seems like using a sledge-hammer to crack a nut (at least for my requirements).
I'm more interested in the auto-generated admin filter forms but I don't know how to implement it in a frontend.
I could simply pass the search box content to the action and build a custom query, but is there any better way to do this?
EDIT
I forgot to mention that I would like to have a single generic input field instead of an input field for each model attribute.
Thanks!
I'm using this solution, instead of integrating Zend Lucene I manage to use the autogenerated Symonfy's filters. This is the way i'm doing it:
//module/actions.class.php
public function executeIndex(sfWebRequest $request)
{
//set the form filter
$this->searchForm = new EmployeeFormFilter();
//bind it empty to fetch all data
$this->searchForm->bind(array());
//fetch all
$this->employees = $this->searchForm->getQuery()->execute();
...
}
I made a search action which does the search
public function executeSearch(sfWebRequest $request)
{
//create filter
$this->searchForm = new EmployeeFormFilter();
//bind parameter
$fields = $request->getParameter($this->searchForm->getName());
//bind
$this->searchForm->bind($fields);
//set paginator
$this->employees = $this->searchForm->getQuery()->execute();
...
//template
$this->setTemplate("index");
}
It's important that the search form goes to mymodule/search action.
Actually, i'm also using the sfDoctrinePager for paginate setting directly the query that the form generate to get results properly paginated.
If you want to add more fields to the search form check this :)
I finally made a custom form using the default MyModuleForm generated by Symfony
public function executeIndex {
...
// Add a form to filter results
$this->form = new MyModuleForm();
}
but displaying only a custom field:
<div id="search_box">
<input type="text" name="criteria" id="search_box_criteria" value="Search..." />
<?php echo link_to('Search', '#my_module_search?criteria=') ?>
</div>
Then I created a route named #my_module_search linked to the index action:
my_module_search:
url: my_module/search/:criteria
param: { module: my_module, action: index }
requirements: { criteria: .* } # Terms are optional, show all by default
With Javascript (jQuery in this case) I append the text entered to the criteria parameter in the href attribute of the link:
$('#search_box a').click(function(){
$(this).attr('href', $(this).attr('href') + $(this).prev().val());
});
And finally, back to the executeIndex action, I detect if text was entered and add custom filters to the DoctrineQuery object:
public function executeIndex {
...
// Deal with search criteria
if ( $text = $request->getParameter('criteria') ) {
$query = $this->pager->getQuery()
->where("MyTable.name LIKE ?", "%$text%")
->orWhere("MyTable.remarks LIKE ?", "%$text%")
...;
}
$this->pager->setQuery($query);
...
// Add a form to filter results
$this->form = new MyModuleForm();
}
Actually, the code is more complex, because I wrote some partials and some methods in parent classes to reuse code. But this is the best I can came up with.