Silverstripe 4 - Add many_many relationship by default - silverstripe-4

Is it possible to have a many_many relationship added by default?
I am working with the subsites module where each site has a Blog, but we want the ability to tag BlogPosts so they can appear on any of the other subsites:
subsite 1
subsite 2
subsite 3
I have this setup as an extension to BlogPost:
private static $many_many = [
'Subsites' => Subsite::class
];
$fields->addFieldToTab('Root.PostOptions',
TagField::create('Subsites','Show on other sites',Subsite::get(),$this->owner->Subsites())
->setShouldLazyLoad(false)
->setCanCreate(false)
);
How would I add the current subsite as a default relation on creation of the BlogPost, so that each BlogPost under Subsite2 has a 'Subsite2' tag by default, ie using
Subsite::get_by_id(SubsiteState::singleton()->getSubsiteId())
If that doesn't make sense I'll try and explain more :)

You could try adding the relations in your BlogPost's onBeforeWrite function, this would work by simply calling $this->Subsites()->add($subsiteObject). To make sure that the Object was really created and not only updated, you can check for the objects id. If it has none yet, the object was newly created.

Related

Silverstripe 4 admin add new FormField template not found error

I have tried to add a new FormField to silverstripe 4 admin called "AdminButtonGroupField". But it gives me a error like this,
[User Warning] None of the following templates could be found: AdminButtonGroupField in themes "Array ( [0] => silverstripe/admin:cms-forms [1] => $default ) "
I have tried to put template different places but did not worked. Where is the exact place I can put this template?
Thanks.
You can put your template in app/templates/AdminButtonGroupField.ss.
By putting templates in app/templates they will be available for the whole SilverStripe application to use, regardless of whether you're in the CMS or the frontend.
You could define an "admin theme" and enable it with LeftAndMain.admin_themes config if you don't want the template to be available to be used on the frontend. This probably isn't necessary for you.
Note that I've assumed here that AdminButtonGroupField has no namespace, and that you aren't customising its template name when you render the field. If you provide some (reproducible) sample code that would clear this up.

SilverStripe field-level Page editing permissions

I need to implement field-level permissions in a Page model, in a SilverStripe 3.2 website.
Let's imagine I have an ArticlePage.php model. It has the usual fields like $MenuTitle and $Content, and I've added other properties like $Subtitle and $Author.
I can protect the whole model by using providePermissions() and the associated canEdit() methods, but I need to protect individual fields / page properties.
What I need to do is:
Admins should be able to edit all fields
Users in another permissions group should only be able to edit and save $Subtitle
Is this possible in SilverStripe 3.2? Is there a SilverStripe way of doing it?
If not, is there a way I can Identify the user group of the current user and then perhaps conditionally show the $field->addFieldToTab() code? Is it possible to stop the user saving a field by posting the data maliciously, perhaps by adding the missing fields via inspector?
Thanks in advance.
So here's my own answer. This post was helpful: https://www.silverstripe.org/community/forums/customising-the-cms/show/11693
You can conditionally show CMS fields and tabs using code like the post demonstrates:
public function getCMSFields()
if(!Permission::check('PERMISSION_LABEL'){
$fields->removeFieldFromTab("Root.Main","MenuTitle");
$fields->removeByName('BannerImages');
// etc...
}
// etc...
}
Having defined the permission:
public function providePermissions()
{
return array(
'PERMISSION_LABEL' => 'Can edit some fields',
);
}
My concern with this approach was that a user could still create a form field on the page using inspector or JS and submit values for fields they should not be able to see.
Having tested this it appears that field values are not saved if they are not listed on the page, but are sent with the POST data. Although I'd love to know if a SilverStripe expert could confirm that.

Change Wordpress User Roles with access to Private Pages

I have a user role called Student and would like to allow them access to Private pages (currently only admin and editor roles can do this). I would like to create a function to do so. I found a post that said to add this to the functions.php in my child theme:
// Allow Students to see Private posts and pages
$subRole = get_role( 'Student' );
$subRole->add_cap( 'read_private_posts' );
$subRole->add_cap( 'read_private_pages' );
But it doesn't seem to do anything. Is there a way to change the ability to access private pages?
Also above it says 'read_private_pages' I want to be sure that they can submit the form on that page as well (not just read the page).
Do you can use plugins? If yes, try the plugin Capability Manager Enhanced.
This plugin is a way to manage WordPress role definitions.
More easy that edit direct in the code.

How to create dynamic router for catalog items

I'm trying to work with Kunstmaan bundles for Symfony2 and have one issue.
Currently I'm trying to create catalog bundle, everything seems okey, but I don't want to create menu item for each product. It would be great to access products dynamicaly by item slug-title in /en/catalog/* menu item. How is it possible?
We are experiencing the same problem ... we are trying to solve this by creating catalog items which are also menu items but have null as parent so that they don't show up in the tree. By doing this you still have the versioning system and everything but it doesn't slow down your tree when you have many catalog items. You can list these catalog items somewhere in an admin list using the AdminListBundle (https://github.com/Kunstmaan/KunstmaanAdminListBundle)
To link these catalog items to a certain overview page we are using the chainrouter (https://github.com/Kunstmaan/KunstmaanNodeBundle/blob/master/Resources/doc/NodeBundle.md). For now we don't have a clear example of this but maybe this can get you started? We are trying to make using the chainrouter easier, but it's still under construction: https://github.com/Kunstmaan/KunstmaanNodeBundle/pull/38/files
The fastest/easiest way would to make your product as a page which can be defined as a child for your Catalog. The KunstmaanNodeBundle will take care of the slugs.
In your Catalog class (I assume it extends AbstractPage) override the getPossibleChildTypes method :
public function getPossibleChildTypes()
{
return array (
array(
'name' => 'Product',
'class'=> "Acme\CatalogBundle\Entity\Product"
)
);
}
This way you can just create products as subpages under your catalog page. Then you just need to get the children of your catalog in the twig template of your catalog page.
The drawback is, is that each product is a page on its own (with versioning) instead of being a simple Entity.

Hide other domains' menus from node edit form on a Drupal site using domain access

I'm in the process of making some improvements to a live Drupal site that's using the Domain Access module to run a number of microsites. I'm trying to find a way of restricting the menus a user can post content to from the node edit screen. A user on one of the domains should only be able to post content to menus associated with that domain.
Is there a simple way of achieving this? I'm guessing there are some hooks I could use, but so far I have been unable to identify them. I'd prefer not to have to install further modules to achieve this and to be able to add some code to the current site to alter the forms. The site is struggling with the large number of modules we've had to install on it already.
According to the readme for the module, you need to set some specific permissions in user management:
To enable this feature, you should grant the 'edit domain nodes' and
(optionally) the 'delete domain nodes' permission to some roles. Then assign
individual users accounts to specific domains to assign them as Domain Editors.
From my experience many moons ago with the module, you can check the global $user object and figure out what domains the user should have access to. You can then use a form alter to remove any options from the select box that you don't want them seeing. As always with Drupal though, it's better to let someone else write the code - so if the Domain module provides this functionality, use it!
Here is some updated code for Drupal 7:
/**
* Implements hook_form_FORM_ID_alter().
*/
function MYMODULE_form_page_node_form_alter(&$form, &$form_state) {
global $_domain;
if (isset($_domain['domain_id'])) { // only display domain's primary links
$menus[domain_conf_variable_get($_domain['domain_id'], 'menu_main_links_source')] = $_domain['sitename'].' Main menu';
}
if (isset($menus)) {
$options = menu_parent_options($menus, $form['#node']->type);
$form['menu']['link']['parent']['#options'] = $options;
}
}
Eventually found a way of fixing this for the particular project I have been working on: in module_form_alter I've added the following:-
global $_domain;
if (isset($_domain['domain_id'])) { // only display domain's primary links
$menus[domain_conf_variable_get($_domain['domain_id']
,'menu_primary_links_source')] = $_domain['sitename'].' Primary links';
}
if ( isset($menus) ) {
$options = menu_parent_options($menus, $form['menu']['#item']);
$form['menu']['parent']['#options'] = $options;
}
This restricts the menu options to just the current domain's primary links menu which is just what we wanted.
Thanks to Fabian who pointed me in the right direction earlier.

Resources