Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
As in the subject, we need to execute some custom code only after that all features dependencies and hook are just executed, in our specific case we want to set a default (and save the previously one) input format, that is installed by "input_formats" module.
I've just tried to use hook_enable or hook_install on {myfeatures}.intall, but they are executed too early.
Any advice is really much appreciated.
Thanks a lot,
Paolo
Comment | File | Size | Author |
---|---|---|---|
#58 | hook_features_post_install-981248-58.patch | 1.24 KB | cthiebault |
#56 | hook_features_post_install-981248.patch | 340 bytes | cthiebault |
#20 | features-981248.patch | 1.35 KB | alonpeer |
Comments
Comment #1
havran CreditAttribution: havran commentedHi, i find solution for same thing. I use Features and i want install some dummy content after feature is installed. I use node_export module for exporting content with images. All this working great but only after i enable Feature second time.
I try use function node_export_import($node_array) in my_module.install in hook_enable() but this is too early (content type is not created). For this i use hook_init in my module and here i check my special variable which is set after installing dummy content to TRUE. First time this create nodes with title only (without other fields filled). I try delete all this content, variable, disable all dependencies modules and feature and uninstall them. After that if i enable my feature all working as expected. Dummy content has all fields filled.
Comment #2
paolomainardi CreditAttribution: paolomainardi commentedThanks for your response havran, probably the second time has worked because feature already created (in the first installation) the content type.
My question is, where is placed in the features functions workflow the hook_enable() call to feature itself ?
Thanks a lot.
Comment #3
havran CreditAttribution: havran commentedSorry I have no answer and i want it too :).
Comment #4
paolomainardi CreditAttribution: paolomainardi commentedI'm just digging around features code, i think that could be possible add some hook() after all modules of features are installed, i will provide a patch.
Comment #5
Grayside CreditAttribution: Grayside commentedPart of the problem with creating content after Features are installed is that the feature importation process is re-run when using features-revert.
It might be a cleaner idea to direct the administrator to run a secondary installation process to set up the content, such as going to a special administration page or running a drush command.
Comment #6
paolomainardi CreditAttribution: paolomainardi commentedInteresting, the alternative would be to have some hook_featuresapi() with an $op parameter as: 'install' 'disable' 'revert'
What do you think ?
Comment #7
havran CreditAttribution: havran commentedI'm trying create dummy content after enable new content type in feature an i think i need some function like node_types_rebuild(); and then content_clear_type_cache(TRUE); and then i can insert new content - but this work only partialy. Content is created but CCK fields are empty.
Comment #8
havran CreditAttribution: havran commentedFor dummy content i use this approach now.
I use module Node Export (http://drupal.org/project/node_export) for export and import content.
I create module which is last enabled module in my install profile.
This module set frontpage to 'finalize-configuration' page.
install file
module file
Dummy content is stored into directories named by content type name.
Comment #9
paolomainardi CreditAttribution: paolomainardi commentedThanks a lot Havran for sharing your solution.
Actually i didn't have so many time for creating a generic solution, also because Features API are quite complex, could be nice to have some info by module developers in order to take the right direction.
Keep me updated if you make progress.
Thanks a lot.
Comment #10
Grayside CreditAttribution: Grayside commented@#6: Interesting. It puts me in mind of the hook_nodeapi() pattern.
Not sure if I like that plan. Bears thinking.
Comment #11
inductor CreditAttribution: inductor commentedIt would be a very useful hook. Use case: I include some roles in my feature, and want to assign input formats to them. I can`t achieve this using the hook_install/enable, because the roles aren`t already in the db. So for now I hack the features*.inc files.
Maybe somebody more skilled than me will roll out a patch?
Comment #12
good_man CreditAttribution: good_man commentedsubscribe
can we make hook_install and hook_enable only called after all processing is done? or should we introduce a new hook (e.g. hook_ready).
Comment #13
Grayside CreditAttribution: Grayside commented@good_man: hook_install and hook_enable are called by drupal core, we cannot affect when in the page load they are called. A hook like I proposed in #10 would be reasonable--this is Features-specific.
Comment #14
davideads CreditAttribution: davideads commentedGlad I came across this. I'm also struggling with input formats -- I'm forcibly creating a wysiwyg module profile that more or less MUST be tied to a custom input format (the feature allows TinyMCE to operate as a Markdown source editor). Got it all working nicely BUT the install relies on rather ugly hacking of the feature *.inc files to load everything correctly.
I'd pretty pretty happy with a simple "feature_post_install" hook -- perhaps you could pass it information about the current operation (reversion being different than installation) and leave it at that (if I understood grayside correctly, this is a pretty similar idea).
Comment #15
alonpeer CreditAttribution: alonpeer commentedI like @davidead's idea for hook_feature_post_install, this will really upgrade what I can accomplish with Features.
In my current project, I have a new profile field and cck field, and I want to update them automatically using existing user and node data. hook_install and hook_enable just don't cut it.
My temp solution is using hook_enable with a condition that checks if those fields are empty or not before updating them. This ensures it'll run only once and not each time the feature module is disabled and re-enabled.
Comment #16
davideads CreditAttribution: davideads commentedalonpeer -- the hook_enable solution is a good temporary solution. I would code up a patch for this but currently there's some confusion at my job as to whether I can (for licensing reasons) contribute patches to d.o projects and I don't have the time outside of work to do this.
Comment #17
alonpeer CreditAttribution: alonpeer commentedOK, maybe I'll find the time over the weekend to familiarize myself with the Features' code and write this sort of patch.
Task added :)
Comment #18
Grayside CreditAttribution: Grayside commentedThis is not exactly trivial. Features is not directly involved in the installation of every feature. In fact, there is nothing special features does to react to a module installation, rather, it reacts to the cache being cleared or the feature being reverted.
What is called for here is really a
hook_post_install($module)
in Drupal core, which Features could then use to detect whether a feature had just been installed and take action.If you are willing to test this kind of thing every cache clear, you could add
hook_features_restore_after()
to_features_restore()
.Comment #19
alonpeer CreditAttribution: alonpeer commented@Grayside, thank for the clarifications.
Please correct me if I'm wrong regarding the sort of patch I need here:
In
_features_restore()
, inside the outer loopforeach ($items as $module_name => $components)
, I will check if the current module has already been installed once before (using an array I will save and update in the variables table), and if it hasn't, I will call that module'shook_features_post_install()
.Does that sound right?
Should I run this only if
$op == 'rebuild'
, or is it also relevant for'revert'
?Comment #20
alonpeer CreditAttribution: alonpeer commentedHere's a patch that implements what I described above, please let me know if this is the right direction.
Comment #21
davideads CreditAttribution: davideads commented@alonpeer I'm about to test this, but I did have a question after a cursory review: why not pass the 'op' variable to the _post_install hook?
Comment #22
davideads CreditAttribution: davideads commentedAlso the hook seems to work in my instance (installing a WYSIWYG module profile the hard way) just as expected. Thanks, @alonpeer.
Comment #23
alonpeer CreditAttribution: alonpeer commented@davideads thanks for testing, I'm glad it works. I hope we get some more testing done soon.
I don't see a good reason to pass the $op parameter. This post install process is supposed to run only once when the Feature is first installed.
I think we should keep it simple.
Comment #24
good_man CreditAttribution: good_man commentedI think he means #6
but for this issue I think we better now keep it for installing only.
Comment #25
davideads CreditAttribution: davideads commentedFair enough, re: the $op argument -- I could see a use for the hook running on the 'revert' op as in comment 6, but I'd rather have a simple, working hook and then add the sugar. Here's a module (which currently has some one bad, scary bug) which exploits this hook to install a wysiwyg profile: http://github.com/ecenter/editor_tinymce_markdown.
Comment #26
amitaibuWouldn't it be enough to create hook_update_N() that feature_revertes everything, and then executes all your code?
Comment #27
Grayside CreditAttribution: Grayside commentedThat should work for most cases, but there could be issues with anything that doesn't load into the database until the first page load after revert.
Comment #28
carn1x CreditAttribution: carn1x commentedsubscribe
Comment #29
Grayside CreditAttribution: Grayside commentedHm, not sure why I didn't think of this, but the other problem with relying on hook_update() is that you might want to import content on the initial installation of your feature, and anything triggered by hook_install() will happen before some feature components are properly imported to the database.
#20 is looking like the cleanest path.
Comment #30
smk-ka CreditAttribution: smk-ka commented+1, this is a badly needed addition, given the way features are installed. #20 is working fine here on 7.x-1.0-beta2.
Comment #31
drewish CreditAttribution: drewish commentedShould probably be evaluated on 7.x first then have the fix backported.
Comment #32
Cauliflower CreditAttribution: Cauliflower commentedPatch #20 works for me, thx a lot !
Some suggestions:
If you want to execute some code in module/feature x after feature y is enabled, we need an implementation of this mechanism:
Comment #33
davideads CreditAttribution: davideads commented@cptnCauliflower -- my patch way back when passed $op so the developer could use that as contextual information if she so desired. I dropped it, but I think it makes sense because you might wish to trigger conditional behavior when enabling, reverting, etc.
Comment #34
ao2 CreditAttribution: ao2 commentedPatch from #20 works for me too, in my case I wanted to add terms to a vocabulary I were creating via features.
Thanks,
Antonio
Comment #35
Grayside CreditAttribution: Grayside commented@Cauliflower the goal of the patch is to facilitate the feature you are enabling taking further action after it has gone through the complete routine of installation. hook_install() fires before many features-specific things have happened, which requires this extra, optional function call so the module can take further steps.
I think making this a hook is an interesting idea, but that kind of functionality starts to encroach pretty closely on just adding a
hook_install_module()
hook that allows any module to react to other module installations.Comment #36
Grayside CreditAttribution: Grayside commentedComment #37
febbraro CreditAttribution: febbraro commentedSo there are a few things wrong with the patch. For starters _features_restore does not get called when you enable a feature so you'd have to find a different place to kick it off. The other thing is that if a feature is later disabled and uninstalled and then reinstalled the post install hook would not fire again.
Now, for D7 there is already a core hook that could be used for a post install hook, and that is:
http://api.drupal.org/api/drupal/modules--system--system.api.php/functio...
In talking with Grayside/hefox in IRC is seems like a good fix for D6 would just be having Features implement something very similar to hook_modules_installed such that the upgrade path to D7 would be eased.
So I think the verdict is there is a bit more work/thinking required for D6 and D7 can use core hooks to accomplish the same goal.
Comment #38
ao2 CreditAttribution: ao2 commented@febbraro, it looks like hook_modules_installed() is still not enough to access features added by the same module it is defined in, e.g.:
In my case the vocabulary is defined in
MY_MODULE.features.taxonomy.inc
buthook_modules_installed()
still can't see it. Maybe I am still missing something.Regards,
Antonio
Comment #39
smk-ka CreditAttribution: smk-ka commented@febbraro
No, features (i.e. Drupal's praised deployment strategy) is actually nothing more than a giant hack: it is (currently, at least) triggered by hook_flush_caches(), which means it runs *after* any modules have been installed and associated hooks have run. Unfortunately, this means hook_modules_installed is of no use. Whether features could be rewritten for D7 to be triggered as the first module in hook_modules_installed (see hook_modules_implement_alter) is another question that should be investigated.
Comment #40
fabsor CreditAttribution: fabsor commentedusing hook_modules_installed for importing configuration would make it hard for a feature module to implement hook_install itself to do things with it's own configuration. We would also have serious problems with weighting issues if we would like to do things after features has done it's thing.
I would propose that we add a new hook, hook_component_rebuilt, that takes in the component that has been rebuilt and maybe also a flag that indicates that it was added. This would also make it possible to do proper "update" hooks that needs to act after configuration has been rebuilt, which could be a good thing for deployment.
I would be happy to work on this, if you think that solution sound like a good one.
Comment #41
davideads CreditAttribution: davideads commented@fabsor This corner of the peanut gallery thinks that's a highly reasonable approach. It would certainly satisfy my use cases nicely.
Comment #42
Grayside CreditAttribution: Grayside commentedSomething about @fabsor's approach sprung to mind the idea of using Feeds to handle the import process (sans UUIDs). I don't think that has much bearing on where we place the hook, but it might be relevant to consider for use cases and parameters.
Comment #43
davideads CreditAttribution: davideads commented@Grayside it seems like that runs the risk of being overly complex, but maybe I'm not seeing it... Can't developers simply call feeds if they need to?
Comment #44
Grayside CreditAttribution: Grayside commentedI'm suggesting the implementation of whatever hook this produces might want to trigger a feeds module parsing of a CSV file. Feeds itself could support the use cases of detecting changes/preventing duplicates/etc. It is an implementation use case for handling content import.
Comment #45
fabsor CreditAttribution: fabsor commentedIf we go with this approach we could basicly write code to act upon any rebuild of any component, so yes, it would definetly be possible to for instance import things with feeds.
Comment #46
dgtlmoon CreditAttribution: dgtlmoon commentedsubscribing
Comment #48
attiks CreditAttribution: attiks commentedsub + linking back from #1265168: Rebuild the file list properly when a feature is enabled or disabled
Comment #49
logaritmisk CreditAttribution: logaritmisk commentedsub
Comment #50
njcheng CreditAttribution: njcheng commentedSubscribing.
Comment #51
guillaumev CreditAttribution: guillaumev commentedFor people looking for a temporary solution to this, here is what I do:
If it can help someone...
Comment #52
Mark Vincent Verallo CreditAttribution: Mark Vincent Verallo commentedThis really helped me. Thank you very much.
Comment #53
bergamot CreditAttribution: bergamot commentedI have a feature with some content types, and a module that inserts some nodes of these content types.
What i've done, and seems to work:
Make a dependency on the feature from the custom module:
In the .info:
In the .install file of the custom module, in hook_install, I call the features_rebuild function, that instantaneously rebuilds the enabled features, and thus makes the content types available.
The only downside of this is that the feature gets rebuilt twice: once in the custom module's install file, and once after all modules have been enabled.
Comment #54
neochief CreditAttribution: neochief commented@bergamor, you can use UUID + Deploy modules to export nodes to a feature instead of having it in a module. If you use the trick with dependency there, you wont't need to rebuild things two times.
Here you will find a patch to solve missing includes during installation: http://drupal.org/node/1265168#comment-5810726
Comment #55
cthiebault CreditAttribution: cthiebault commentedFollowing comment #39...
I understand why we cannot use standard hooks like hook_install, hook_modules_installed, etc.
But I don't understand why it would not be possible to add a hook_features_post_install that would be called after the rebuild?
Could we do something like this?
Comment #56
cthiebault CreditAttribution: cthiebault commentedHere is the patch for this.
I tried it and it works... but it's definitely not the best solution:
- this hook is called when all features have been rebuild... not only the feature of the current module
- it's called several times so we have to check if the work done in our hook_features_post_install was already done
Comment #57
cthiebault CreditAttribution: cthiebault commentedForget my patch.. it does not work as I imagined...
Comment #58
cthiebault CreditAttribution: cthiebault commentedFinally I've modified patch from #20 to include op name in the hook.
And I don't check if the features was already installed because the first time op == 'enable' but I needed to do some work on rebuild so my module implements hook_features_rebuild_completed.
Here are the available hooks:
Comment #59
cthiebault CreditAttribution: cthiebault commentedComment #60
EmanueleQuinto CreditAttribution: EmanueleQuinto commentedUhm, after reading the comments and testing we found a possible solution. At least it works with taxonomy that is our user case, but probably works for other contents as well.
In comments #37 febbraro suggested to use the hook_modules_installed() but in #39 ao2 discovered that the added features are not yet available. In #53 bergamot suggested to use an auxiliary module for further processing noticing the need of features_rebuild();
Now Putting the Pieces Together (C) what about using the hook_modules_installed and call features_rebuild?
Well it works at least for the taxonomy!
We need to add 3 taxonomy terms ('Available', 'Booked', 'Canceled') in the vocabulary defined in the feature and here's the code:
You can check the output commenting features_rebuild(): it won't work. Not sure about side effects of running features_rebuild there but everything seems ok.
Comment #61
davidwatson CreditAttribution: davidwatson commentedComment #62
ao2 CreditAttribution: ao2 commentedThanks @cthiebault
Patch from #58 looks OK to me, and I verified it woked in my use case of adding terms to a taxonomy defined in the feature itself. I just have to add the terms in the hook_features_rebuild_completed() implementation.
@EmanueleQuinto give that a try.
Comment #63
hefox CreditAttribution: hefox commentedHaven't been reading this fully, but please provide some sort of example use of the new hooks in api functions.
Also, wouldn't it be relavent to provide status information, e.g. what was rebuilt/disabled/etc?
Comment #64
BrockBoland CreditAttribution: BrockBoland commentedAs hefox pointed out there, I started a similar issue a couple weeks ago, because I didn't find this one.
#1782492: Invoke a hook on the Features module when the feature is reverted/enabled/disabled
Perhaps we should combine them, but I've added some additional aspects to my version. I found that running
drush features-revert-all<code> will actually call <code>_features_restore()
once for each component. As such, I moved the hook invocation inside the$components
loop, and pass the affected component to the hook. I also included a "pre" hook to run before Features reverts/installs/uninstalls, just in case.Comment #65
mpotter CreditAttribution: mpotter commentedI think Brock's patch is a bit more general-purpose, so I'm closing this as a dup and will work on getting #1782492: Invoke a hook on the Features module when the feature is reverted/enabled/disabled into one of the next versions.