-
Notifications
You must be signed in to change notification settings - Fork 23
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 functionality to reset page order #129
Conversation
This reverts commit 65b2d68.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @ruscoe
Thank you so much for working on this and congratulations on your first PR at 10up!
I have reviewed your code and I have a concern.
Since the REST endpoint in open to public, anyone with access to it can reset the page ordering.
Watch this video below where I am able to reset the ordering through Postman:
spo-129.mp4
For this feature, I would suggest you to use wp_ajax_{$action} instead.
You can use the following:
- wp_nonce_url() to generate a URL with nonce which you can verify in the PHP callback using wp_verify_nonce().
OR
If you would like to go ahead with the current implementation, then you can pass a nonce and verify it in the permissions_callback
.
@Sidsector9 Very good point! Thank you for reviewing and catching that. I'll take your suggestion and submit an updated PR shortly. |
@Sidsector9 Changes made! It's now using the admin AJAX functionality rather than a REST endpoint. Is there something better I could do to avoid the code duplication between |
@ruscoe Thanks for working on those changes, tested well for me 👍 No pressure at all, but would you be comfortable at writing end-to-end tests for the same? Else let us know if you'd like someone from our team to pick up writing the tests. Answering your question:
Looking at the code, I think we can let it pass for now as the duplication is less. In the future when the number of AJAX handlers increase using the same set of checks, then we can look at refactoring it under a common handler. |
@Sidsector9 I'd like to write the tests. It'll be a great opportunity for me to learn how they work. Will update soon! |
@Sidsector9 Thank you for all your assistance with this! I've just committed my first attempt at a Cypress test. I took a lot of guidance from the other tests. The tests pass for me and look correct when I run them through the command line and UI / browser aspect of Cypress. Let me know what you think! |
const newSecondText = cy.get(`${second} .row-title`); | ||
|
||
cy.get(`${first} .row-title`).then($el => { | ||
newFirstText.should('have.text', $el.text()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this will always be true, as newFirstText
and cy.get('${first} .row-title')
refer to the same element.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to save the original post names so that we can verify their positions after swapping and reverting.
This is something I was trying today, I used cy.as()
to store the text values and refer them later on for verification:
describe( 'Test Reset Page Order Change', () => {
it( 'Can reset pages order', () => {
cy.login();
cy.visit('/wp-admin/edit.php?post_type=page');
const firstRow = '.wp-list-table tbody tr:nth-child(1)';
const secondRow = '.wp-list-table tbody tr:nth-child(2)';
// Alias titles as `firstRowText` and `secondRowText` for convenience.
cy.get( firstRow ).find( '.row-title' ).invoke( 'text' ).as( 'firstRowText' );
cy.get( secondRow ).find( '.row-title' ).invoke( 'text' ).as( 'secondRowText' );
// Swap position of `Page 1` with `Page 2`.
cy.get( firstRow ).drag( secondRow );
// Verifies if 1st row has title `Page 2`.
cy.get( firstRow ).find( '.row-title' ).invoke( 'text' ).then( function( text ) {
expect( text ).to.eq( this.secondRowText );
} );
// Verifies if 2nd row has title `Page 1`.
cy.get( secondRow ).find( '.row-title' ).invoke( 'text' ).then( function( text ) {
expect( text ).to.eq( this.firstRowText );
} );
// Now reset the page order and verify original values are back.
cy.get( '#contextual-help-link' ).click();
cy.get( '#tab-link-simple_page_ordering_help_tab' ).click();
cy.get( '#simple-page-ordering-reset' ).click();
cy.on( 'window:confirm', () => true );
// Perform a reload as Cypress won't after window:confirm.
cy.reload();
// Verifies if 1st row has title `Page 1`.
cy.get( firstRow ).find( '.row-title' ).invoke( 'text' ).then( function( text ) {
expect( text ).to.eq( this.firstRowText );
} );
// Verifies if 2nd row has title `Page 2`.
cy.get( secondRow ).find( '.row-title' ).invoke( 'text' ).then( function( text ) {
expect( text ).to.eq( this.secondRowText );
} );
} );
} );
cy.on(`window:confirm`, () => true); | ||
|
||
// wait for the page to reload before checking for reset post order. | ||
cy.wait(1000); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cypress considers using cy.wait()
as anti-pattern. We can replace this with cy.reload()
instead because window.location.reload()
will not actually reload the page in cypress.
@ruscoe Thanks so much for the tests! I have reviewed and requested some minor changes. |
… original post titles after order reset.
@Sidsector9 Thank you! I replaced my test code with your modified code and it works perfectly. Do you mind if I just commit your modified test in place of mine? |
481a3fb
to
bd8a6fc
Compare
simple-page-ordering.php
Outdated
} | ||
|
||
// reset the order of all posts of given post type | ||
$wpdb->update( 'wp_posts', array( 'menu_order' => 0 ), array( 'post_type' => $post_type ) ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dkotter This PR works well. The only area that I am concerned about is the performance impact due to this line.
Would this be an issue for an extremely large database? If so, should we look into performing the updates in batches?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at the code wpdb::update
runs, seems like the final query will be something like:
UPDATE 'wp_posts' SET 'menu_order' = 0 WHERE 'post_type' = 'page'
I think that should scale fairly well and we won't need to worry about doing any sort of batching here. That said, @ruscoe if you'd be able to do some quick testing on various sizes to see the performance impact, that would help us be more confident about merging this in. Something like profiling this code when run on a site that has 10 pages, 100 pages and 1000 pages, that would be helpful.
In addition, I think best practice here is to utilize the format properties of the update
method. Something like
$wpdb->update( 'wp_posts', array( 'menu_order' => 0 ), array( 'post_type' => $post_type ) ); | |
$wpdb->update( 'wp_posts', array( 'menu_order' => 0 ), array( 'post_type' => $post_type ), array( '%d' ), array( '%s' ) ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dkotter No problem at all! I profiled by measuring execution time.
Just to show my process, first I used a quick shell script to create pages:
#!/bin/bash
for i in {1..10}
do
wp post create --post_type=page --post_title="Page $i"
done
Then used the following to test:
$start_time = microtime( true );
$wpdb->update( 'wp_posts', array( 'menu_order' => 0 ), array( 'post_type' => 'page' ), array( '%d' ), array( '%s' ) );
$end_time = microtime( true );
$total_time = ( $end_time - $start_time );
echo $total_time;
Taking the average of five test runs each:
10 posts: 0.0041 microseconds
100 posts: 0.0042 microseconds
1000 posts: 0.0116 microseconds
5000 posts: 0.0299 microseconds
How does that look?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @ruscoe! Definitely see an increase in time as the number of posts increase but the overall amount of time is so low that this doesn't seem like it will cause any problems. This looks good to go on my end
Co-authored-by: Darin Kotter <[email protected]>
Description of the Change
In the page admin section, the Simple Page Ordering plugin help section has been modified to include a "Reset page order" link. Clicking this link first displays a confirmation dialog then, if the user confirms, resets the "menu_order" field of all pages to 0, resetting any changes made with this plugin.
I think this is the most minimally invasive solution, adding little code to achieve the purpose. I chose to place the reset link in the help menu to minimize chances of accidental order resets. Plus, if someone needs to reset the order of their posts, they have probably made a mistake and will be looking for help.
Closes #24
How to test the Change
/wp-admin/edit.php?post_type=page
Changelog Entry
Credits
Props @pattonwebz, @ruscoe, @Sidsector9, @dkotter
Checklist: