how to modify function of contributed module in drupal? - drupal

I have the reqirement to modify simplenews_build_newsletter_mail() function in simplenews module but, we don't modify directly contributed module function.
can someone gives me ways to modify simplenews_build_newsletter_mail() function ?

Most of the data moving around in drupal can be altered through 'hooks'
the function you want to alter simplenews_build_newsletter_mail(&$message, SimplenewsSourceInterface $source) is being called from simplenews_mail($key, &$message, $params) which is simplenews implementation for hook_mail
fortunately all the output for hook_mail can be altered though hook_mail_alter().
What you need to do is to create your own module, then implement hook_mail_alter() in your new custom module. find your target emails, change them.
you will need to identify which mail you would like to alter using the mail $id, The id will be {$module}_{$key} where the module is the drupal module generated this email (simplenews) in your case.
find more information here https://api.drupal.org/api/drupal/modules%21system%21system.api.php/function/hook_mail_alter/7
/**
* Implements hook_mail_alter().
*/
function mymodule_mail_alter(&$message) {
switch ($message['id']) {
case 'simplenews_node':
case 'simplenews_test':
// Do your magic.
break;
}
}

Related

Silverstripe 4 use additional custom HTMLEditorField

In Silverstripe 4 how can we use different HTMLEditor configs ?
I'd like to have two different HTMLEditorFields in the same environment.
One with all functionality and all Buttons.
And another one (MyCustomHTMLEditorField) with reduced functionality and e.g. only 3 buttons (underline, italic, bold).
How do you use ::set_active ?
How to extend HTMLEditorConfig ?
Yes, i've read the documentation but How can this be archived?
There can be multiple configs, which should always be created / accessed using HtmlEditorConfig::get(). You can then set the currently active config using set_active().
Can you provide an Example?
Any help welcome.
The documentation at https://docs.silverstripe.org/en/4/developer_guides/forms/field_types/htmleditorfield/ goes to length about how to define and use HTMLEditorConfig sets.
HTMLEditorConfig::set_active() is really for if you're intending to set an editor for use in multiple HTMLEditorFields in a given form or admin section, or to override the config for all admin sections. It more-or-less sets the 'default' config. That won't be so useful in your case, as it sounds like you want to set a configuration for a given HTMLEditorField.
Setting configuration
This is detailed in the documentation at https://docs.silverstripe.org/en/4/developer_guides/forms/field_types/htmleditorfield/#adding-and-removing-capabilities
Usually this is done in your _config.php (or in some separate class which then gets called from _config.php - unless you only need it in a very specific section, in which case you could set this up or call your special class from that admin's init() method).
The examples in the documentation here modify the default ('cms') config. This is useful if you want to modify the configuration that is used by default. So do this for your config that you've referred to as having "all functionality and all Buttons".
Setting up a new HTMLEditorConfig
Calling HTMLEditorConfig::get($configName) will get the existing config based on the name you pass it - but if there is no existing config, it will create a new one. So you could call $customConfig = HTMLEditorConfig::get('some-custom-config') - now your $customConfig variable holds a new configuration that you can configure however you so choose (insert buttons, enable plugins, define whitelisted elements, etc).
Using configuration
This is discussed in the documentation here: https://docs.silverstripe.org/en/4/developer_guides/forms/field_types/htmleditorfield/#specify-which-configuration-to-use
I've already mentioned the set_active() - if you're going to set up multiple HTMLEditorFields in a form for example you can use that in your getCMSFields() method:
public function getCMSFields()
{
$fields = parent::getCMSFields();
$fields->addFieldToTab('Root.Main', HMLEditorField::create('Content')); // This will use the default 'cms' config.
HTMLEditorConfig::set_active('some-custom-config');
$fields->addFieldToTab('Root.Main', HMLEditorField::create('OtherContent')); // This will use the 'some-custom-config' config that you defined.
// Don't forget to reset to the default.
HTMLEditorConfig::set_active('cms');
return $fields;
}
You can also, as explained in the docs, set your config by name for a given HTMLEditorField which is preferred if you're using a non-default for one one field.
public function getCMSFields()
{
$fields = parent::getCMSFields();
$fields->addFieldToTab('Root.Main', HMLEditorField::create('Content')); // This will use the default 'cms' config.
$fields->addFieldToTab('Root.Main', HMLEditorField::create('OtherContent')->setEditorConfig('some-custom-config')); // This will use the 'some-custom-config' config that you defined.
return $fields;
}
Note that the syntax I used here is slightly different to the docs - this allows you to avoid passing in the second and third constructor arguments that you're not changing from the defaults. Keeps things a little tidier.
Disclaimer: All of the code above was written from memory, so it may need some tweaks to work correctly.

Symfony2. Enum: pls explain "You can register this type with Type::addType('enumvisibility', 'MyProject\DBAL\EnumVisibilityType')"

I am trying to implemt the following instruction, as to have Enum type somehow
Shame on me, but I have not an idea on how/where I go to "register [the defined] type with Type::addType('<enummyfield>', 'MyProject\DBAL\<EnumMyfield>Type')".
EDIT Answer 1 helps. It seems I need too:
to move definition of EnumMyfield to directory MyBundle\Doctrine\DBAL\Types\Type (with appropriate use declarations)
to update app\config\config.yml with lines
types:
<myfield>: <mybundle>\Doctrine\DBAL\Types\Type\<EnumMyfield>Type
since I wish to have a Select on the Form side, to define:
->add('MyField','choice', array('label'=>'Select please', 'choices'=>array('A'=>'A','B'=>'B')), within my MyentityType\buildForm().
With respect to the last point, if I just use choices'=>array('A','B'), values for the select options are rendered as numbers (0,1), and I run into an error (I am not sure why)
your comments/advises are welcome
Just a recap, useful for others (maybe); I will highlight were you're blocked
Create a directory Doctrine\DBAL\Types
Define your new DBAL type there like shown into your link
Register it into your bundle main file (*) <--- this is what you're missing
Use it into entity definition
(*) You have a file inside your bundle named YourBundleNameBundle.php this file is used to register the bundle. If you want to register your custom type also, put inside this bundle the string Type::addType('enum', 'MyProject\DBAL\EnumType')".
So, something like
public function boot()
{
if (false === Type:hasType('enum')) {
$em = $this->container->get('doctrine.orm.entity_manager');
Type::addType('enum', 'Path\To\Bundle\Doctrine\DBAL\Types\EnumType');
$em->getConnection()->getDatabasePlatform()->registerDoctrineTypeMapping('enum','enum');
}
}
Don't forget the use statement
use Doctrine\DBAL\Types\Type;
at the top of the file

Drupal 7 preprocess_views not working

I have the following code in my Drupal 7 template.php file:
function mytheme_preprocess_views_view__videos__videos(&$vars) {
drupal_add_css(drupal_get_path('theme', 'mytheme') . "/css/qwembed-jquery-1.0.css");
drupal_add_js(drupal_get_path('theme', 'mytheme').'/js/jquery.swfobject.1-1-1.min.js', array('type' => 'file', 'scope' => 'footer'));
drupal_add_js(drupal_get_path('theme', 'mytheme').'/js/qwembed-jquery-1.0.js', array('type' => 'file', 'scope' => 'footer'));
}
I need to load these css and js file only when this view is displayed.
the view display name is: Videos
the view Machine Name is: videos
and the override files are:
views-view--videos--videos.tpl.php
views-view-unformatted--videos--videos.tpl.php
views-view-fields--videos--videos.tpl.php
any ideas why this is not working?
The problem is likely that you try to implement a preprocess function based on the same naming pattern as used for template overrides. But preprocess functions are a bit different in that by default, they can only be implemented based on the name of the 'base' template, and do not have the same mechanism for 'specific' versions based on template suggestions. See my answer to a more generic question for details.
So you'd need to fall back to implementing the 'base' preprocess function, and check if it gets called for the desired view (and optionally display) within that function, roughly like so:
function [yourThemeName]_preprocess_views_view(&$vars) {
$view = $vars['view'];
if ('videos' == $view->name) {
// Add desired manipulations for all 'videos' views
if ('videos' == $view->current_display) {
// Add desired manipulations for the 'videos' display only
}
}
}
You could also add the behavior you expected by implementing a generic preprocess function that tries to call specific versions by checking for functions with the proper name - see the end of this article for an example - but this introduces quite some processing overhead and would only make sense, if you need specific preprocess functions for many views.
There are more 'base' preprocess functions per view type that you can implement directly - see the list of template_preprocess_views_view_* in 'views/theme/theme.inc' for the available options.
As a base rule, whenever there is a template_preprocess_* function for a template, you can implement a corresponding yourThemeOrModuleName_preprocess_* function as well. If you need to manipulate for templates based on template name suggestions, you need to find the 'base' preprocess function name, implement that and check for your specific case in that function (like for the specific view as in the example above).

Drupal node creation - back to origin after creation

I have organic groups setup and within those group users are allowed to post certain content.
What I woulkd like to do is, when you create a node inside an organic group, it automatically defaults back to frontpage of the group, or the same page that I used to create the node.
At present it defaults to the node view page.I assume there must be a way to add some kind of code so that after the node creation it defauls back to its origin. I.E. the page from where the node was created from.
thanks :)
UPDATE: Got the below, but not entirly sure how to ensure that it redirects back to the GROUP node, from where it was created,
<?php
/**
* Grabs current node ID
*/
$node_nid = nid;
/**
* Implements hook_form_alter().
*/
function mod_form_alter(&$form, $form_state) {
$form['buttons']['submit']['#submit'][] = 'mod_form_finish_redirect';
unset($form['buttons']['preview']);
}
/**
* Custom submit handler. Overwrites the form redirection variable.
*/
function mod_form_finish_redirect($form, &$form_state) {
$form_state['redirect'] = '/content/<?php print $node_nid; ?>';
}
?>
I would recommend the rules module. Rules is a great module that allows you to do many kinds of workflow and it is perfect for this. You can write a rule that triggers when a specified node type is created (and include any other conditions you require as well). After the node is created you can specify a redirect action rule to the home page. This can all be done without any code.
Rules (as 'We Love Drupal' says) is a possibility, but also quite a big module for such a small change in behavior. Another option is to write a custom module implementing hook_form_alter setting the #redirect value of the form.
Keep in mind that of seeing the node you have just created is important feedback for a user. When you perform an action, you want confirmation that you have achieved your task. While it's technically possible to do what you ask, it may be bad for usability.
I had the same requirment. Rules worked for me.

Disable Drupal content creation message?

Whenever a content item is created, a message is displayed like this:
[Content Type] [Name] has been created.
Is there any way to disable this message for specific users? Or for all users would be fine too.
I think the best practice would be to use hook_nodeapi() and drupal_get_messages('status'). The $op for hook_nodeapi() would be insert. Ex:
mymodule_nodeapi(&$node, $op) {
if ($node->type == 'content_type_to_check_for' && $op == 'insert') {
drupal_get_messages('status');
}
}
It's node_form_submit that is creating those messages. You could pretty easily use hook_form_alter on the node form and use your own version of node_form_submit instead. All you would need to do, would be to copy the function and add an user_access('whatever') check before that message is created.
Alternatively, you could in preprocess_page function, check which messages is being served, and remove unwanted ones, but that would be a bit more tricky. Should be possible with some regex. On the other hand, this method would be a bit more upgrade friendly, since you could remain using the node_form_submit function and would get future changes if any.
Best way would be to user Disable Messages module.
There are many kind of messages that can be disabled by this module:
Filter out messages that match a full text string exactly.
Filter out messages that match a regular expression.
Permissions to specifically hide all messages of a given type from any role.
Disable all filtering for specific users.
Disable all filtering for specific paths.
Apply filtering only for specific paths.
Debug system to get messages in the HTML without showing it to the end users.
Here is the way I discovered to hide such messages for specific content types (the node type is 'request'):
// specific node type form alteration hook (implements [hook_form_FORM_ID_alter][1]())
function MYCUSTOMMODULE_form_request_node_form_alter(&$form, &$form_state) {
// ...
// custom validation function
$form['#validate'][] = '_custom_request_node_form_validate';
// ...
}
function _custom_request_node_form_validate($form, &$form_state) {
//...
// here we can set a submit handler that is executed before
// node_form_submit which sets the messages we are trying to hide
$form_state['submit_handlers'][] = '_custom_request_node_disable_msg';
//...
}
function _custom_request_node_disable_msg($form, &$form_state) {
//...
// clear status messages
drupal_get_messages('status');
}
If you want to use the Rules module, then you can use the new module I created called "Better Rules Message".
By using this you can setup a rule that will delete all of the messages after a node is being created...
Hopefully this will be added to the main Rules module in the near future.
googletorp is right (about the submit function). But unfortunately you can't decouple the message from the node submit function and duplicating the functionality (without the message) is going to mean your site might break when a security release is issued. You'd have to maintain your own version of that function. It's probably not a big deal but it's a good idea to follow best practice.
You'll need to write your own submit hook either before or after node_form_submit gets called.
With a submit hook after the node save, you could remove the message from $_SESSION['messages'] if the messages array was easy enough to work with. I imagine that would be simple enough. See drupal_set_message
OR
You could write some class in CSS in your body tag and set the display to none when status messages are returned on the page that the node form submits to. But that might put your business logic in your theme layer which should be avoided.
You can use stringoverrides module in drupal ! :)
You could try using the following module to disable specific messages in Drupal - http://drupal.org/project/disable_messages

Resources