I currently have a working controller that extends WP_REST_Controller in a file under the current theme. These are being called using jQuery ajax. (all code below)
The issue I am facing is that I receive this error ONLY when accessing with a mobile device.
{"code": "rest_no_route", "message": "No route was found matching the URL and request method" "data": {"status": 404}}
settings -> permalinks -> save changes
tried using controller namespace "api/v1" and "wp/v2"
javascript
function getAllClients() {
jQuery.ajax({
url: "http://myurl.com/index.php/wp-json/wp/v2/get_all_clients",
type: "GET",
data: { /*data object*/},
success: function (clientList) {
// success stuff here
},
error: function (jqXHR, textStatus, errorThrown) {
alert(jqXHR.statusText);
}
})
}
api/base.php
<?php
class ApiBaseController extends WP_REST_Controller
{
//The namespace and version for the REST SERVER
var $my_namespace = 'wp/v';
var $my_version = '2';
public function register_routes()
{
$namespace = $this->my_namespace . $this->my_version;
register_rest_route(
$namespace,
'/get_all_clients',
array(
array(
'methods' => 'GET',
'callback' => array(new ApiDefaultController('getAllClients'), 'init'),
)
)
);
$ApiBaseController = new ApiBaseController();
$ApiBaseController->hook_rest_server();
api/func.php
<?php
class ApiDefaultController extends ApiBaseController
{
public $method;
public $response;
public function __construct($method)
{
$this->method = $method;
$this->response = array(
// 'Status' => false,
// 'StatusCode' => 0,
// 'StatusMessage' => 'Default'
// );
}
private $status_codes = array(
'success' => true,
'failure' => 0,
'missing_param' => 150,
);
public function init(WP_REST_Request $request)
{
try {
if (!method_exists($this, $this->method)) {
throw new Exception('No method exists', 500);
}
$data = $this->{$this->method}($request);
$this->response['Status'] = $this->status_codes['success'];
$this->response['StatusMessage'] = 'success';
$this->response['Data'] = $data;
} catch (Exception $e) {
$this->response['Status'] = false;
$this->response['StatusCode'] = $e->getCode();
$this->response['StatusMessage'] = $e->getMessage();
}
return $this->response['Data'];
}
public function getAllClients()
{
// db calls here
return json_encode($stringArr,true);
}
}
These are registered in the Functions.php file
require get_parent_theme_file_path('api/base.php');
require get_parent_theme_file_path('api/func.php');
Turns out the issue was a plugin my client installed called "oBox mobile framework" that was doing some weird routing behind the scenes. Disabling it resolved the issue, though there is probably a way to hack around this and get both to play together.
Related
I am trying to setup google indexing api in codeigniter, I have done all steps on google cloud and search console part.
It works, but returning success message on all options event when url is not submited, that is why I want to get exact response from google instead of a created success message.
How can I display exact response from google return $stringBody;? or check for the correct response ?
Here is my controller :
namespace App\Controllers;
use App\Models\LanguageModel;
use App\Models\IndexingModel;
class IndexingController extends BaseController
{
public function initController(\CodeIgniter\HTTP\RequestInterface $request, \CodeIgniter\HTTP\ResponseInterface $response, \Psr\Log\LoggerInterface $logger)
{
parent::initController($request, $response, $logger);
$this->indexingModel = new IndexingModel();
}
public function GoogleUrl()
{
checkPermission('indexing_api');
$data['title'] = trans("indexing_api");
$data["selectedLangId"] = inputGet('lang');
if (empty($data["selectedLangId"])) {
$data["selectedLangId"] = $this->activeLang->id;
}
echo view('admin/includes/_header', $data);
echo view('admin/indexing_api', $data);
echo view('admin/includes/_footer');
}
/**
* indexing Tools Post
*/
public function indexingToolsPost()
{
checkPermission('indexing_api');
$slug = inputPost('slug');
$urltype = inputPost('urltype');
$val = \Config\Services::validation();
$val->setRule('slug', trans("slug"), 'required|max_length[500]');
if (!$this->validate(getValRules($val))) {
$this->session->setFlashdata('errors', $val->getErrors());
return redirect()->to(adminUrl('indexing_api?slug=' . cleanStr($slug)))->withInput();
} else {
$this->indexingModel->AddUrlToGoogle($slug, $urltype);
$this->session->setFlashdata('success', trans("msg_added"));
resetCacheDataOnChange();
return redirect()->to(adminUrl('indexing_api?slug=' . cleanStr($slug)));
}
$this->session->setFlashdata('error', trans("msg_error"));
return redirect()->to(adminUrl('indexing_api?slug=' . cleanStr($slug)))->withInput();
}
}
And This is my model :
namespace App\Models;
use CodeIgniter\Model;
use Google_Client;
class IndexingModel extends BaseModel {
public function AddUrlToGoogle($google_url, $Urltype){
require_once APPPATH . 'ThirdParty/google-api-php-client/vendor/autoload.php';
$client = new Google_Client();
$client->setAuthConfig(APPPATH . 'ThirdParty/google-api-php-client/xxxxxxxxx.json');
$client->addScope('https://www.googleapis.com/auth/indexing');
$httpClient = $client->authorize();
$endpoint = 'https://indexing.googleapis.com/v3/urlNotifications:publish';
$array = ['url' => $google_url, 'type' => $Urltype];
$content = json_encode($array);
$response = $httpClient->post($endpoint,['body' => $content]);
$body = $response->getBody();
$stringBody = (string)$body;
return $stringBody;
}
public function AddUrlToBing($google_url, $Urltype){
}
public function AddUrlToYandex($google_url, $Urltype){
}
}
This is a success response when I try it out of codeigniter and print_r($stringBody);
{ "urlNotificationMetadata": { "url": "https://example.com/some-text", "latestUpdate": { "url": "https://example.com/some-text", "type": "URL_UPDATED", "notifyTime": "2023-01-29T01:51:13.140372319Z" } } }
And this is an error response :
{ "error": { "code": 400, "message": "Unknown notification type. 'type' attribute is required.", "status": "INVALID_ARGUMENT" } }
But In codeigniter I get a text message "url submited" even if url not submited.
Currently you are not handling the actual response of IndexingModel->AddUrlToGoogle(). It seems your code has a validation before, so it claims, if no validation error occurs, its always a success.
So the first question to ask is, why your validation is not working here - or is it?
Secondly you could handle the actual response in any case:
IndexingController
class IndexingController extends BaseController
public function indexingToolsPost()
{
if (!$this->validate(getValRules($val))) {
// validation error
$this->session->setFlashdata('errors', $val->getErrors());
return redirect()->to(adminUrl('indexing_api?slug=' . cleanStr($slug)))->withInput();
} else {
// no validation error
$apiResponseBody = $this->indexingModel->AddUrlToGoogle($slug, $urltype);
if(array_key_exists('error', $apiResponseBody)) {
// its an error!
// either set the actual messsage
$this->session->setFlashdata('error', $apiResponseBody['error']['message']);
// OR translate it
$this->session->setFlashdata('error', trans($apiResponseBody['error']['message']));
} else {
// Its a success!
$this->session->setFlashdata('success', trans("msg_added"));
}
// ...
}
return redirect()->to(adminUrl('indexing_api?slug=' . cleanStr($slug)))->withInput();
}
And in the model, return the response as an array:
IndexingModel
public function AddUrlToGoogle($google_url, $Urltype) {
// ...
$response = $httpClient->post($endpoint,['body' => $content]);
return json_decode($response->getBody() ?? '', true); // return an array
}
so I am working in a social network, and I want once a post is done to be able to edit it, but I am having the error:
message: "This action is unauthorized."
is seems something simple to me, I get the info in the component send it throuhg an axios call that goes through a route I have defined and it just goes to the controller and from there to the service, but I must be missing something which I do not know what it is. Any hint is much appreciated as I am getting a bit mad...
this would be the function in the component:
editPost() {
let formData = new FormData();
let headers = { headers: { "Content-Type": "multipart/form-data" } };
let updatedPost = this.post_to_update;
formData.append("post", updatedPost.description);
formData.append("file", this.file);
formData.append("video_link", updatedPost.video_link);
axios
.post("/posts/update/" + updatedPost.id, formData, headers)
.then(response => {
updatedPost.attach_file = response.data.attach_file;
updatedPost.id = response.data.id;
serverBus.$emit("post_edited", updatedPost);
});
this.file = "";
this.post_to_update = {
id: "",
index: null,
description: "",
attach_file: "",
video_link: "",
name: this.profile_info.name,
surname_1: this.profile_info.surname_1,
surname_2: this.profile_info.surname_2,
nick: this.profile_info.nick,
picture: this.profile_info.picture,
id_rol: this.profile_info.id_rol,
time_ago: "0 minutes",
code: this.profile_info.code
};
$("#EditModal").modal("hide");
},
this is the web.php:
########################################################################################################################
# Post Routes
########################################################################################################################
Route::post('/posts/recommend', 'PostController#recommend')
->name('recommendPost');
Route::post('/posts/update/{id}', 'PostController#update');
Route::post('/posts/report', 'PostController#report')
->name('reportPost');
Route::get('/posts/{post}/comments', 'PostController#retrieveComments')
->where('post', '[0-9]+')
->name('commentsByPost');
Route::resource('/posts', 'PostController')
->only(['index', 'store', 'update', 'destroy']);
Route::get('/reportedPosts', 'PostController#reportedPosts');
The controller:
public function update(StorePostRequest $request, $post_id)
{
return $this->postService->updatePost($request, $post_id);
}
and the service:
public function updatePost(StorePostRequest $request, $post_id)
{
$post_to_update = Post::where('id', $post_id)->first();
$post_to_update->description = $request->post;
$post_to_update->attach_file = $request->file ? $filename = sha1(time()) : null;
$post_to_update->file_name = $request->file ? $request->file->getClientOriginalName() : null;
$post_to_update->file_type = $request->file ? $request->file->getClientOriginalExtension() : null;
$post_to_update->save();
if ($request->file) {
Storage::disk('s3')->putFileAs('storage/user_uploads/post_files/' . $post_to_update->id, $request->file, $filename, 'public');
Storage::disk('local')->putFileAs('public/user_uploads/post_files/' . $post_to_update->id, $request->file, $filename, 'public');
}
return $post_to_update;
}
I think StorePostRequest class cause the block of user authorization.
Try add following lines at StorePostRequest to pass the authorization check.
public function authorize()
{
return true; //Default false;
}
I have a class that registers a new endpoint, rewrites rules and then flushes it. It works perfectly except that it also gives a 404 error, making the page title "page not found" and adding some css which I dont want. I need to make it so that it actually knows my page exists.
This is the class I wrote:
<?php
use Jigoshop\Helper\Render as RenderCore;
use Jigoshop\Frontend\Page\PageInterface;
use Jigoshop\Integration\Helper\Render;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
class twizo_Jigoshop_TFASettings implements PageInterface
{
function __construct()
{
Render::addLocation('twizo-verification', __DIR__);
add_action('init', function () {
add_rewrite_endpoint("twizo-verification", EP_ROOT | EP_PAGES |
EP_PERMALINK);
add_filter('generate_rewrite_rules', function ($rewrite) {
$mySettings = [
'^account/twizo-verification/?$' => 'index.php?
pagename=twizo-verification'
];
$rewrite->rules = $mySettings + $rewrite->rules;
return $rewrite->rules;
});
flush_rewrite_rules();
});
add_filter('jigoshop.frontend.page_resolver.page', function ($args) {
global $wp_query;
if ($wp_query->query['pagename'] == 'twizo-verification') {
return $this;
}
return $args;
});
}
public function action()
{
$this->renderTFASettings();
}
public function render()
{
}
public function renderTFASettings()
{
add_action('jigoshop\template\shop\content\before', function () {
echo '<h1>My account » 2FA Settings</h1>';
});
add_action('jigoshop\template\shop\content\after', function() {
echo '<br><a href="./" class="btn btn-default">Go back to My
account</a>';
});
switch(get_template()) {
case "twentyfifteen":
RenderCore::output('layout/twentyfifteen', [
'content' => Render::get('twizo-verification', 'tfa-
settings-body', array())
]);
break;
case "twentysixteen":
RenderCore::output('layout/twentysixteen', [
'content' => Render::get('twizo-verification', 'tfa-
settings-body', array())
]);
break;
case "twentyseventeen":
RenderCore::output('layout/twentyseventeen', [
'content' => Render::get('twizo-verification', 'tfa-
settings-body', array())
]);
break;
default:
RenderCore::output('layout/default', [
'content' => Render::get('twizo-verification', 'tfa-
settings-body', array())
]);
break;
}
exit;
}
}
I'm trying to figure out why my ApiException is still returning a text/html response instead of a json response as denoted in ApiException render method. It is giving me the correct error message however its not rendering it as json.
/**
* Get the checklist (depending on type - send from Vue model)
*/
public function fetchChecklist(Request $request)
{
$id = $request->input('projectId');
$type = $request->input('type');
if (empty($id)) {
throw new ApiException('Project was not provided.');
}
if (! $project = RoofingProject::find($id)) {
throw new ApiException('Project not found.');
}
if (empty($type)) {
throw new ApiException('No checklist type was provided.');
}
switch ($request->input('type')) {
case 'permitting':
$items = $project->permittingChecklist;
break;
case 'permit':
$items = $project->permitReqChecklist;
break;
default:
throw new ApiException('Checklist not found.');
break;
}
return [
'status' => 'success',
'message' => '',
'items' => $items
];
}
App\Exceptions\ApiException.php
<?php
namespace App\Exceptions;
class ApiException extends \Exception
{
public function render($request)
{
return response()->json(['status' => 'error', 'error' => $this->message]);
}
}
In your request to the API you can try to add the following to your head/curl call to specify the datatype:
"Accept: application/json"
The laravel application is looking for if the requests expects json.
It worked for me with setting the following header as so
"x-requested-with": "XMLHttpRequest"
I'm still trying to add a recaptcha to my website, I want try the recaptcha from Google but I can't use it properly. Checked or not, my email is still sent.
I tried to understand the code of How to validate Google reCaptcha v2 using phalcon/volt forms?.
But i don't understand where are my problems and more over how can you create an element like
$recaptcha = new Check('recaptcha');
My controller implementation :
<?php
/**
* ContactController
*
* Allows to contact the staff using a contact form
*/
class ContactController extends ControllerBase
{
public function initialize()
{
$this->tag->setTitle('Contact');
parent::initialize();
}
public function indexAction()
{
$this->view->form = new ContactForm;
}
/**
* Saves the contact information in the database
*/
public function sendAction()
{
if ($this->request->isPost() != true) {
return $this->forward('contact/index');
}
$form = new ContactForm;
$contact = new Contact();
// Validate the form
$data = $this->request->getPost();
if (!$form->isValid($data, $contact)) {
foreach ($form->getMessages() as $message) {
$this->flash->error($message);
}
return $this->forward('contact/index');
}
if ($contact->save() == false) {
foreach ($contact->getMessages() as $message) {
$this->flash->error($message);
}
return $this->forward('contact/index');
}
$this->flash->success('Merci, nous vous contacterons très rapidement');
return $this->forward('index/index');
}
}
In my view i added :
<div class="g-recaptcha" data-sitekey="mypublickey0123456789"></div>
{{ form.messages('recaptcha') }}
But my problem is after : i create a new validator for the recaptcha like in How to validate Google reCaptcha v2 using phalcon/volt forms? :
use \Phalcon\Validation\Validator;
use \Phalcon\Validation\ValidatorInterface;
use \Phalcon\Validation\Message;
class RecaptchaValidator extends Validator implements ValidatorInterface
{
public function validate(\Phalcon\Validation $validation, $attribute)
{
if (!$this->isValid($validation)) {
$message = $this->getOption('message');
if ($message) {
$validation->appendMessage(new Message($message, $attribute, 'Recaptcha'));
}
return false;
}
return true;
}
public function isValid($validation)
{
try {
$value = $validation->getValue('g-recaptcha-response');
$ip = $validation->request->getClientAddress();
$url = $config->'https://www.google.com/recaptcha/api/siteverify'
$data = ['secret' => $config->mysecretkey123456789
'response' => $value,
'remoteip' => $ip,
];
// Prepare POST request
$options = [
'http' => [
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'method' => 'POST',
'content' => http_build_query($data),
],
];
// Make POST request and evaluate the response
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
return json_decode($result)->success;
}
catch (Exception $e) {
return null;
}
}
}
So i don't know if tjis code is correct anyway, i have a problem too after that : how to create an object "recaptcha" in my form add
$recaptcha = new ?????('recaptcha');
$recaptcha->addValidator(new RecaptchaValidator([
'message' => 'Please confirm that you are human'
]));
$this->add($recaptcha);
PS: I apologize because i'm a noob here and my mother tongue is not english, so if you don't understand me or want give me some advices to create a proper question, don't hesitate ^^
I've made a custom form element for recaptcha. Used it for many projects so far.
The form element class:
class Recaptcha extends \Phalcon\Forms\Element
{
public function render($attributes = null)
{
$html = '<script src="https://www.google.com/recaptcha/api.js?hl=en"></script>';
$html.= '<div class="g-recaptcha" data-sitekey="YOUR_PUBLIC_KEY"></div>';
return $html;
}
}
The recaptcha validator class:
use Phalcon\Validation\Validator;
use Phalcon\Validation\ValidatorInterface;
use Phalcon\Validation\Message;
class RecaptchaValidator extends Validator implements ValidatorInterface
{
public function validate(\Phalcon\Validation $validation, $attribute)
{
$value = $validation->getValue('g-recaptcha-response');
$ip = $validation->request->getClientAddress();
if (!$this->verify($value, $ip)) {
$validation->appendMessage(new Message($this->getOption('message'), $attribute, 'Recaptcha'));
return false;
}
return true;
}
protected function verify($value, $ip)
{
$params = [
'secret' => 'YOUR_PRIVATE_KEY',
'response' => $value,
'remoteip' => $ip
];
$response = json_decode(file_get_contents('https://www.google.com/recaptcha/api/siteverify?' . http_build_query($params)));
return (bool)$response->success;
}
}
Using in your form class:
$recaptcha = new Recaptcha($name);
$recaptcha->addValidator(new RecaptchaValidator([
'message' => 'YOUR_RECAPTCHA_ERROR_MESSAGE'
]));
Note 1: You were almost there, you just missed to create custom form element (the first and last code piece from my example);
Note 2: Also there is a library in Github: https://github.com/fizzka/phalcon-recaptcha I have not used it, but few peeps at phalcon forum recommended it.