Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add user preference api #1948

Closed
wants to merge 7 commits into from
Closed

Add user preference api #1948

wants to merge 7 commits into from

Conversation

notnownikki
Copy link
Member

@notnownikki notnownikki commented Jul 19, 2017

Fixes #1455

lib/api.php Outdated
* @param string $request The parameter key for the value being validated.
* @return bool If the preference name is valid.
*/
function gutenberg_validate_preference_name( $preference_name, $request, $key ) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to wrap all of this logic in functions? Why not just a single static class that also contains a register_routes method?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need to, but merging these and the Gutenberg_User_Preferences would couple it to the API, as it would become dependent on the API request. But perhaps that's not a problem, I'm still getting used to our coding styles and usually I'd have a class that handled the preferences and could be reused outside of the API. I'll change this round.

* @return bool If the preference name is valid preference.
*/
public static function is_valid_preference_name( $preference_name ) {
return in_array( $preference_name, self::VALID_PREFERENCES );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can add a filter here to allow plugins to register their own user preferences. Not something that needs to be done for this PR.

lib/api.php Outdated
function gutenburg_register_routes() {
register_rest_route( 'gutenburg/v1', '/user-preferences', array(
'methods' => WP_REST_Server::READABLE,
'callback' => 'gutenburg_get_user_preferences',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We will want a permission_callback here and with other endpoints to make sure the user is authenticated (and has whatever capability we deem necessary to use the Gutenberg interface, probably edit_posts). We should be able to re-use the same permission callback for all of these routes..

lib/api.php Outdated
'validate_callback' => 'gutenberg_validate_preference_name',
),
),
) );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's combine these two endpoints using the same route ('/user-preferences/(?P<preference>[a-z_]+)') into a single register_rest_route call. See: https://core.trac.wordpress.org/browser/tags/4.8/src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php#L90

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, now that I think about it, I don't think there are many use cases for getting a single preference. Setting a single preference and setting multiple preferences can be done the same way:

POST /gutenberg/v1/user-preferences
{
    "pref1": "value1",
    "pref2: "value2" // if needed, and so on
}

or the value can be set to null to delete them.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. Will change this.

@notnownikki
Copy link
Member Author

Merged the api routes and functions into the preferences class, fixed a load of lint issues and issues with older PHP versions, and added API tests.

Will squash this up once we're happy.

@notnownikki notnownikki changed the title [WIP] Add user preference api Add user preference api Jul 24, 2017
@swissspidy
Copy link
Member

Couldn't we just use the users/me endpoint when all that's done is setting some user meta...?

Instead of using the REST API for this, we should think about leveraging the user settings WordPress already has. See wp_user_settings(), get_all_user_settings(), getUserSetting(), setUserSetting(), etc.

The wp-settings-{time}-[UID] cookie is made to store user preferences like the number of list table items, etc. Seems like most recently used blocks would be a good fit for that as well.

We can simply update the cookie on the client side using setUserSetting(), and every time the cookie is sent to WordPress, it will update the user setting.

@nylen
Copy link
Member

nylen commented Jul 27, 2017

/users/me isn't a great fit here because of permissions: there's no reason to allow users to read each others' preferences, and AFAIK there's no way to support this kind of permission with register_meta.

The existing user settings functions may work fine; I don't think we knew about them, but we should try that first.

$user_id = get_current_user_id();
$preferences = array();
foreach ( self::$valid_preferences as $preference_name ) {
$preferences[ $preference_name ] = get_user_meta( $user_id, 'gutenberg_' . $preference_name );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens when a preference is unset? It should be excluded from this array.

}

foreach ( $params['preferences'] as $preference_name => $value ) {
update_user_meta( $user_id, 'gutenberg_' . $preference_name, $value );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If null is passed here, then the preference should be deleted instead.

@nylen
Copy link
Member

nylen commented Jul 27, 2017

This code looks nice and clean, the only thing I see that's missing is handling of unset preferences and deleting preferences.

Let's hold off on adding those, though, we may not need this at all. Sorry about the potential waste of effort 😞

@notnownikki
Copy link
Member Author

In the end this wasn't required, but before I close and delete the branch, @nylen what was the alternative to this?

@swissspidy
Copy link
Member

@notnownikki #2140 used the existing user settings functionality I mentioned earlier.

@notnownikki
Copy link
Member Author

I'm not quite sure what this would look like using setUserSetting... we'll want to keep track of how often the user uses blocks, so on first load, the user sees their most frequently used blocks. It doesn't look like it's possible to have a user setting that contains more than simple values, so we'd have to have a setting per block type with the number of uses?

@swissspidy
Copy link
Member

You can totally store arrays etc. with it. No need for per-block-type-settings

@notnownikki
Copy link
Member Author

Ah brilliant! Thanks, docs on it were a bit difficult to find, codex. and developer. returned nothing when I searched for it.

@notnownikki
Copy link
Member Author

@swissspidy so I've been trying this, and can't get it to work with anything but strings.

window.setUserSetting('test', { option: true } )

results in this:

window.getUserSetting('test')
"objectObject"

I still can't find docs on this, but reading the code, it converts the value to a string just by calling .toString which isn't going to be able to store objects or arrays, so I still can't see how it's a viable alternative to this PR. Can you show me how it should be used?

@youknowriad
Copy link
Contributor

I had the same issue when using setUserSetting. I ended up using the userSetting global in the same way setUserSetting does #2462 (comment)

@notnownikki
Copy link
Member Author

Closing in anticipation of @youknowriad's PR that will take care of serialization

@notnownikki notnownikki deleted the add/user-preference-api branch August 22, 2017 11:44
@notnownikki notnownikki restored the add/user-preference-api branch August 22, 2017 13:24
@notnownikki
Copy link
Member Author

Reopening.

Turns out we've been looking at this from different perspectives. There's a need for local storage that persists on the client side (e.g. recently used blocks, session preferences) and storing data that persists across session and browser (e.g. block usage stats so we can determine what blocks a user frequently uses, across all their posts).

This PR lets us fulfil the latter, and there is currently no way of doing this. So, reopening in case js-core discussions don't result in something usable for us.

@notnownikki notnownikki reopened this Aug 22, 2017
@codecov
Copy link

codecov bot commented Aug 22, 2017

Codecov Report

❗ No coverage uploaded for pull request base (master@659c64f). Click here to learn what that means.
The diff coverage is n/a.

Impacted file tree graph

@@           Coverage Diff            @@
##             master   #1948   +/-   ##
========================================
  Coverage          ?   27.2%           
========================================
  Files             ?     160           
  Lines             ?    4914           
  Branches          ?     819           
========================================
  Hits              ?    1337           
  Misses            ?    3030           
  Partials          ?     547

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 659c64f...2e1259e. Read the comment docs.

@BE-Webdesign
Copy link
Contributor

@notnownikki

I think we should use {action}_user_option over {action}_user_meta. The user options API in WordPress is multisite compatible, where user meta is not. Basically it is a wrapper for user meta but adds the blog id as part of the meta key. Going to check out the code more in depth so we can hopefully get this merged soon.

@gziolo
Copy link
Member

gziolo commented Jan 27, 2018

It looks like #1455 is closed. I'm closing this one as it is very old. Feel free to reopen if this one is still necessary. Thanks :)

@gziolo gziolo closed this Jan 27, 2018
@gziolo gziolo deleted the add/user-preference-api branch January 27, 2018 11:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants