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

Recomendation #49

Closed
drosendo opened this issue Aug 30, 2017 · 10 comments
Closed

Recomendation #49

drosendo opened this issue Aug 30, 2017 · 10 comments

Comments

@drosendo
Copy link

After trying to use this plugin I really had issues with perfomance, querying like 15000 times due to my ACF being built in a massive block with option (imagine a Visual Composer but built with ACF).
Due to this the result is very slow.

So my approach will be much cleaner, and want some opinion on it.
What i'm going to do is on wordpress add an action (https://codex.wordpress.org/Plugin_API/Action_Reference/save_post), that when the user hits save:

  1. Check if page has ACF
  2. If have ACF run getfields (https://www.advancedcustomfields.com/resources/get_fields/)
  3. Save the buetifull structured array into a a post meta (https://codex.wordpress.org/Function_Reference/update_post_meta), lets called it, "acf_corcel"
  4. In Corcel just get that post meta $post = Post::find(31); echo $post->meta->link;

I think this will be much faster and easy, opinions?

Cheers,
David

@drosendo
Copy link
Author

drosendo commented Aug 31, 2017

So here goes my code to whoever wants it:

On wordpress:

add_action('save_post', 'acf_corcel', 10, 3);
    /**
     * Save post metadata when a post is saved.
     *
     * @param int $post_id The post ID.
     * @param post $post The post object.
     * @param bool $update Whether this is an existing post being updated or not.
     */
    public function acf_corcel($post_id, $post, $update) {

        $fields = get_fields($post_id);

        if ($fields) {
            update_post_meta($post_id, 'acf_corcel', $fields);
        }
    }

Then on Laravel:

$post = Page::slug('home')->first();
$fields = unserialize($post->meta->acf_corcel);

Result:
Queries: 2 Queries
Memory: 2MB
Time: 154ms
DD:

array:1 [▼
  "data" => array:1 [▼
    "layout" => array:7 [▼
      0 => array:5 [▼
        "option" => "container-fluid"
        "background" => "None"
        "image" => false
        "color" => ""
        "container" => array:1 [▶]
      ]
      1 => array:5 [▶]
      2 => array:5 [▶]
      3 => array:5 [▶]
      4 => array:5 [▶]
      5 => array:5 [▶]
      6 => array:5 [▶]
    ]
  ]
]

Previous code:

$post = Page::slug('home')->first();
$fields = $post->acf->layout;

Result:
Queries: 13206 Queries
Memory: 134MB
Time: 12.8s
DD:

array:1 [▼
  "data" => Collection {#7589 ▼
    #items: array:7 [▼
      0 => array:15 [▼
        "option" => "container-fluid"
        "background" => "None"
        "container_0_rows_0_row_0_col_0__extra_small" => "12"
        "container_0_rows_0_row_0_col_0__small" => "12"
        "container_0_rows_0_row_0_col_0__medium" => "12"
        "container_0_rows_0_row_0_col_0__large" => "12"
        "container_0_rows_0_row_0_col_0__extra_large" => "12"
        "container_0_rows_0_row_0_col" => Collection {#626 ▶}
        "container_0_rows_0_row_0_slide_0_type" => "image"
        "container_0_rows_0_row_0_slide_0_image" => Image {#632 ▶}
        "container_0_rows_0_row_0_slide_0_link" => "none"
        "container_0_rows_0_row_0_slide" => Collection {#687 ▶}
        "container_0_rows_0_row" => Collection {#1450 ▶}
        "container_0_rows" => Collection {#1717 ▶}
        "container" => Collection {#2263 ▼
          #items: array:1 [▶]
        }
      ]
      1 => array:23 [▶]
      2 => array:96 [▶]
      3 => array:58 [▶]
      4 => array:25 [▶]
      5 => array:14 [▶]
      6 => array:12 [▶]
    ]
  }
]

From my result just deconstruct to get your "special field" data.

Cheers,
David

@drosendo drosendo mentioned this issue Aug 31, 2017
@benrolfe
Copy link

Looks a good solution, have you run into any limitations?

@drosendo
Copy link
Author

None, I now do whatever I want with the information.
Data is updated in WordPress after each save, so I always get the current data.

Cheers,
David

@jgrossi
Copy link
Member

jgrossi commented Sep 12, 2017

@drosendo can you make this a PR, please?

@drosendo
Copy link
Author

@jgrossi Maybe I don't know what you mean with "PR" (Pull request?), but there is nothing here to be added to your code... except the WordPress part, but this is a case to case...
:)

@DanDvoracek
Copy link

@drosendo this is great! Great thinking, Thanks! This was exactly what I needed 👍

@drosendo
Copy link
Author

I think there is nothing much to add here... feel free to suggest better ways of getting the structured data.

@drosendo
Copy link
Author

@jgrossi

Update for WPML support:

On Wordpress:

add_action('save_post', 'acf_corcel', 10, 3);
    /**
     * Save post metadata when a post is saved.
     *
     * @param int $post_id The post ID.
     * @param post $post The post object.
     * @param bool $update Whether this is an existing post being updated or not.
     */
    public function acf_corcel($post_id, $post, $update) {
    global $sitepress;
        $lang = '';
        if (class_exists('SitePress')) {
            $lang = ICL_LANGUAGE_CODE;
            if ($lang == 'pt-pt') // If the same as default language clear it so that I use acf_corcel
                $lang = '';
        }

        $fields = get_fields($post_id);

        if ($fields) {
            update_post_meta($post_id, 'acf_corcel'. $lang, $fields); // if lang is set then the meta will be "acf_corcel**lang**"
        }
    }

Then on laravel:

//Im using mcamara/laravel-localization
        $lang = '';
        if (\LaravelLocalization::getCurrentLocale() !== 'pt')
            $lang = \LaravelLocalization::getCurrentLocale();

$post = Page::slug('home')->get(); // Will get all posts IF translation shares same slug

        if (count($post) > 1) {
            foreach ($post as $k => $v) {

                $meta_field = 'acf_corcel' . $lang;
                $data = $v->meta->$meta_field; //gets the translated information
                if (unserialize($data)) // If found
                    $fields = unserialize($data); //Voilá
            }
        } else {
            $fields= unserialize($post[0]->meta->acf_corcel . $lang);
        }

Any recommendation on this better? At least it's working...

Cheers,
David

@jgrossi
Copy link
Member

jgrossi commented Feb 9, 2018

anyone to create a PR with that solution, please? 🙏🎉

@cjke
Copy link
Contributor

cjke commented Mar 27, 2018

@drosendo @jgrossi - I was hitting a similar performance issue (and have raised a seperate PR discussion to try to resolve it in the core library).

For now, I have taken a similar approach as @drosendo - this one deep dives, recursively. get_fields() seems to resolved nested content. For example - if you have a repeater of Posts, it won't get the meta on the Posts.

function recurse($value) 
{
        if(is_array($value)) {
            foreach ($value as $key => $item) {
                $value[$key] = recurse($item);
            }
        } else if($value instanceof WP_Post) {
            $value = array_merge($value->to_array(), get_fields($value->ID));
        }
        return $value;
}
    
add_action('save_post', function($postId)  {
    global $post;
   
    $fields = recurse(get_fields($postId));

    update_post_meta($postId, 'serialized_data', json_encode(
        array_merge($post->to_array(), $fields)
    ));
});

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

No branches or pull requests

5 participants