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.
The basic idea is exploiting the Field API to define a Title field and attach it to nodes.
On node load (see hook_entity_load) we would replace $node->title
value with $node->title_field[$langcode][0]['value']
, where $langcode
is $language_content->language
. The title field will be hidden by default while viewing the node.
On the node form we must hide the title text field. Before saving we must put in $node->title<code> the value of <code>$node->title_field[$node->language][0]['value']
.
Comment | File | Size | Author |
---|---|---|---|
#59 | initial_work-924968-59.patch | 76.82 KB | plach |
#56 | initial_work-924968-55.patch | 33.53 KB | plach |
#54 | initial_work-924968-54.patch | 33.38 KB | plach |
#50 | initial_work-924968-50.patch | 33.38 KB | plach |
#41 | title-inital-work-924968-41.patch | 15.25 KB | plach |
Comments
Comment #1
das-peter CreditAttribution: das-peter commentedInitial code.
Features:
$entity->title
is changed too$entity->title
according to the language defined by$language_content
Needs testing & review.
Comment #2
das-peter CreditAttribution: das-peter commentedAdded some stuff:
Comment #3
das-peter CreditAttribution: das-peter commentedEnhanced migrate integration - triggers now title translatable hook too.
Comment #4
das-peter CreditAttribution: das-peter commentedFix for migrate integration
Comment #5
plachSorry for the dealy, but I have been pretty busy these days. I'll try to give this a look tomorrow.
Comment #6
das-peter CreditAttribution: das-peter commentedNo problem, just found a nasty issue.
I totally forgot to check the bundle specific multilingual-settings.
We have to make a decision about what should happen if a entity type has title translation enabled - but the bundle has node-translation configured.
Right now, an instance of the translatable_title field is attached to each bundle of a entity type where title translation is enabled - ignoring the bundles multilingual settings.
Here are the two choices I see:
This means that the instance has to be added / removed when the multilingual settings of a bundle are changed.
Here I'm concerned about the data consistency - already translated titles will be lost if the bundle configuration is changed.
This means some bundles will have a unused invisible field attached.
Here I'm concerned about performance and it's ugly to have a hidden / unused field...
What's you suggestion? Any other idea?
Comment #7
plachA quick note while I find the time for a proper review: the project has born as a helper for Translation but will live as an independent project: AAMOF many sites might need node titles behaving as fields besides their multilingual capabilities (e.g. think of HTML titles).
For this reason:
title_field
Comment #8
das-peter CreditAttribution: das-peter commentedI've rewritten the whole thing - removed the per entity-type configuration.
Now there's only a check box to activate / deactivate the title-translations support.
All the rest is done based on the configuration of the translation module and the bundle settings.
After this rewrite a review is definitely needed - I had not enough sleep last night, hopefully the code quality is not battered ;)
Comment #9
plachWell, to make the initial code easier to design and review I'd like having this patch split into smaller ones: first we should focus on the basic behavior (node title replacement), then we can work on integrating other modules. I'd like an issue for each different module so we can discuss every one separately.
That said, here is my first review (to be continued):
Please, change this to "Title". As I said before translatability is only one of the benefits we get by having node title as a field. In my mind the replacement should be as transparent as possible to the users.
I'd change this to something like "A field replacing node title."
Yes, node title has it so I'd say we definitely need one.
See above.
This looks pretty complex to me, why not simply using http://api.drupal.org/api/function/hook_node_load/7?
Edit: we might want to check if this feasible by implementing http://api.drupal.org/api/function/hook_field_load/7.
Since we need to perform this on node save (no matter if the node comes from a form or an API call) I'd implement http://api.drupal.org/api/function/hook_field_presave/7. This way we are sure that no module implementing http://api.drupal.org/api/function/hook_field_attach_presave/7 can "beat" us. Anyway submit handlers can deal with node titles before, so to be sure we probably need to add a submit handler (as first one) to the node form to and update $node->title also there.
I suggest we should have an API function performing the replacement, something like
title_node_sync($node)
, we can call in both places.!empty($entity->translations->original)
should be faster. Moreover there must be a white space vefore?
and:
.$form['title']['#access'] = FALSE;
should be the proper way.title_field_enabled()
Why can't we just have
variable_get("title_field_enabled_$bundle", FALSE)
?Since title field has a more generic scope than just translation we need a configuration in the content type settings form.
Isn't there a way to tell the Field UI we don't need a settings link? I don't really like this kind of form manipulation, but if it is the only way let's go with it.
I think we can use http://api.drupal.org/api/function/hook_field_extra_fields_alter/7 to remove node title form field configuration.
I don't get what this code is supposed to do. Would you please explain to me? I ain't sure understand it well, but two things:
1) Translation will depend on this, so if changes are needed over there to reach a better integration, we'll do them.
2) We don't need to care about node language in the translation form, since it can be changed only in the node edit form.
Powered by Dreditor.
Comment #10
das-peter CreditAttribution: das-peter commentedNode Title
Patch contains only the necessary changes - hook usage / migrate integration excluded.
Hook definition still included - see comment below.
Answers numbered according to code snippets above
But at least I've added a submit handler besides the presave hook ;)
Another question is, if the
title_field_presave
handler should check for changes made to$node->title
and sync them back to the title field.!empty()
$form['title']['#access'] = FALSE
title_field_enabled()
variable_get("title_field_enabled_$bundle", FALSE)
hook_field_extra_fields_alter()
- I simply unset the field right now, do you know a better way to handle this?And because I need pathauto - and I guess a lot other users too - I've used the hook in title.title.inc (not included in this patch) to trigger pathauto.
Of course the ideal solution would be that the modules using the
$node->title
would check if the title_field is enabled and use this instead.According to http://drupal.org/node/902264 I've moved
title_field_schema()
into the ".install" fileCould you check the patch format, please? Is it better now?
What do you think, would we benefit from the test-bot in this early stage of the module?
Comment #11
sunHi there! I didn't really look at the patch, but it seems like this project needs a kick-start. :)
So I went ahead and committed the usual/common baseline of module files (also replacing the old title.module from 2004 that was still there). I hope that this heavily simplifies to roll this patch.
But unfortunately, this patch no longer applies now. :-| Can you re-roll once more?
Also, please make sure that this does not happen. You may want to use http://drupal.org/project/dreditor to review your own patches.
Powered by Dreditor.
Comment #12
plachSorry for being vacant, but I have been busy with killing the language system and core translation queues (there are 3-4 issues over there that would benefit from a passionate eye ;). I'll try to give this another look in a couple of days.
Comment #13
das-peter CreditAttribution: das-peter commentedThanks guy's for feedback. I've re-rolled the patch.
And added ending lines - hope now it fits
Comment #14
sunmmmm -- did you cvs up? title.info, .install, .api.php, as well as a tests/title.test already exists in CVS HEAD now.
Also note that there are some tabs + trailing white-space in the files.
Powered by Dreditor.
Comment #15
das-peter CreditAttribution: das-peter commentedDamn, don't know what went wrong before - this time I deleted not only the existing files but also the whole project to create everything from scratch.
Comment #16
das-peter CreditAttribution: das-peter commentedJust found an small issue in
TitleEntityControllery
. I was not carefully enough while copy paste some stuff.Comment #17
plachFirst of all: thanks for your work on this! I didn't test it yet, I'd like to have a "commitable" patch first, but here is my (hopefully) last code review:
No need for curly brackets in
db_delete
.Can we leave Trigger integration for a later patch?
Trailing dots are missing from many PHP docs/inline comments.
"handler", missing trailing dot
We can implement
title_form_node_form_alter()
and remove this check.We can use
$form['#node']->type
here.Should be "Submit handler" instead of "Callback", missing trailing dot.
For consistency we could use
$form['#node']->type
also here.As I was saying, we can make an API function out of this code, I'd say
title_field_sync($node, $display = TRUE)
. We should have a parameter specifiying if we have to use the node language or the current display language (see http://api.drupal.org/api/function/field_language/7). So we don't need that check on$node->translations
.This way in the submit handler we can call
title_field_sync((object) $form_state['values'], FALSE)
.No, for now I don't think we need to sync the title back.
Here we can call
title_field_sync($entity, FALSE)
.I'd move this code into
title_form_node_form_alter()
so it is not called for each entity form.PHPdocs messed up: for consistency "Checks" should be "Check". We are missing an empty line between the first line and the parameter descriptions, and we are missing also those :)
Missing empty line.
There is no
$form_id
param here.Sure, but I don't fully grok the
title_translate
hook yet, I'll have to test it after we finish the code review.I really don't get why we need this.
We'll change translation to depend on title.
"Submit handler", missing trailing dot.
Where do we need this?
Missing trailing dot.
"there is", missing trailing dot
node_field_extra_fields()
defaults to -5. Perhaps we want to do the same to maintain consistent behavior.As I told you before I ain't sure this is the right approach: altering entity info is subject to the same order than implementing
hook_field_attach_load()
orhook_field_load()
(better): other modules could overwrite our entity controller. IMO we should implementhook_field_load()
and rely on a low module weight (say-0xFFFFFFFF
) to act before any other one. The risk of actually not being the first exists anyway, but we'll have a far simpler code.Sidenote: I took into consideration Entity API while coding the initial Translation patch, but basically it provides a CRUD API which we don't need atm. I'll keep an eye on it, however.
Powered by Dreditor.
Comment #18
das-peter CreditAttribution: das-peter commentedThank you for the feedback. I'd like to see this RTBC asap too. But right now there are still some open points.
I've changed all the parts you mentioned - but for some of them I need some more feedback.
hook_field_load()
hook_field_attach_load()
hooks don't work out for me. It seems like the hooks aren't triggered on each load.The only hook which works for me is
hook_entity_load
. Maybe I'd missed something but it looks like a caching issue.Was just cosmetic anyway, now the overview shows again "n/a" instead the language specific title.
I changed that too - but what's about the titles of other entity types? Is there a more general way instead using
title_form_node_form_alter()
?According to the API Doc of D7 there is a
$form_id
parameter.Removed like the other hook stuff. I moved all this stuff into a custom module because I need a pathauto integration right away for my project.
Removed, was only used in my installation profile ;)
Comment #19
das-peter CreditAttribution: das-peter commentedMistake in hook parameter definition fixed.
Comment #20
plachI tested the patch for the first time and it seems we are almost ready to go!
My goal for the title project is reaching a stable status ASAP with a basic set of features including strictly the ones needed to make Translation and the "node title as a field" behavior work. Afterwards I'd like to work on a general API allowing to replace any pseudo-field with a regular field for any entity. This would allow us to replace Taxonomy term names, for instance, or comment subjects or bodies.
Hopfully these are my last code-related remarks:
Let's remove this line, I don't know which package we should be using, but Multilingual is misleading.
Please remove these dependencies, they are unneeded.
These files are not present atm.
Sorry for making a wrong suggestion, but to have a 32 bit representation this should be
-0x7FFFFFFF
.Probably we are missing some information, see the attached screenshot.
" and hide the standard title field."
After testing the patch I don't think we need this: as I was saying before this module will allow to have a regular field replacing node title; this means we will be able to choose the widget to use and set the text processing type (plain/filtered). Instead we want to implement http://api.drupal.org/api/function/hook_field_widget_info_alter/7 to tell the Field API which widget we support (for now just textfield).
Why
property_exists()
and notisset()
, which should be faster?Missing trailing dot.
"enable/disable". Please remove the whitespaces around the slash.
I'd rephrase this: "If enabled node title is stored and behaves as a regular field."
You are right, I did not take into account field cache. We can keep
title_field_load()
, since it will act before anyhook_field_attach_load()
implementation when field cache is empty. I think performing synchronization two times in this case should not be a great problem.Fine. Let's keep this as the primary way to perform synchronization. We need a comment here explaining what is the intended workflow, I'd say: "Since the result of field_attach_load() is cached, we perform title synchronization also here to ensure that we always have the correct value in $entity->title".
Powered by Dreditor.
Comment #21
sunmmm, review of the review: LOL
Ugh, please don't! :-) -100 should be more than sufficient. There are almost no modules that use a negative weight, and those that actually do, know that, too, and so they're using tiny negative weights only. Although I wonder why this is necessary in the first place (not having looked at the code again), but I hope that the code comments explain it.
Again, not having read the code, I suspect this to be a description of a checkbox. Anyway, "if enabled" should be avoided. Instead, use clear and direct speech to express what effectively happens:
"Node titles will behave like any other field."
(which also reveals that this description does not clearly communicate what it tries to communicate -- what does it try to communicate? ;)
Comment #22
das-peter CreditAttribution: das-peter commentedHi guys,
I've applied all the mentioned changes.
db_query("UPDATE {system} SET weight = -100 WHERE name = 'title'");
(as mentioned by sun) and added a comment.property_exists()
vs.isset()
. Looks like the later is up to three times faster :0 . Frankly speaking, I don't know why I usedproperty_exists()
, but it's interesting, that a specialized function is so much slower.If enabled the title is stored as a common instead an extra field.
toStore title as a common instead an extra field.
. But I'm not sure if this makes clear what happens - @sun any suggestions? Idea is to express that the title will be handled like a common field and thus has the same features - e.g. multilingual support.Comment #23
plachI still get errors on node creation and view. I'm using the latest 7.x-1.x-dev and a plain installation with only Title enabled (no Locale, no Translation):
Moreover we still have some minor string/coding standard issues:
I'd say "Replaces with" is more correct.
Leading tabs instead of spaces.
There should be an indentation of 2 spaces between @param and the following line.
"enable/disable"
Whitespaces around the slash.
As above.
Let's just call
title_entity_load()
intitle_field_load()
.Please add a check on the entity type so we avoid the iteration on non-node entity lists.
Powered by Dreditor.
Comment #24
das-peter CreditAttribution: das-peter commentedAll mentioned issues should be fixed now
Notices were definitely my mistake - had inserted
text_processing
into the field- instead the instance-settings.Test with a plain drupal installation was successful.
Comment #25
plachGreat work!
Let's give sun the chance to have a final look to this before committing it.
Comment #26
sunHm.
1) Somehow, I didn't expect to see a limitation to nodes...? What about other entities like comments and taxonomy terms? We recently introduced generic entity label information to entity API: #629484: Add entity 'label' key info (e.g. title on node)
2) http://drupal.org/node/958162#comment-3696356 -- It would be good to group and order the functions in files by logical and chronological units. In this case: general module hooks, Field API integration, Entity API integration, Node/Form API integration, etc.
3) Why is the field type 'title_field' and not just 'title'? Only the field instance cannot use 'title' and also not 'field_title' in order to not override potentially existing entity properties or attached fields. In other words, the field type should be 'title', only the field instance name should be 'title_field'.
4) title_node_form_submit() clashes with auto-suggested and auto-invoked form submit handlers. An essential change in D7 is that Form API automatically invokes form handlers for the base form ID; i.e., while the form_id of a particular node form might be article_node_form, the base form ID is node_form, and thus, hook_article_node_form_submit() as well as hook_node_form_submit() is invoked in all modules.
5) Additionally, the code in title_node_form_submit() doesn't look correct to me. We need #entity_builders facility that the patch in #830704: Entity forms cannot be properly extended introduces.
Aside from that, good job! Attached patch performs some tweaks.
Comment #27
sunAlso replacing that switch construct, which was a bit weird.
Comment #28
das-peter CreditAttribution: das-peter commentedsun: thank you very very much for your review and the new patch.
It's awesome that you and plach take care about this module :)
I've no additions to your feedback - maybe after a more extensive test run on my installation...
And damn you got me: I've some kind of a switch() statement fetish - but only because I hate if/elseif/else constructs :P
Comment #29
sunBefore committing an initial patch, I'd highly recommend to explore a more generic implementation through the #629484: Add entity 'label' key info (e.g. title on node) facility (which has been committed already)
See http://api.drupal.org/api/drupal/includes--common.inc/function/entity_la...
That would be a bit more future-proof, and actually shouldn't be very hard to do.
Afterwards, we should remove the current checkbox from the node type configuration form, and, also based on the entity label information, integrate with Field UI's Manage Fields configuration page instead. Both the original/legacy title/label of an entity and also the title_field are locked and not configurable on this screen. Core has made sure that modules are able to alter that Field UI table, so it should be possible for us to inject a "Configure" link into the Operations for the title/label field row. The link can point to a custom form callback of Title module, but the resulting effect is that nothing in Title module is limited to nodes anymore. Any entity that is fieldable and has a label can get a title field.
Overall, I expect a decrease in SLOCs, even.
Comment #30
bojanz CreditAttribution: bojanz commentedThe problem with entity_label() is that core itself doesn't use it, so if you remove all the syncing code and just declare a label callback, core would just display the plain old title.
entity_label is used only by contrib at the moment (efq_views, og, etc...).
This means that actually doing an entity_info_alter and adding a callback wouldn't give you anything that the current syncing code doesn't.
Sorry if this is already obvious.
Comment #31
plach@sun:
As bojanz is pointing out
entity_label()
won't work for core, we surely can add a label callback to support it, but this should be an additional measure not an alternative to synchronization.I ain't sure we can fully generalize label handling and extending it to any entity, but if we go this way IMO we should have a basic API to replace any "custom" field with a "regular" field. Title should build on top of this API to handle the particular needs of node titles, which are fairly different from comment subjects, or term or user names, at least in core.
However, the last patch seems to work well, just a couple of issues: the title field should be hidden in the display settings by default, moreover title does not show up in node preview (full version). I found a few coding standard issues left:
Comment does not wrap at column 80.
Wrong indentation.
Comment does not wrap at column 80.
Powered by Dreditor.
Comment #32
klonosI started testing #27 just today and I am really exited to see how this is being implemented. It will eventually solve most of the language/path/translation/sync issues I'm having for some time now in all my D6 setups (list of related issues too long to post here). Here's a list of the issues I've spotted so far:
1. After one enables the 'Store title as a field' setting for a node, there is no way to revert that change (checkbox locked/grayed out). I don't know if this will ever be possible (?), but I am mentioning it anyways in hope to receive a definite answer by someone that understands the 'mechanism' behind this.
2. Once I enabled the 'Store title as a field' setting for the basic page content type and after creating a basic page node, it also displayed the title field (I believe that it was meant/intended to be hidden by default). Please see attached screenshot.
We might have hit a core bug here(?). My guess is that it only effects fields that have 'hidden' as the only available option for their format. Simply visiting the content type's 'Mange display' tab (../admin/structure/types/manage/page/display) and saving the node display places the title field in the hidden section where it should have been in the first place. See second screenie (before hitting the 'save' button) where the title field is listed along with the other fields visible fields, despite the fact that its format is set to 'hidden'.
Comment #33
plachWorking on Field UI/entity_label() integration to see what we can get.
@klonos:
About 1) see http://drupal.org/node/924968#comment-3516774.
I guess we had. It would be nice if you could investigate a little more about this and possibly open a core issue (please link it here if you do).
Comment #34
pcambrasuscribe
Comment #35
good_man CreditAttribution: good_man commented@plach: any patch to share? just want to ask so I won't duplicate the work.
Comment #36
plachI haven't found the time for this yet, but I will in a few days. Don't lose hope ;)
Comment #37
good_man CreditAttribution: good_man commentedNo don't get me wrong, I said so because I might work on this today/tomorrow, so if you haven't worked on it maybe I can give it a try!
Comment #38
plachI didn't write any line of code yet, if you want to try to work on this be sure to post an interdiff between your patch and #27.
Comment #39
plachHere is a partially working patch extending the Field UI to support any entity. As per #31 the patch introduces a field replacement API that can be used on any legacy pseudo-field (there is a docblock describing it in some more detail).
entity_label()
support is still TODO.The main change wrt the previous patch is that the replacement field is provided through an hook for each legacy pseudo-field and can be managed through the Field UI as any other: when a lpf is replaced with a regular field, it disappears from the field overview form and gets back when the replacing field instance is removed.
If the direction is good I'll provide a complete patch implementing syncing and form massaging for any entity.
Please don't make a code style review, the patch is a huge mess from that POV and actually is needs work, just evaulte the direction taken.
Comment #40
plachHere is the full patch implementing form massaging and synchronization for any entity. Comments and documentation should be ok too.
Please let me know what you think about this, because I'd really like to have a testable dev snapshot in a few days.
entity_label() support is still TODO because IMO we have bug in the API: the label callback function is called without specifying the entity type (just the entity), which makes impossible to achieve a generalized label handling. Probably we need to file a core issue to fix this.
Comment #41
plachThere were some trailing whitespaces all around.
Comment #42
fagovery interesting.
* Updating the value on entity load is troublesome as soon as an entitycache would be plugged in. Also it does not apply the right language if the entity is supposed to be display in a different (language) context *if* the display makes use of the plain property value. Perhaps hook_entity_view() could be used instead load() + the value of the default language could be synced into the property before saving.
* The patch in #41 basically implements an API to replace plain entity properties with fields, so it could be used to make any entity property translatable / a field for any reason. So maybe title isn't the right module name any more?
* You could leverage the property info introduced by the entity API for supporting any non-field property, if you want for any data type with any property of the right data type (including field data) as source + the metadata wrappers could be utilized for setting/getting the property values.
However, the multi-lingual-API of the property info would probably need some improvements, i.e. mark properties as multi-lingual in the property info. Update: -> See #1031382: allow marking properties as translatable.
What's that? hook_entity_load() will be invoked anyway?
-> Marking as needs work.
Having entity_label() taking an optional langcode parameter sounds like a good thing to me.
Comment #43
sun@fago created #1031382: allow marking properties as translatable
Comment #44
rfayI took #41 for test drive and it worked fine for me. Thanks!
The one thing that would have improved the UX would have been if the existing titles in existing nodes were copied into the new title field.
Looking forward to translatable entity titles.
Comment #45
BenK CreditAttribution: BenK commentedSubscribing
Comment #46
good_man CreditAttribution: good_man commenteddeprecated call by reference.
Comment #47
Scott J CreditAttribution: Scott J commentedSo far, so good.
Comment #48
plachThanks to git people wishing to review/test some up-to-date code can have a look to the initial_work-924968 issue branch.
At the moment I'm working on some simple tests for the code recently added (mainly integration with the Entity API and support for the 'label callback' entity key).
I'm hoping to post a patch here soon for a final review.
Comment #49
klonos...thanx for the update Francesco. This is great news!
Comment #50
plachOk, here is what I came up with after talking with sun, fago and rfay in Chicago.
The approach is not that much different from the one posted in #41:
hook_field_attach_load
,hook_entity_load
,hook_entitycache_load
(see #1089130: Allow modules to act on any entity type) andhook_entity_prepare_view
(see #1089174: Prepare view hooks do not receive the language parameter);entity_label()
integration for any entity replacing its label with a field; this is currently disabled due to #1096446: entity_label() is not passing along the $entity_type parameter.If there is any other pending concern please let me know soon because I'd wish to release a development snapshot in a week, so more people can start testing this and we can start opening individual issues to polish things.
Comment #51
plachI forgot: we have tests now!
Comment #52
plach@sun:
Somehow related issue: #1099162: Is commit tracking for unofficial branches/tags intended?.
Comment #54
plachLet's try again.
Comment #56
plachProbably we need to commit an initial patch first. The attached one ships some small improvement on comments/phpdocs.
Comment #58
plachComment #59
plachCommitted the attached patch to HEAD!
A development snapshot will be available in 12 hours.
Comment #60
klonosThanx Francesco, that's great!! ;)