• Hi! I am the developer of MarsEdit, a desktop blogging app for the Mac.

    MarsEdit supports configuration of custom fields to e.g. update the pertinent values for SEO packages such as WordPress SEO by Yoast. Unfortunately, the default behavior of WordPress is to prohibit such access because the fields beginning with “_” underscores are considered “protected.”

    I experimented with whitelisting these accesses through a plugin with good success. I wonder if you would consider integrating something like the following into your plugin so it will work “out of the box” for folks who want to use MarsEdit with Yoast SEO.

    Note this has the nice effect that it doesn’t change the fields from “protected” so they still don’t show up as raw custom fields in the WP admin interface. But they do pass the test of meriting editing and adding permission, so when XMLRPC submissions include changes to those values, they are editable.

    <?php
    /*
    Plugin Name: Custom Field Permissions
    Description: Simple plugin to open up access for editing "protected" custom fields e.g. to facilitate editing SEO plugin fields via MarsEdit.
    Author: Daniel Jalkut / Red Sweater Software
    Version: 1.0
    Author URI: http://www.red-sweater.com/blog/
    */
    
    function startsWith($haystack, $needle)
    {
        return !strncmp($haystack, $needle, strlen($needle));
    }
    
    // I don't think it's particularly well documented but in my tests $args[3] is the name of the meta field value
    // being attempted to be edited or added.
    function grantCustomFieldEditPermissions( $allcaps, $cap, $args )
    {
        // Only apply when the question is whether a metadata field should be editable
        $requestedCap = $args[0];
        if (($requestedCap == "edit_post_meta") || ($requestedCap == "add_post_meta"))
        {
            // Only indulge editing rights to users who can otherwise edit this post
            $postID = $args[2];
            $userCanEdit = current_user_can('edit_post', $postID);
            if ($userCanEdit)
            {
                $editedMetaField = $args[3];
    
                // Allow anything relating to SEO Plugins Yoast, AIOSEO, etc. Note because only
                // underscore-prefixed fields are "protected" by default, we don't need to worry about
                // any plugins that use names not starting with underscore.
                if (startsWith($editedMetaField, "_yoast_wpseo_") ||
                    startsWith($editedMetaField, "_aioseop_") ||
                    startsWith($editedMetaField, "_headspace_"))
                {
                    $allcaps[$args[0]] = true;
                }
            }
        }
    
        return $allcaps;
    }
    
    add_filter( 'user_has_cap', 'grantCustomFieldEditPermissions', 0, 3 );
    
    ?>

    http://wordpress.org/extend/plugins/wordpress-seo/

Viewing 11 replies - 1 through 11 (of 11 total)
  • I think that perhaps the “register_meta()” function might also allow the plugin to register a santize/auth callback for the meta fields that would achieve the same thing.

    Hi Daniel,

    Have you ever got any news from Yoast?

    I’ve found this recent (2012) tutorial (since the Macography website where the old instructions were has disappeared) :

    http://nilorior.com/archives/2012/04/marsedit-wordpress-all-in-one-seo-pack-and-seo-by-yoast.html

    And for those interested, this is the original thread at MarsEdit forum about this issue:
    http://www.red-sweater.com/forums/discussion/1921/custom-fields-not-saved-by-wordpress/p1

    Cheers,

    P.

    Ok,

    I found a way to make it work (it’s a workaround until a proper integration). I didn’t found anything by myself but made some tests based on the discussions you’ll found above. First attempt based on Nilorior blog (in Japanese) failed.

    The instructions displayed below were tested on WordPress 3.5.1 with MarsEdit 3.5.8 It’s quite easy and involves two steps: 1) Edit the meta.php file in your WordPress installation; 2) Edit the MarsEdit setting for your WordPress blog in order to configure Yoast’s plugin custom fields. All in all it should take you five to fifteen minutes. Faster if you’re familiar with editing PHP file.

    1) First using an FTP client go to the root folder of your WordPress installation and locate the folder wp-includes;

    2) In this folder, locate the file meta.php Just to be safe download a copy of it: if something goes wrong during the editing, you will always be able to revert back to the original file.

    3) Using an editor (such as TextWrangler or TextMate) open the meta.php file and perform a search for is_protected_meta You should be able to find the following snippet of code around line no. 854:

    /**
     * Determine whether a meta key is protected
     *
     * @since 3.1.3
     *
     * @param string $meta_key Meta key
     * @return bool True if the key is protected, false otherwise.
     */
    function is_protected_meta( $meta_key, $meta_type = null ) {
    	$protected = (( '_' == $meta_key[0] ) && ( strpos($meta_key, "_yoast") !== 0));
    
    	return apply_filters( 'is_protected_meta', $protected, $meta_key, $meta_type );
    }

    You don’t need to change everything only the line that start with $protected This WHOLE line should be changed to the following:
    $protected = (( '_' == $meta_key[0] ) && ( strpos($meta_key, "_yoast") !== 0));

    That’s it. You’re done with editing your meta.php file.

    4) Now head over to MarsEdit. In the Main Window (Window>Main Window), locate your WordPress blog in the column on the left (it may be the only one or you may have multiple blog set there running on various platforms).

    5) Right-click on its name and chose “Edit settings” from the drop-down menu that appears.

    6) In the “Edit settings” window, chose the tab completely on the right: “Custom Fields”

    7) Depending on how you use Yoast’s plugin (which official name is “WordPress SEO”) you need to create three or four of those custom fields. I don’t use meta keywords, so I only need three. For each of those field whose name will appear in the left column, you’ll need to assign a “Server Custom Field Name” in the right column. I did it like this (the dots are only there to replicate the table: they divide between the left and right column you’ll find under the “Custom Fields” tab:

    SEO Title………._yoast_wpseo_title
    SEO Desc………_yoast_wpseo_metadesc
    SEO FW…………_yoast_wpseo_focuskw

    Click “OK” (lower right) and you’re done. It worked for me. What it does is fill Yoast’s plugin fields on WordPress with the proper value you will have created in MarsEdit. You can test it simple by creating a test post in MarsEdit: fill all the fields with the value you want, set the post for “draft” instead of “publish” and send it to your blog. Then, head over to your WordPress dashboard to see if all the fields are there.

    Hope it helps some of you.

    P.

    *** PLEASE READ: SMALL EDIT:

    When you’ll look into the meta.php file the first time, the code will look like this (in the example above, I copy/pasted the code from my meta.php which was already modified):

    /**
     * Determine whether a meta key is protected
     *
     * @since 3.1.3
     *
     * @param string $meta_key Meta key
     * @return bool True if the key is protected, false otherwise.
     */
    function is_protected_meta( $meta_key, $meta_type = null ) {
    	$protected = ( '_' == $meta_key[0] );
    
    	return apply_filters( 'is_protected_meta', $protected, $meta_key, $meta_type );
    }

    The only line you have to change is this one:
    $protected = ( '_' == $meta_key[0] );

    Change it for this:
    $protected = (( '_' == $meta_key[0] ) && ( strpos($meta_key, "_yoast") !== 0));

    That’s it.

    Plugin Contributor Joost de Valk

    (@joostdevalk)

    Just patched my local trunk with this, which seems to work well in my testing:

    /**
     * Allows editing of the meta fields through weblog editors like Marsedit.
     *
     * @param array $allcaps Capabilities that must all be true to allow action.
     * @param array $cap     Array of capabilities to be checked, unused here.
     * @param array $args    List of arguments for the specific cap to be checked.
     *
     * @return array $allcaps
     */
    function allow_custom_field_edits( $allcaps, $cap, $args ) {
    	// $args[0] holds the capability
    	// $args[2] holds the post ID
    	// $args[3] holds the custom field
    
    	// Make sure the request is to edit or add a post meta (this is usually also the second value in $cap,
    	// but this is safer to check).
    	if ( in_array( $args[0], array( "edit_post_meta", "add_post_meta" ) ) ) {
    		// Only allow editing rights for users who have the rights to edit this post and make sure
    		// the meta value starts with _yoast_wpseo.
    		if ( current_user_can( 'edit_post', $args[2] ) && strpos( $args[3], "_yoast_wpseo_" ) === 0 )
    			$allcaps[$args[0]] = true;
    	}
    
    	return $allcaps;
    }
    add_filter( 'user_has_cap', 'allow_custom_field_edits', 0, 3 );

    Added this in inc/wpseo-non-ajax-functions.php, could you perhaps test too?

    Hi,

    Nice! Thank you for the super fast answer!

    Yes, I would gladly test it. I have already modified my meta.php file to manually whitelist WordPress SEO custom field (like I said above). Before running the test, should I revert to the old meta.php ? I will guess I do need to revert and run the test anyway.

    Results are coming shortly.

    P.

    Yes! Fantastic!

    1) I revert back to default meta.php file (users who have not modified this file obviously don’t need to care about this);

    2) I added Joost de Valk code (see above) at the very end of the wpseo-non-ajax-functions.php file (wp-content>plugins>wordpress-seo>inc)

    3) Make sure you have properly edited your blog settings in Mars Edit (see above steps no. 4 through7).

    4) Now SEO fileds in WordPress can be populated directly in MarsEdit.

    I guess I can leave the code there and it will be implemented in the next version?

    In any case, thanks a lot to Daniel Jalkut and Joost de Valk for their efficient collaboration.

    P.

    I guess I’m a little confused between the two methods of whitelisting, as mentioned above. Perhaps it’s due to to my lack of knowledge about php.

    I use the meta.php hack as I have for years prior. When that method is employed, I see the fields on each post in the wp-admin backend. However, when I revert my meta.php As Parneix notes in step 1 above, and insert the code per step 2, I get nothing on the backend of each post.

    Should I just assume that it will save this information or should I be seeing it somewhere? Also, what does the patch for wpseo-non-ajax-functions.php have as an advantage over hacking the meta.php file?

    Hi,

    Although I can’t answer all of your questions (I’m a novice when it comes to PHP) I can tell you that the pacth for wpseao-non-ajax-functions.php doesn’t create “custom fields” ON TOP of WordPress SEO fields.

    When I used the meta.php patch and sent the value for the SEO from MarsEdit, I would find them under my post editor (wp-admin end) AND find duplicate in the form of “custom fields”. It doesn’t happen with Joost de Valk proper method of integration.

    Regards,

    P.

    Correct, i would see them under the ‘custom fields’ section. This is how I knew they were pulling properly from MarsEdit when I would upload a post. So, using the wpseao-non-ajax-functions.php method, it won’t create duplicate fields. I’m all for that.

    I guess my question is: how do I know it’s actually working. Since my point-of-reference was seeing the custom fields before, where would I go to ‘see’ the wpseao-non-ajax-functions.php method in action to verify it’s actually doing what it should be?

    I must sound like I’m doubting the method, however, I have a very good reason for asking. When core WP is updated, some updates overwrite the meta.php hack and as a result, I had to go back and correct about a dozen or so posts recently because I found that the information in the _yoast fields wasn’t translating to the backend of WordPress like I assumed it was. Very annoying. I’m merely trying to keep the same thing from happening.

    Hum. Is your plugin activated? I mean Yoast plugin? If so, when editing a post in WordPress (logged in as the author or administrator), directly under the text field for the blog post itself, there would be a new window with the title “WordPress SEO by Yoast”. Within this window, I would find all the fields used by the plugin: Snippet Preview, Focus Keyword, SEO Title, Meta Description.

    If the plugin is activated and the wpseao-non-ajax-functions.php method was a success, AND your previously created the appropriate custom fields in MarsEdit (you must create them using the value I used in step 7 above)… then whatever value you would input in those field within MarsEdit would be sent to the corresponding field in WordPress.

    NOW… I think I understand you publish DIRECTLY from MarsEdit? (I don’t: I always publish as draft, check and preview in WP and then publish: it’s cumbersome but I’m use to it). Then, a way to check if it worked would be to check you post online (once publicly published on your blog) and get “source view” from your browser: you should see the meta description field for example.

    I hope it makes some sense.

    P.

Viewing 11 replies - 1 through 11 (of 11 total)
  • The topic ‘Consider whitelisting editing of custom fields’ is closed to new replies.