This is a very vague idea I've been turning over for ages.
The motivation is this:
A ton of support requests in the issue queue are due to people using Flag in totally bizarre and insane ways. Generally, they add a flag to something that they don't actually care about being flagged. What they actually want to happen when the user flags is completely different. They then use Rules to detect the user flagging the entity, and then cause the thing they actually want to happen -- and throw away or ignore the actual Flagging.
Some recent examples:
- using Flag to add products to the cart with Commerce
- using Flag to publish/unpublish a node
- wanting the flagged entities to end up as values in an entityreference field, so that the end result is an orderable list of things. This might be, for example, a playlist or a wishlist.
The reason for doing this convoluted crazy stuff is simple: people want the nice JS AJAXy toggle link. Using Flag gives them a very nice UI where the user sees 'Add to cart', clicks it, sees the link update itself and turn into 'Remove from cart'.
This leads me to consider the following question:
Could we decouple the link part of Flag to a general 'Action Link' module?
This would provide generic links that 'do stuff'. A link would have a particular entity as its subject, and be aware of the current user. We'd have different types of link, to match the current different types of flag link.
- instead of the path being flag/ACTION/FLAGNAME/ENTITY_ID we'd have action_list/ACTION_LINK_NAME/TOGGLE_STATUS/ENTITY_TYPE/ENTITY_ID
- ACTION_LINK_NAME would be analogous to the flag name. We'd prefix with 'flag', so here it would be 'flag_bookmarks'.
- TOGGLE_STATUS would 0 or 1 (or preferably something human-readable, but using 0 and 1 would allow us to extend from binary toggling if desired)
- ENTITY_TYPE isn't necessary for flags, but nice to have if other consumer modules need to know this.
The link types would be, as currently on Flag:
- AJAX link, updates magically
- Normal link, reloads the page
- Confirmation form
Things to figure out:
- how to tell the Action Link system how to attach the Flagging entity that we now have on the Flagging form.
- how do we account for the Flagging Form module's flag link, which allows editing of the flagging once it's been made? This might be a general concept that you can return to the confirmation form and adjust the current state of the toggle. But then:
- how do we account that for Flag, when the toggle is 'off' there is nothing to actually look at, as there is no flagging? That suggests that an 'adjust current state' form is per-state
- Flags are per-entity type. An action link presumably does not need this restriction. But individual ones -- such as those provided by flag -- would need to be aware that they are restricted in this way.
Applications of this beyond Flag:
- nodequeue, which currently has a 'normal link' on nodes
- OG: join/leave group
- Commerce: Add to basket
- Workbench: publish / mark for review
- Rules: triggers a Rules event, allowing custom behaviour
- making/breaking entityreference relations (as in, 'add this entity as a value to a set field on a set entity'. This would cover things like 'Add to my playlist', where a playlist is an entity with a multivalued field so that items can be ordered)
How this would look to consumers:
I imagine that to declare an action link, you need to specify:
- its type: whether it's AJAX, reload, confirm form, etc
- its machine name: eg 'flag_bookmarks'
- various strings for the different states, like we have for Flag at the moment.
- various options such as:
- whether the action is reversible
- whether the action link is replaced with the reverse link, or a confirmation message
- a callback for performing the actual action. This would need standard parameters, presumably something like:
- the action link machine name (from which we deduce the flag)
- the toggle state (maps to 'flag' / 'unflag')
- entity type
- entity ID
- the account performing the action
- an array of extra options from, say, the query string-
- a callback for access, which would get the same sort of parameters
How this would work for users:
We'd want to keep the setup tasks to a minimum, and not end up with the sort of situation with D7 taxonomy (where it's a lot more complicated to add taxonomy terms to a node type).
On Flag we now have flag links exposable as:
- entity links, set per view mode. This is in the style of D6-era hook_links(), alongside the 'read more' link. This is obviously mainly suited to nodes and users.
Ideally, we'd keep everything in the Flag admin form, but allow the creation of multiple Action Links per flag. Each action link can be set to display as entity links or pseudofields, or be output with a theme call.
Consequences for Flag:
- extra dependency :(
- more users and eyeballs on our JS code, which really needs someone who knows their JS to take care of it
- slower code :( We need to load two pieces of configuration: the Flag itself and the Flag link. But it's highly likely that we'd want Flag Links to become their own plugin type on D8 anyway, so the only extra bit of indirection is that the Flag Link plugin would need to know its callbacks, rather than those being hardcoded.
Interesting ways to take this further
- make the link type dependent on the state, rather than for the whole action link plugin. This is a current feature request on flag: have a confirm form for flagging, but just AJAX for unflagging.
- have more than 2 states: cycle through A -> B -> C -> A rather than just A -> B -> A.