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

Media: Remove manual cache busting #4312

Closed
swissspidy opened this issue Sep 2, 2020 · 7 comments · Fixed by #11759
Closed

Media: Remove manual cache busting #4312

swissspidy opened this issue Sep 2, 2020 · 7 comments · Fixed by #11759
Assignees
Labels
Group: Library Group: Media Group: WordPress Changes related to WordPress or Gutenberg integration Group: Workspace A group encompassing all of workspace – everything inside the canvas and sidebar P2 Should do soon Type: Code Quality Things that need a refactor, rewrite or just some good old developer ❤️

Comments

@swissspidy
Copy link
Collaborator

Task Description

In the editor we currently preload media items using the wp.apiFetch preloading middleware.

It is basically works as a cache that can’t be invalidated.

So if /path/to/load/media is preloaded, it's not possible to request /path/to/load/media again to fetch new data as it will always use the cached data.

This causes issues like #4109 and requires solutions like #4310.

One possible alternative solution mentioned by @Jhtin is to make the initial call look different from the subsequent calls. Then you preload the first call that looks different and then every subsequent call isn’t cached. Basically the opposite of what #4310 dos.

Essentially, what we need is a way to pre-populate media state upon page load, ideally one that is not so tightly coupled to WordPress, i.e. avoiding wp.apiFetch preloading middleware

@swissspidy swissspidy added Group: Media Type: Task Tasks which do not involve engineering Group: WordPress Changes related to WordPress or Gutenberg integration Pod: Prometheus (Workspace) labels Sep 2, 2020
@swissspidy swissspidy added the P3 Nice to have label Sep 23, 2020
@barklund barklund added the Group: Workspace A group encompassing all of workspace – everything inside the canvas and sidebar label Oct 5, 2020
@swissspidy swissspidy added Group: Library Type: Code Quality Things that need a refactor, rewrite or just some good old developer ❤️ and removed Type: Task Tasks which do not involve engineering labels Sep 9, 2021
@mohdsayed
Copy link
Contributor

mohdsayed commented Sep 10, 2021

Just for the reference of my findings:

  1. Gutenberg also preloads multiple paths by using wp.apiFetch.createPreloadingMiddleware

https://github.com/WordPress/WordPress/blob/e175db4ae12056774d691f8b377cb61a4b9655aa/wp-includes/block-editor.php#L453

  1. initialEdits is the fifth parameter of wp.editPost.initializeEditor
    https://github.com/WordPress/WordPress/blob/e175db4ae12056774d691f8b377cb61a4b9655aa/wp-admin/edit-form-blocks.php#L270-L281
    Which is null by default and holds an object containing title, content and excerpt when the post status is auto-draft initially.
    https://github.com/WordPress/WordPress/blob/e175db4ae12056774d691f8b377cb61a4b9655aa/wp-admin/edit-form-blocks.php#L80-L90

So looks like you want to remove this wp.apiFetch.createPreloadingMiddleware for two reasons.

  1. To remove the workaround of passing cacheBust=true to invalidate cache.
  2. In a non-WordPress environment when may be apiFetch is not used, we don't expect the integration to use some middleware to preload data like we currently do?

If both the assumptions are correct, I can only think of one possible solution for now.

With the proposed changes for API calls in #8966, all the apiFetch calls have been moved to wp-story-editor package however we are still in control of calling those API callbacks from the core editor.

https://github.com/google/web-stories-wp/blob/8a5f1915e903e93255aa87acca0f0cf165e7e1a2/packages/story-editor/src/app/api/apiProvider.js#L170-L174

What if we add one more parameter of apiPath and pass the preloaded data via window.webStoriesEditorSettings
https://github.com/google/web-stories-wp/blob/9d18d5f52f1b8a88f170df6be099b0a9d69e40c2/includes/templates/admin/edit-story.php#L130-L141

Something like this

window.webStoriesEditorSettings.preloadAPIResponse = {
  '/web-stories/v1/web-story/5/?_embed=..': {},
  '/web-stories/v1/media..': {},
  '/web-stories/v1/users/?per_page=100..': {}
    ...
}

and then we create some helper function as our own little middleware/HOF of these callbacks in story-editor which will return the preloaded response only if it is the initial load unlike wp.apiFetch.createPreloadingMiddleware which always returns the pre cached response for the same API path. Something like

actions.getMedia = useCallback(
  ({ apiPath, mediaType, searchTerm, pagingNum }) =>
    withInitialPreload( apiPath )( () => getMedia({ mediaType, searchTerm, pagingNum }, media) ) ,
  [media, getMedia]
);

withInitialPreload would somehow be aware of the initial load and return the preloaded response with Promise.resolve( preloadData ) or else would call the provided API Callback and return the fresh response.

@swissspidy
Copy link
Collaborator Author

I just had another look at this and it turns out this was fixed in Gutenberg a while ago! 🎉

See:

Preloading now only works a single time, the cache is invalidated after that.

That means we no longer need this cacheBust parameter and don't need to overcomplicate things with initialEdits etc.

@swissspidy
Copy link
Collaborator Author

I suppose we still need to keep this for WP < 5.7, which is where this fix was included (Gutenberg 9.1 maps to WP 5.7)

@swissspidy swissspidy changed the title Reconsider media preloading in the editor Media: Remove manual cache busting Sep 22, 2021
@swissspidy swissspidy added P2 Should do soon and removed P3 Nice to have labels Jun 11, 2022
@spacedmonkey
Copy link
Contributor

I suppose we still need to keep this for WP < 5.7, which is where this fix was included (Gutenberg 9.1 maps to WP 5.7)

As we are not going to support 5.7- soon, do we still need this ticket?

@swissspidy
Copy link
Collaborator Author

Well, we need the ticket to finally remove this code.

We've added this manual cache busting in the past because we had to support older WordPress versions.

Now that we are bumping the WP version requirement to WP 5.7+ we should be able to finally remove this manual cache busting, which is why I moved this to Ready for Sprint.

Relevant code sections:

{ mediaType: currentMediaType, cacheBust: true },

{ mediaType: currentMediaType, cacheBust: true },

it('resetWithFetch calls getMedia with cacheBust:true and then fetchMediaSuccess', async () => {
// Set up and make initial call to useContextValueProvider (which calls
// getMedia and fetchMediaSuccess once). Sets an empty media state.
const getMedia = jest.fn(() =>
Promise.resolve({
data: [],
headers: GET_MEDIA_RESPONSE_HEADER,
})
);
const apiState = {
actions: {
getMedia,
},
};
const configState = {
api: {},
allowedMimeTypes: {
image: [],
vector: [],
video: [],
caption: [],
audio: [],
},
capabilities: { hasUploadMediaAction: true },
};
const { result } = renderAllProviders({
reducerState,
reducerActions,
configState,
apiState,
});
// This promise will only complete when the "done()" callback is called
// (see reducerActions.fetchMediaSuccess mock implementation in Promise).
await new Promise((done) => {
getMedia.mockImplementation(() => {
return Promise.resolve({
data: GET_MEDIA_RESPONSE_BODY,
headers: GET_MEDIA_RESPONSE_HEADER,
});
});
reducerActions.fetchMediaSuccess.mockImplementation(() => {
done();
});
// Act:
result.current.actions.resetWithFetch();
});
// Assert after fetchMediaSuccess callback is called:
expect(getMedia).toHaveBeenNthCalledWith(2, {
mediaType: '',
searchTerm: '',
pagingNum: 1,
cacheBust: true,
});

// Important: Keep in sync with REST API preloading definition.
export function getMedia(
config,
{ mediaType, searchTerm, pagingNum, cacheBust }
) {
let path = addQueryArgs(config.api.media, {
context: 'view',
per_page: 50,
page: pagingNum,
_web_stories_envelope: true,
_fields: MEDIA_FIELDS,
});
if (mediaType) {
path = addQueryArgs(path, { media_type: mediaType });
}
if (searchTerm) {
path = addQueryArgs(path, { search: searchTerm });
}
// cacheBusting is due to the preloading logic preloading and caching
// some requests. (see preload_paths in Dashboard.php)
// Adding cache_bust forces the path to look different from the preloaded
// paths and hence skipping the cache. (cache_bust itself doesn't do
// anything)
if (cacheBust) {
path = addQueryArgs(path, { cache_bust: true });
}

it('getMedia with cacheBust:true should call api with &cache_bust=true', () => {
apiFetch.mockReturnValue(
Promise.resolve({
body: GET_MEDIA_RESPONSE_BODY,
headers: GET_MEDIA_RESPONSE_HEADER,
})
);
const { getMedia } = bindToCallbacks(apiCallbacks, {
api: { media: MEDIA_PATH },
});
getMedia({
mediaType: '',
searchTerm: '',
pagingNum: 1,
cacheBust: true,
});
expect(apiFetch).toHaveBeenCalledWith(
expect.objectContaining({
path: expect.stringMatching('&cache_bust=true'),
})
);
});

@timarney timarney self-assigned this Jun 20, 2022
@felipebochehin87
Copy link

felipebochehin87 commented Jun 26, 2022

Tested using PR #11759. Dragged and dropped one and multiple files, uploaded one and multiple files. No refresh needed to have files displayed in the media gallery.

https://images.zenhubusercontent.com/235435637/1ed58d3a-8a34-4268-8248-8736b6d8310d/2022_06_26_18_55_37.mp4

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Group: Library Group: Media Group: WordPress Changes related to WordPress or Gutenberg integration Group: Workspace A group encompassing all of workspace – everything inside the canvas and sidebar P2 Should do soon Type: Code Quality Things that need a refactor, rewrite or just some good old developer ❤️
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants