De ce nu poate API-ul WP Filesystem să citească googlefonts.json?
Am preluat un site construit cu un temă de la Highgrade (southcentral) care folosește cadrul Redux.
Văd următoarea eroare în frontend și panoul de administrare:
Warning: Invalid argument supplied for foreach() in /Volumes/Data/Users/me/Sites/reference360.eu/wordpress/wp-content/themes/southcentral/highgrade/framework/inc/fields/typography/field_typography.php on line 772
Am încercat să modific permisiunile și ownership-ul pentru googlefonts.json dar fără succes.
Problema pare să fie în cadrul Redux - vezi acest thread pe github
Depanez în clasa typography.php:
if (!isset($this->parent->fonts['google']) || empty($this->parent->fonts['google'])) {
$this->parent->fonts['google'] = json_decode($wp_filesystem->get_contents(ReduxFramework::$_dir . 'inc/fields/typography/googlefonts.json'), true);
var_dump(ReduxFramework::$_dir . 'inc/fields/typography/googlefonts.json');
var_dump($wp_filesystem->get_contents(ReduxFramework::$_dir . 'inc/fields/typography/googlefonts.json')); exit;
$this->parent->font_groups['google'] = array(
'id' => 'google',
'text' => __('Google Webfonts', 'redux-framework'),
'children' => array(),
);
foreach ($this->parent->fonts['google'] as $font => $extra) {
$this->parent->font_groups['google']['children'][] = array(
'id' => $font,
'text' => $font
);
}
}
}
Are cineva vreo idee ce ar putea cauza asta? Fișierul există și se află la calea specificată. Mediul de dezvoltare este OSX Mavericks.
ACTUALIZARE:
Schimbarea ownership-ului întregului director wordpress la _www:_www
rezolvă problema dar evident nu este o soluție ideală.

Nu este necesar să folosiți WP_Filesystem pentru orice lucru minor, iar în acest caz, soluția corectă este să utilizați funcția normală file_get_contents
.
WP_Filesystem este un wrapper în jurul diferitelor metode de a interacționa cu sistemul de fișiere într-un mod sigur... dar nu este destinat pentru orice situație.
În esență, codul WP_Filesystem a fost creat pentru a permite WordPress să se actualizeze singur.
Când faceți astfel de operații, proprietatea fișierelor este o problemă destul de importantă. Multe servere rulează sub utilizatorul "www" (de exemplu) în loc să ruleze sub proprietarul real al fișierelor PHP. Dacă WordPress ar scrie direct un fișier în astfel de cazuri, fișierul rezultat ar fi deținut de "www", nu de adevăratul proprietar. Acest lucru poate duce la probleme de securitate, în special în cazul hostingului partajat.
Deci, WP_Filesystem abstractizează operațiunile cu fișiere. Poate citi și scrie fișiere în modalități care vor păstra proprietatea acestora. Dacă poate scrie direct și proprietatea rămâne neschimbată, atunci va face acest lucru, dar dacă nu poate, atunci va avea nevoie de credențiale pentru o metodă precum FTP. Folosind aceste credențiale, se poate conecta prin acea rută și poate scrie fișiere folosind proprietarul corect.
Ce înseamnă acest lucru este că înainte de a utiliza WP_Filesystem, acesta trebuie configurat. Trebuie efectuat un test, iar dacă testul eșuează, atunci trebuie obținute credențiale de la utilizator. Fără aceste credențiale, nu poate funcționa.
În cazul dumneavoastră, deoarece "schimbarea proprietarului întregului director WordPress la _www:_www" a rezolvat problema, aceasta este situația care vă afectează. Testul prin care încercă să scrie un fișier și să obțină proprietatea corectă eșuează. Prin schimbarea proprietarului fișierelor existente, modificați condițiile pentru acel test.
În realitate, în acest caz, nu există niciun motiv să utilizați WP_Filesystem deloc. Utilizatorul citește un fișier. Poate citi acel fișier direct. Proprietatea nu contează aici. Așadar, pur și simplu folosiți file_get_contents
. Utilizarea WP_Filesystem pentru această operație nu are sens.
Mai multe informații despre WP_Filesystem, din perspectiva utilizării: http://ottopress.com/2011/tutorial-using-the-wp_filesystem/

Mi se pare un pic contradictoriu să susții folosirea file_get_contents()
, în timp ce aceasta este interzisă de regulile repo-ului. Ce se întâmplă dacă acesta ar fi un theme public în repo? Înțeleg că temele care nu sunt în repo pot pur și simplu (și o fac, inclusiv eu) să ignore această regulă, dar cred că este un context important pentru răspuns, iar cazul unui theme din repo nu este acoperit prin recomandarea acestuia.

@Otto deci WP Filesystem efectuează un test pentru a scrie un fișier înainte de a face $wp_filesystem->get_contents(ReduxFramework::$_dir . 'inc/fields/typography/googlefonts.json') în cazul meu? Dacă aș ști unde încearcă să scrie un fișier, aș putea pur și simplu să schimb permisiunile pe acel director, așa că această informație ar fi utilă

De asemenea, tot ce face WP_Filesystem_Direct::file_get_contents pare a fi să încapsuleze și să suprascrie erorile file_get_contents() din PHP

@codecowboy Variabila globală global $wp_filesystem
nu este setată până când nu apelezi funcția WP_Filesystem()
, care de fapt face acel test pentru fiecare dintre metodele disponibile. Dacă metoda directă funcționează, atunci este atribuită acelei variabile. Deci nu poți apela $wp_filesystem->get_contents()
până nu ai apelat WP_Filesystem() măcar o dată.

@Rarst Dacă asta era pentru o temă din repository, aș recomanda rescrierea completă pentru a nu mai fi nevoie să citești și să analizezi acel fișier .json de fiecare dată. În loc să-l lași ca fișier json, îl citești o dată, îl treci prin json_decode, folosești print_r pe rezultat și pui asta într-un fișier PHP, pe care apoi îl poți include pur și simplu pentru a seta orice variabilă conține. De ce să te complici cu citirea și parsarea unui fișier de fiecare dată când poți face asta o singură dată?

@Rarst Pentru cazul mai general de "citire a unui fișier într-o temă", nu pot să mă gândesc la vreun motiv într-adevăr bun pentru care o temă ar face asta. Permitem file()
specific pentru acele cazuri, dar realist vorbind, a apărut doar de câteva ori și în acele cazuri a fost relativ simplu să folosești o alternativă care elimină nevoia de a citi fișierul cu totul.

@Otto punctul meu principal a fost că în forma "a folosi normal file_get_contents()
" răspunsul lipsește context, cum ar fi regulile repository-ului. Dacă cineva pur și simplu îl folosește și apoi este respins încercând să trimită la repository - ei ar considera un astfel de răspuns ca fiind un sfat prost.

@Rarst Înțeleg punctul tău, dar nu sunt de acord cu el. El a pus o întrebare despre o bucată specifică de cod. Răspunsul meu reflectă doar asta. El nu a pus o întrebare care să necesite un răspuns mult mai complex care să implice review-ul temei, pluginul de verificare a temei și repository-ul oficial gratuit. El vrea să-și rezolve problema și să învețe puțin despre WP_Filesystem, nu să învețe cum funcționează întreaga structură.

@codecowboy, ce versiune de Redux folosești? În versiunile mai noi nici măcar nu mai folosim googlefonts.json în acest fel.
Îți sugerez să instalezi pur și simplu Redux Framework din depozitul de plugin-uri WordPress (http://wordpress.org/plugins/redux-framework/), iar această problemă va fi rezolvată pentru tine deoarece plugin-ul va suprascrie versiunea de Redux încorporată în tema ta.

Mulțumesc pentru aceasta. Voi încerca această soluție rapidă care nu va afecta eventualele actualizări viitoare ale temei.

După ce am făcut depanarea, se pare că ceea ce se întâmplă cu adevărat este că WP_Filesystem încearcă să deschidă o conexiune FTP către fișierul temporar în timp ce efectuează verificările:
public function get_contents( $file ) {
$tempfile = wp_tempnam($file); // Creează un nume de fișier temporar unic
$temp = fopen($tempfile, 'w+'); // Deschide fișierul temporar pentru scriere/citire
if ( ! $temp )
return false; // Dacă nu poate fi deschis, returnează false
// Încearcă să descarce fișierul prin FTP în fișierul temporar
if ( ! @ftp_fget($this->link, $temp, $file, FTP_BINARY ) )
return false; // Dacă eșuează, returnează false și obțin un array gol pentru fonturile Google
fseek( $temp, 0 ); // Revine la începutul fișierului temporar
$contents = ''; // Inițializează variabila pentru conținut
// Citește fișierul în bucăți de 8192 bytes
while ( ! feof($temp) )
$contents .= fread($temp, 8192);
fclose($temp); // Închide fișierul temporar
unlink($tempfile); // Șterge fișierul temporar
return $contents; // Returnează conținutul citit
}
Pe mașina mea locală cu OSX acest cod eșuează, în timp ce pe serverul țintă funcționează. Nu sunt sigur de ce schimbarea drepturilor de proprietate pentru întregul director WordPress la _www:_www
permite acestui ftp_fget
să funcționeze, având în vedere că încearcă să citească un fișier temporar în /var/tmp
.

Pentru clarificare, cea mai recentă versiune de Redux nu mai utilizează această metodă specifică pentru încărcarea fonturilor Google. Și în al doilea rând, Otto are o oarecare aversiune față de oamenii de la Redux, așa că luați cu rezerve ceea ce spune el aici. Vedem CONSTANT erori în verificarea temelor care spun:
AVERTIZARE: file_put_contents a fost găsit în fișierul class.redux_filesystem.php Operațiunile cu fișiere ar trebui să folosească metodele WP_Filesystem în loc de apeluri directe la sistemul de fișiere PHP.
Serios? Deci, Otto? Inventezi standarde și linii directoare pe parcurs? Are sens, într-adevăr, având în vedere că întreaga bază $wp_filesystem acționează de parcă a fost asamblată bucată cu bucată de copii care nu aveau nicio idee despre ce făceau. Standarde, într-adevăr!

Nu mă adresam direct temei tale, doar codului dat. Nu știu nimic despre framework-ul tău, per se. Nu l-am studiat în profunzime.

De asemenea, folosirea file_get_contents
nu este permisă pentru teme în directorul WordPress.org în principal pentru că multe programe malware o folosesc. Plugin-ul de verificare a temelor este axat special pe acele standarde.
Cu toate acestea, în loc să citești un fișier .json și să-l decodifici de fiecare dată, ar fi mult mai logic să-l decodifici o singură dată și să incluzi array-ul PHP rezultat direct în cod.

Nu, nu este tema mea, și sincer domnule, nu te cred în legătură cu framework-ul, bazat pe evenimentele recente cu acesta.

http://reduxframework.com/2014/07/sometimes-standards-dont-always-work/

@kprovance Nu sunt sigur dacă a început să urască, a vorbit în termeni generali.
Otto, deci cum sugerezi să avem o soluție permanentă dincolo de ce am făcut. Încercăm să folosim WP_Filesystem, dar dacă nu funcționează, folosim file_get_contents. Este acceptabil acest lucru? Se pare că a funcționat până acum.

Cei de la Redux sunt liberi să nu fie de acord cu mine și să folosească ceea ce funcționează cel mai bine pentru ei și utilizatorii lor. Nu mă deranjează deloc.

Otto, te rog să îmi trimiți un email sau să mă contactezi pe Skype. dovy@reduxframework.com. Skype: DovyDigital
Aș dori să rezolvăm toate preocupările și să primesc sfatul tău sincer.
